5.4. 直方图-4:直方图反投影¶
5.4.1. 目标¶
在本章中,我们将学习直方图反投影。
5.4.2. 理论¶
它是由 迈克尔·J·斯温,达娜·H·巴拉德 在他们的报纸上 颜色直方图索引 .
用简单的话来说到底是什么? 它用于图像分割或在图像中查找感兴趣的对象。简单地说,它创建的图像与输入图像的大小相同(但只有一个通道),其中每个像素对应于该像素属于我们的对象的概率。在更简单的世界中,输出图像将使我们感兴趣的对象比剩余部分更白。好吧,这是一个直观的解释。(我无法使它更简单)。直方图反投影与camshift算法等结合使用。
我们怎么做? 我们创建一个包含感兴趣对象的图像直方图(在我们的例子中,是地面、离开播放器和其他东西)。对象应尽可能填充图像以获得更好的效果。与灰度直方图相比,颜色直方图更受欢迎,因为对象的颜色比其灰度强度更好地定义对象。然后,我们将这个直方图“投影”到我们的测试图像上,在那里我们需要找到目标,也就是说,我们计算出属于地面的每个像素的概率并显示出来。在适当的阈值上产生的输出给了我们单独的土地。
5.4.3. Numpy中的算法¶
首先,我们需要计算我们需要查找的对象(设为“M”)和要搜索的图像(设为“I”)的颜色直方图。
>>> %matplotlib inline
>>>
>>> import cv2
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>>
>>> #roi is the object or region of object we need to find
>>> roi = cv2.imread('/cvdata/rose_red.png')
>>>
>>> hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
>>>
>>> #target is the image we search in
>>> target = cv2.imread('/cvdata/rose.png')
>>> hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)
>>>
>>> # Find the histograms using calcHist. Can be done with np.histogram2d also
>>> M = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
>>> I = cv2.calcHist([hsvt],[0, 1], None, [180, 256], [0, 180, 0, 256] )
>>> plt.imshow(roi)
<matplotlib.image.AxesImage at 0x7fe6cb7e8cc0>
>>> plt.imshow(target)
<matplotlib.image.AxesImage at 0x7fe6cb7bea20>
>>> cv = cv2
>>> h,s,v = cv.split(hsvt)
>>> B = M[h.ravel(),s.ravel()]
>>> B = np.minimum(B,1)
>>> B = B.reshape(hsvt.shape[:2])
找到比率 \(R = \frac{{M}}{{I}}\) . 然后以R为调色板,以每一个像素作为对应的目标概率,创建一个新的图像。工业工程
B(x,y) = R[h(x,y),s(x,y)]
其中h是色调,s是(x,y)处像素的饱和度。之后适用条件 \(B(x,y) = min[B(x,y), 1]\) .
现在用圆盘作卷积, \(B = D \ast B\) ,其中D是磁盘内核。
>>> disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
>>> cv2.filter2D(B,-1,disc,B)
>>> B = np.uint8(B)
>>> cv2.normalize(B,B,0,255,cv2.NORM_MINMAX)
array([[255, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255],
...,
[ 0, 0, 0, ..., 0, 0, 0],
[ 0, 0, 0, ..., 0, 0, 0],
[ 0, 0, 0, ..., 0, 0, 0]], dtype=uint8)
现在最大强度的位置给出了物体的位置。如果我们期望图像中有一个区域,则对适当的值进行阈值化可以得到很好的结果。
>>> ret,thresh = cv2.threshold(B,50,255,0)
>>> plt.imshow(thresh)
<matplotlib.image.AxesImage at 0x7fe6cb715cf8>
就这样!!
5.4.4. OpenCV中的反投影¶
OpenCV提供了一个内置函数 cv2.calcBackProject() . 其参数几乎与 化学气相色谱仪() 功能。它的一个参数是直方图,它是物体的直方图,我们必须找到它。此外,在传递给backproject函数之前,应该对对象直方图进行规范化。它返回概率图像。然后将图像与磁盘核卷积,并应用阈值。下面是我的代码和输出:
>>> import cv2
>>> import numpy as np
>>>
>>> roi = cv2.imread('/cvdata/rose_red.png')
>>> hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
>>>
>>> target = cv2.imread('/cvdata/rose.png')
>>> hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)
>>>
>>> # calculating object histogram
>>> roihist = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
>>>
>>> # normalize histogram and apply backprojection
>>> cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
>>> dst = cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)
>>>
>>> # Now convolute with circular disc
>>> disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
>>> cv2.filter2D(dst,-1,disc,dst)
>>>
>>> # threshold and binary AND
>>> ret,thresh = cv2.threshold(dst,50,255,0)
>>> thresh = cv2.merge((thresh,thresh,thresh))
>>> res = cv2.bitwise_and(target,thresh)
>>>
>>> res = np.vstack((target,thresh,res))
>>> cv2.imwrite('xx_res.jpg',res)
True
下面是我工作过的一个例子。我使用蓝色矩形内的区域作为示例对象,并希望提取整个地面。
5.4.5. 额外资源¶
“通过颜色直方图进行索引”,斯温,迈克尔J.第三届计算机视觉国际会议,1990年。