OpenCV竟然可以这样学!成神之路终将不远(二十五)

Posted 满目星辰wwq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV竟然可以这样学!成神之路终将不远(二十五)相关的知识,希望对你有一定的参考价值。

返回目录

目录

25 直方图-4:直方图反投影

25.1 目标

25.2 理论

25.3 Numpy中的算法

25.4 OpenCV的反投影


25 直方图-4:直方图反投影

25.1 目标

在本章中,我们将学习直方图反投影。

25.2 理论

这是由Michael J.Swain和Dana H.Ballard在他们的论文《通过颜色直方图索引》中提出的。

用简单的话说是什么意思?它用于图像分割或在图像中查找感兴趣的对象。简而言之,它创建的图像大小与输入图像相同(但只有一个通道),其中每个像素对应于该像素属于我们物体的概率。用更简单的话来说,与其余部分相比,输出图像将在可能有对象的区域具有更多的白色值。好吧,这是一个直观的解释。(我无法使其更简单)。直方图反投影与camshift算法等配合使用。

我们该怎么做呢?我们创建一个图像的直方图,其中包含我们感兴趣的对象(在我们的示例中是背景,离开播放器等)。对象应尽可能填充图像以获得更好的效果。而且颜色直方图比灰度直方图更可取,因为对象的颜色对比灰度强度是定义对象的好方法。然后,我们将该直方图“反投影”到需要找到对象的测试图像上,换句话说,我们计算出属于背景的每个像素的概率并将其显示出来。在适当的阈值下产生的输出使我们仅获得背景。

25.3 Numpy中的算法

1.首先,我们需要计算我们要查找的对象(使其为“ M”)和要搜索的图像(使其为“ I”)的颜色直方图。

import cv2 as cv

# roi是我们需要找到的对象或对象区域
roi = cv.imread('roi.jpg')
hsv = cv.cvtColor(roi, cv.COLOR_BGR2HSV)
# 目标是我们搜索的图像
target = cv.imread('rose.jpg')
hsv_target = cv.cvtColor(target, cv.COLOR_BGR2HSV)
# 使用calcHist查找直方图。也可以使用np.histogram2d完成
M = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
I = cv.calcHist([hsv_target], [0, 1], None, [180, 256], [0, 180, 0, 256])

2.求出比值R = \\frac{M}{I}。然后反向投影R,即使用R作为调色板,并以每个像素作为其对应的目标概率创建一个新图像。即B(x,y) = R[h(x,y),s(x,y)]其中h是色调,s是像素在(x,y)的饱和度。之后,应用条件B(x,y) = min[B(x,y), 1]

h,s,v = cv.split(hsvt)
B = R[h.ravel(),s.ravel()]
B = np.minimum(B,1)
B = B.reshape(hsvt.shape[:2])

3.现在对圆盘应用卷积,B = D \\ast B,其中D是圆盘内核。

disc = cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
cv.filter2D(B,-1,disc,B)
B = np.uint8(B)
cv.normalize(B,B,0,255,cv.NORM_MINMAX)

4.现在最大强度的位置给了我们物体的位置。如果我们期望图像中有一个区域,则对合适的值进行阈值处理将获得不错的结果。

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

就是这样!!

25.4 OpenCV的反投影

OpenCV提供了一个内建的函数cv.calcBackProject()。它的参数几乎与cv.calchist()函数相同。它的一个参数是直方图,也就是物体的直方图,我们必须找到它。另外, 在传递backproject函数之前,应该对对象直方图进行归一化。它返回概率图像。然后我们用圆盘内核对图像进行卷积并应用阈值。下面是代码和运行结果:

import numpy as np
import cv2 as cv

# roi是我们需要找到的对象或对象区域
roi = cv.imread('roi.jpg')
hsv = cv.cvtColor(roi, cv.COLOR_BGR2HSV)

# 目标是我们搜索的图像
target = cv.imread('rose.jpg')
hsv_target = cv.cvtColor(target, cv.COLOR_BGR2HSV)

# 计算对象的直方图
roi_hist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])

# 直方图归一化并利用反传算法
cv.normalize(roi_hist, roi_hist, 0, 255, cv.NORM_MINMAX)
dst = cv.calcBackProject([hsv_target], [0, 1], roi_hist, [0, 180, 0, 256], 1)
# 用圆盘进行卷积
disc = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5))
cv.filter2D(dst, -1, disc, dst)
# 应用阈值作与操作
ret, thresh = cv.threshold(dst, 50, 255, 0)
thresh = cv.merge((thresh, thresh, thresh))
res = cv.bitwise_and(target, thresh)
res = np.vstack((target, thresh, res))
cv.imwrite('res.jpg', res)

以下是我处理过的一个示例。我将小姐姐头发矩形内的区域用作示例对象,我想提取整个绿色头发。


欢迎评论区留言,一起探讨OpenCV成神之路的奥秘。

顺便给我加个关注,点个赞,加个收藏,让我们一起登上神坛。

以上是关于OpenCV竟然可以这样学!成神之路终将不远(二十五)的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV竟然可以这样学!成神之路终将不远(二十八)

OpenCV竟然可以这样学!成神之路终将不远(二十一)

OpenCV竟然可以这样学!成神之路终将不远(二十八)

OpenCV竟然可以这样学!成神之路终将不远(二十三)

OpenCV竟然可以这样学!成神之路终将不远(二十)

OpenCV竟然可以这样学!成神之路终将不远(二十六)