人口普查变换在python openCV中

时间:2016-07-08 11:19:02

标签: python opencv

我开始在与stereovision相关的项目中使用openCV和python。我在openCV中找到了关于C ++中Census Transform的文档页面。 link

有没有人知道python实现是否有类似的功能?

(例如cv2.nameofthefunction)

谢谢大家!

编辑:PM 2Ring的优秀解决方案(再次感谢你)可以使用openCV进行这一小改动:而不是使用Image.open

img = cv2.imread(img.png)
#some minor changes I needed like select some ROI and store them in img2[j] 
#then a for cycle in which I wrote
src_img = img2[j] 
h, w = src_img.shape

"形状"指令似乎切换w和h的顺序与" size"相比较命令。然后我粘贴PM 2Ring的其余代码并且它工作得非常好

2 个答案:

答案 0 :(得分:8)

我不使用openCV,而且我不知道是否存在人口普查变换的现有实施。但是,使用Numpy很容易实现。

这是一个简单的演示,它使用PIL来处理加载图像并将数组数据转换回图像。

#!/usr/bin/env python

''' The Census Transform

    Scan an 8 bit greyscale image with a 3x3 window
    At each scan position create an 8 bit number by comparing the value
    of the centre pixel in the 3x3 window with that of its 8 neighbours.
    The bit is set to 1 if the outer pixel >= the centre pixel

    See http://stackoverflow.com/questions/38265364/census-transform-in-python-opencv

    Written by PM 2Ring 2016.07.09
'''

import numpy as np
from PIL import Image

iname = 'Glasses0S.png'
oname = 'Glasses0S_census.png'

#Get the source image
src_img = Image.open(iname)
src_img.show()

w, h = src_img.size
print('image size: %d x %d = %d' % (w, h, w * h))
print('image mode:', src_img.mode)

#Convert image to Numpy array
src_bytes = np.asarray(src_img)

#Initialize output array
census = np.zeros((h-2, w-2), dtype='uint8')

#centre pixels, which are offset by (1, 1)
cp = src_bytes[1:h-1, 1:w-1]

#offsets of non-central pixels 
offsets = [(u, v) for v in range(3) for u in range(3) if not u == 1 == v]

#Do the pixel comparisons
for u,v in offsets:
    census = (census << 1) | (src_bytes[v:v+h-2, u:u+w-2] >= cp)

#Convert transformed data to image
out_img = Image.fromarray(census)
out_img.show()
out_img.save(oname)

<强>来源

source image

<强>输出

output image

原始全彩眼镜图片由Gilles Tran使用POV-Ray创建,属于公共领域。它可以在Wikipedia上找到。

答案 1 :(得分:0)

使用numpy和OpenCV的Python 3代码。增加了处理不同窗口大小并在立体图像之间产生成本差异的功能。下方Middlebury 2014 stereo image set(游戏室完美)上显示的转换示例。

enter image description here

import numpy as np
import cv2

def transform(image, window_size=3):
    """
    Take a gray scale image and for each pixel around the center of the window generate a bit value of length
    window_size * 2 - 1. window_size of 3 produces bit length of 8, and 5 produces 24.

    The image gets border of zero padded pixels half the window size.

    Bits are set to one if pixel under consideration is greater than the center, otherwise zero.

    :param image: numpy.ndarray(shape=(MxN), dtype=numpy.uint8)
    :param window_size: int odd-valued
    :return: numpy.ndarray(shape=(MxN), , dtype=numpy.uint8)
    >>> image = np.array([ [50, 70, 80], [90, 100, 110], [60, 120, 150] ])
    >>> np.binary_repr(transform(image)[0, 0])
    '1011'
    >>> image = np.array([ [60, 75, 85], [115, 110, 105], [70, 130, 170] ])
    >>> np.binary_repr(transform(image)[0, 0])
    '10011'
    """
    half_window_size = window_size // 2

    image = cv2.copyMakeBorder(image, top=half_window_size, left=half_window_size, right=half_window_size, bottom=half_window_size, borderType=cv2.BORDER_CONSTANT, value=0)
    rows, cols = image.shape
    census = np.zeros((rows - half_window_size * 2, cols - half_window_size * 2), dtype=np.uint8)
    center_pixels = image[half_window_size:rows - half_window_size, half_window_size:cols - half_window_size]

    offsets = [(row, col) for row in range(half_window_size) for col in range(half_window_size) if not row == half_window_size + 1 == col]
    for (row, col) in offsets:
        census = (census << 1) | (image[row:row + rows - half_window_size * 2, col:col + cols - half_window_size * 2] >= center_pixels)
    return census

def column_cost(left_col, right_col):
    """
    Column-wise Hamming edit distance
    Also see https://www.youtube.com/watch?v=kxsvG4sSuvA&feature=youtu.be&t=1032
    :param left: numpy.ndarray(shape(Mx1), dtype=numpy.uint)
    :param right: numpy.ndarray(shape(Mx1), dtype=numpy.uint)
    :return: numpy.ndarray(shape(Mx1), dtype=numpy.uint)
    >>> image = np.array([ [50, 70, 80], [90, 100, 110], [60, 120, 150] ])
    >>> left = transform(image)
    >>> image = np.array([ [60, 75, 85], [115, 110, 105], [70, 130, 170] ])
    >>> right = transform(image)
    >>> column_cost(left, right)[0, 0]
    2
    """
    return np.sum(np.unpackbits(np.bitwise_xor(left_col, right_col), axis=1), axis=1).reshape(left_col.shape[0], left_col.shape[1])

def cost(left, right, window_size=3, disparity=0):
    """
    Compute cost difference between left and right grayscale images. Disparity value can be used to assist with evaluating stereo
    correspondence.
    :param left: numpy.ndarray(shape=(MxN), dtype=numpy.uint8)
    :param right: numpy.ndarray(shape=(MxN), dtype=numpy.uint8)
    :param window_size: int odd-valued
    :param disparity: int
    :return:
    """
    ct_left = transform(left, window_size=window_size)
    ct_right = transform(right, window_size=window_size)
    rows, cols = ct_left.shape
    C = np.full(shape=(rows, cols), fill_value=0)
    for col in range(disparity, cols):
        C[:, col] = column_cost(
            ct_left[:, col:col + 1],
            ct_right[:, col - disparity:col - disparity + 1]
        ).reshape(ct_left.shape[0])
    return C

def norm(image):
    return cv2.normalize(image, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX).astype(np.uint8)

if __name__ == "__main__":
    # Image set from http://vision.middlebury.edu/stereo/data/scenes2014/
    resize_pct = 0.1
    ndisp = 330 # from calib.txt
    ndisp *= resize_pct
    # load as grayscale
    left = cv2.imread('Playroom-perfect-left.png', 0)
    right = cv2.imread('Playroom-perfect-right.png', 0)
    left = cv2.resize(left, dsize=(0,0), fx=resize_pct, fy=resize_pct)
    right = cv2.resize(right, dsize=(0, 0), fx=resize_pct, fy=resize_pct)

    window_size = 5
    ct_left = norm(transform(left, window_size))
    ct_right = norm(transform(right, window_size))

    ct_costs = []
    for exponent in range(0, 6):
        import math
        disparity = int(ndisp / math.pow(2, exponent))
        print(math.pow(2, exponent), disparity)
        ct_costs.append(norm(cost(left, right, window_size, disparity)))

    cv2.imshow('left/right grayscale/census', np.vstack([np.hstack([left, right]), np.hstack([ct_left, ct_right])]))
    cv2.imshow('costs', np.vstack(ct_costs))
    cv2.waitKey(0)