OpenCV-Python教程:26.Histogram 4 Histogram 向后投影

理论

Michael J. Swain , Dana H. Ballard 发表的Indexing via color histograms

用来在图片分割或者在图像里找感兴趣的目标,简单说来,它创建了一个和输入图像一样大小的图像,但是是单通道的。输出图像会有我们感兴趣的目标,但是它比其他部分更白。

我们怎么做呢?我们创建一个图像的histogram,包含我们感兴趣的目标。彩色的histogram比灰度的要好,因为彩色目标更好被定义。然后我们“向后投影”这个histogram到我们的测试图像上,我们计算每个像素的可能性,并显示它。

Numpy里的算法

1.首先我们需要计算我们要找的目标(假设叫M)和我们要搜索的图像(假设叫I)的彩色histogram。

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('rose_red.png')
hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)

#target is the image we search in
target = cv2.imread('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] )

2.找到 R = M / I .然后向后投影R, 用R当调色板创建一个新图像,图像的每个像素和它的目标对应的像素点可能性。B(x, y) = R[h(x, y), s(x,y)], h 是色调,s是饱和度,然后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])

3.现在用卷积, 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)

4.现在最大强度的位置告诉我们目标的位置,我们如果想得到图像的一个区域,可以用合适的阈值得到:

ret,thresh=cv2.threshold(B,50,255,0)

OpenCV里的向后映射

OpenCV提供了内置函数cv2.calcBackProject()。它的参数和calcHist()一样,一个参数是histogram,目标的histogram应该标准化,然后再传给向后投影函数。它返回可能性图片。然后我们用disc 核卷积,接着用阈值。

import cv2
import numpy as np

roi = 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 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('res.jpg',res)

下面是一个例子,我使用了蓝色矩形的区域作为样本对象,我想提取整个草皮

OpenCV-Python教程:26.Histogram 4 Histogram 向后投影_第1张图片

END

你可能感兴趣的:(OpenCV-Python教程:26.Histogram 4 Histogram 向后投影)