51.反向投影-OpenCV从零开始到图像识别

本文作者:小嗷

微信公众号:aoxiaoji

链接:https://f600lt.github.io/archives/

在本篇中,您将学习:

什么是反向投影,为什么它有用?

如何使用OpenCV函数cv::calcBackProject来计算反向投影

如何使用OpenCV函数cv::mixChannels混合不同的图像通道

本文你会找到以下问题的答案:

反向投影

mixChannels()

calcBackProject()

2.1 反向投影

要理解直方图的反向投影,先要看下直方图反向投影矩阵的计算方法!

设有原灰度图像矩阵:

Image=

将灰度值划分为如下四个区间:

[0,2] [3,5] [6,7] [8,10]

很容易得到这个图像矩阵的直方图hist= 4 4 6 2

好,接下来计算反向投影矩阵:

反向投影矩阵的大小和原灰度图像矩阵的大小相同!

原图像中坐标为(0,0)的灰度值为1,1位于区间[0,2] 中,区间[0,2] 对应的直方图值为4,所以反向投影矩阵中中坐标为(0,0)的值记为4

按上面的计算方法,可以得到Image的直方图反向投影矩阵为:

back_Projection=

从上面的计算过程我们来理解直方图的反向投影到底代表什么?

我们看到,实际上是原图像的256个灰度值被置为很少的几个值了,具体有几个值,要看把0~255划分为多少个区间!反向投影矩阵中某点的值就是它对应的原图像中的点所在区间的灰度直方图值。所以我们可以看出,一个区间点越多,在反向投影矩阵中就越亮。

那么怎么理解反向投影矩阵中的“反向”二字呢?从这个过程可以看出,我们是先求出原图像的直方图,再由直方图得到反向投影矩阵,由直方图到反向投影矩阵实际上就是一个反向的过程,所以叫反向。

通过图像的反向投影矩阵,我们实际上把原图像简单化了,简单化的过程实际上就是提取出图像的某个特征。所以以后我们可以用这个特征来对比两幅图,如果两幅图的反向投影矩阵相似或相同,那么我们就可以判定这两幅图这个特征是相同的。那么怎么对比相似度呢?可以参看第50篇。

注意累计的直方图区间数极可能大于256,所以需要归一化规定一下范围,忘了什么是归一化,找小嗷以前的文章第10几篇吧

反向投影是一种记录给定图像像素与直方图模型中像素分布匹配程度的方法。

为了简化操作:对于反向投影,计算特征的直方图模型,然后使用它在图像中查找该特征。

应用程序示例:如果您有一个肉色直方图(例如,颜色饱和度直方图),那么您可以使用它来查找图像中的肉色区域:

我们用皮肤的例子来解释这个问题:

假设你得到了一个基于下图的皮肤直方图(颜色饱和度)。除此之外的直方图将是我们的模型直方图(我们知道它代表了皮肤色调的一个样本)。你使用了一些掩膜来捕捉皮肤区域的直方图:

处理图

现在,让我们假设您得到另一个手部图像(测试图像),如下图所示:(具有其各自的直方图):

我们要做的是使用我们的模型直方图(我们知道它代表皮肤的色调)来检测我们测试图像中的皮肤区域。以下的步骤

(不知道小嗷在说什么,请查看

第47篇

在我们测试图像的每个像素(即p(i,j))中,收集数据并找到该像素的对应bin位置(即hi,j,si,j))。

查找对应bin中的模型直方图—(hi,j,si,j)—并读取bin值。

将此bin值存储在新映像中(反向投影)。另外,您可以考虑首先对模型直方图进行规范化,以便您可以看到测试图像的输出。

应用上面的步骤,我们得到了以下测试图像的反投影图像:

从统计学的角度来看,在BackProjection中存储的值代表测试图像中的像素属于皮肤区域的概率,这是基于我们使用的模型直方图。例如,在我们的测试图像中,较亮的区域更可能是皮肤区域(实际上是),而较暗的区域的可能性更小(注意,这些“暗”区域属于表面上有一些阴影,这反过来影响检测)。

3.1 create函数

自己查看第9篇[可以的话,帮小嗷推荐一下身边的共同学习的好友,老是两位数的阅读,看着伤心]

3.2 mixChannels()

将指定的通道从输入数组复制到输出数组的指定通道。

mixChannels函数为变换图像通道提供了一种高级机制。

cv::split,cv::merge,cv::extractChannel,cv::insertChannel和某些形式的cv::cvtColor是cv::mixChannels的部分情况。

在下面的示例中,代码将一个4通道的BGRA图像分割为一个3通道的BGR(交换了B和R通道)和一个单独的alpha通道图像:

与OpenCV中许多其他的新式c++函数不同(请参阅介绍部分和Mat::create), cv::mixChannels要求在调用函数之前预先分配输出数组。

将一个4通道BGRA图像分割成一个3通道BGR和一个单独的alpha通道图像:

其中,索引对from_to[] = { 0, 2, 1, 1, 2, 0, 3, 3 }的含义为:

如图所示:

因此原图的青色(255,255,0)通过指定通道复制到输出图像中变成了黄色(0,255,255)。

示例二:HSV通道获取

在HSV颜色空间中:

色相 (Hue):代表色彩。取 0 到 360 度的数值来衡量(红-黄-绿-青-蓝-洋红)。

饱和度 (Saturation):又称色度,指色彩的深浅,饱和度代表灰色与色调的比例,并以 0% (灰色) 到 100% (完全饱和) 来衡量;S = 0时只有灰度。

色调 (Value):色彩的明亮程度。V=1。它包含RGB模型中的R=1,G=1,B=1 三个面,所代表的颜色较亮。

利用mixChannels()函数通过复制指定通道可以看到HSV颜色空间下的三个通道的具体情况。

参数详情

src:输入矩阵的数组或向量;所有矩阵的大小和深度必须相同。

nsrcs:src中的矩阵数。

dst:矩阵的输出数组或向量;必须分配所有矩阵;它们的大小和深度必须与src[0]中的相同。

ndsts:dst中的矩阵数。

fromTo:指定复制哪些通道以及复制在何处的索引对数组;fromTo[k2]是src中输入通道的基于0的索引,fromTo[k2+1]是dst中输出通道的索引;采用连续通道编号:第一输入图像通道从0索引到src[0].channels()-1,第二输入图像通道从src[0].channels()索引到src[0].channels() + src[1].channels()-1等,输出图像通道采用相同的方案;在特殊情况下,当from - to [k*2]为负时,对应的输出通道为零。

npairs:从to中的索引对数。

3.3 calcBackProject()

计算直方图的反向投影。

函数cv::calcBackProject计算直方图的back project。也就是说,与calcHist类似,在每个位置(x, y),函数从输入图像中选择的通道中收集值,并找到相应的直方图bin。但是函数不是递增,而是读取bin值,按比例缩放,并存储在backProject(x,y)中。从统计学的角度来看,该函数计算每个元素值的概率,根据直方图表示的经验概率分布。例如,看看如何在场景中找到和跟踪一个鲜艳的对象

在跟踪之前,将对象显示给相机,使其几乎覆盖整个帧。计算颜色直方图。直方图可能有很强的最大值,与物体的主色调相对应。

在跟踪时,使用预计算的直方图计算每个输入视频帧的色相平面的反向投影。阈值后投影以抑制弱色。对于颜色饱和度不充分、像素过暗或过亮的像素也可以进行抑制。

在结果图片中找到连接的组件并选择,例如,最大的组件。

这是CamShift彩色目标跟踪器的一个近似算法。

参数详情

加载一个图像

将原始的HSV格式转换为单独的色相通道用于直方图(使用OpenCV函数cv::mixChannels)

让用户输入计算直方图时要使用的bin(区间数)。

计算直方图(如果区间数改变了就更新它)和相同图像的反向投影。

在窗口中显示反向投影和直方图。

本篇文章的代码如下所示。

源图:

效果图:

解释一下:

读输入图片:

将其转换为HSV格式:

对于本文,我们将只使用1-D直方图的色相值(如果您想使用更标准的H-S直方图,请查看上面链接中更花哨的代码,这样可以得到更好的结果):

为用户创建一个轨迹栏来输入bin值。Trackbar上的任何更改都意味着对Hist_and_Backproj回调函数的调用。

显示图像,等待用户退出程序:

Hist_and_Backproj函数:初始化cv::calcHist所需的参数。区间数来自于Trackbar:

计算直方图并将其规范化为范围[0,255]

所有的参数都已知(与计算直方图相同),只有我们添加backproj矩阵,它将存储源图像的backprojection (&hue)

显示backproj:

绘制图像的一维色相直方图:

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180813G07CMS00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券