学习目标
这一节,我们学习直方图反向投影(histogram backprojection)。
理论
该理论由Michael J. Swain , Dana H. Ballard发表在他们的论文中,Indexing via color histograms.
那么,直方图反向投影是什么意思呢?常被用于图像分割或者寻找图像中感兴趣区域。简单来说,首先创建与输入图像相同大小的单通道图像,图像中每一个像素与该像素属于目标的概率有关。简而言之,输出图像中目标区域具有更大的白色区域(相对于背景区域)。这仅仅是直觉上的理解。直方图反向投影常与CameShift算法一起使用。
那么该算法如何操作呢?首先创建包含目标的图像直方图(本节的例子,我们留下地面,去掉其余的对象)。若要得到很好的效果,那么需要目标区域足够大。那么彩色直方图将更加优于灰度直方图,因为色彩更好的定义目标。然后我们对该图像应用直方图反向投影,最终定位到目标区域。换句话说,我们估计每一个像素属于目标(地面,ground)的概率。
Numpy反向投影的计算
首先,我们计算目标的直方图(令为M
),以及搜索的目标图像 (令为I
)。
import cv2import numpy as npfrom matplotlib import pyplot as plt#roi is the object or region of object we need to findroi = cv2.imread('rose_red.png')hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)#target is the image we search intarget = cv2.imread('rose.png')hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)# Find the histograms using calcHist. Can be done with np.histogram2d alsoM = 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] )
计算比值: R = M I R=\frac{M}{I} R=IM,然后将R作为画板,并创建新的图像,每一个像素表示与目标相关的概率,比如B(x,y)=R[h(x,y),s(x, y)]
,这里h是hue
,s是饱和度(saturation)。然后,应用条件,B(x,y) = min(B(x,y),1).
h,s,v = cv2.split(hsvt)B = R[h.ravel(),s.ravel()]B = np.minimum(B,1)B = B.reshape(hsvt.shape[:2])
现在,我们应用圆盘卷积,B=D*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)
那么最大值的位置就是目标位置。如果我们期待一个图像中的区域,那么我们可以给合适的阈值,会得到很好的结果。
ret,thresh = cv2.threshold(B,50,255,0)
OpenCV中的反向投影计算
OpenCV中提供了计算直方图的内置函数,cv2.calcBackProject()
. 它的参数几乎与cv2.calcHist()
的参数一致。他的其中一个参数是目标的直方图,我们需要寻找该目标。并且,传入的直方图必须是归一化的。返回概率图像。然后使用卷积对图像进行卷积,最后应用阈值,下面是代码和输出:
import cv2import numpy as nproi = cv2.imread('rose_red.png')hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)target = cv2.imread('rose.png')hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)# calculating object histogramroihist = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )# normalize histogram and apply backprojectioncv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)dst = cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)# Now convolute with circular discdisc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))cv2.filter2D(dst,-1,disc,dst)# threshold and binary ANDret,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('res.jpg',res)
运行结果如下:
如果觉得《OpenCV-Python -- Histogram - 4 : Histogram Backprojection》对你有帮助,请点赞、收藏,并留下你的观点哦!