OpenCV学习(二十二) :反向投影:calcHist(),minMaxLoc(),compareHist()

参考博客:
反向投影backproject的直观理解
opencv 反向投影
颜色直方图的计算、显示、处理、对比及反向投影

一、概述

1、官方解释:反向投影是一种记录给定图像中的像素点如何适应直方图模型像素分布的方式。简单的讲,
1)就是首先计算某一特征的直方图模型;(特征可以为色调+饱和度、灰度值等等)
2)然后使用模型去寻找图像中存在的该特征。例如,你有一个肤色直方图(Hue-Saturation直方图),你可以用它(色调和饱和度)来寻找图像中的肤色区域:

2、反向投影图就是图像对应位置像素的数量统计,也可以看做是密度统计。 反向投影图在某一位置(点)的值是原图对应位置(点)的像素值所在原图区间(bins)的总数目。(所以,一个区间点越多,在反向投影矩阵中就越亮。)

3、反向投影中的“反向”指的是从直方图值到反向投影矩阵映射的过程。

4、通过反向投影,原始的图像被简化了,而这个简化的过程实际上就是提取出图像的某个特征。所以我们就可以用这个特征来对比两幅图,如果两幅图的反向投影矩阵相似或相同,那么我们就可以判定这两幅图这个特征是相同的。

5、反向投影的作用:
反向投影用于在输入图像(通常较大)中查找**特定图像(通常较小或者仅1个像素,以下将其称为模板图像)**最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。如图:

第一个图为源图像,中间的那个小图像是产生用于反向投影的直方图的图像,最后的用直方图均衡化后的结果图像,可以看到,苹果的像素位置几被找到了。

二、calcBackProject()函数

calcBackProject 的基本过程是:
1)拿到 特征图像 (或模板图像)
2)得到 特征图像的直方图
3)拿到测试图像,依据测试图像的每个像素的值,在特征图像的直方图中找到对应的值,然后将直方图的值赋给新的图像,backproject算法就完成了。

void cv::calcBackProject(
const Mat* images       // 输入图像,图像深度必须位CV_8U,CV_16U或CV_32F中的一种,尺寸相同,每一幅图像都可以有任意的通道数
int nimages             // 输入图像的数量
const int* channels     // 用于计算反向投影的通道列表,通道数必须与直方图维度相匹配,第一个数组的通道是从0到image[0].channels()-1,
InputArray hist         // 输入的直方图,直方图的bin可以是密集(dense)或稀疏(sparse)
OutputArray backProject // 目标反向投影输出图像,是一个单通道图像,与原图像有相同的尺寸和深度
const float ranges**    // 直方图中每个维度bin的取值范围
double scale=1:            // 可选输出反向投影的比例因子
bool uniform=true:     // 直方图是否均匀分布(uniform)的标识符,有默认值true
)

三、CalcBackProjectPatch()函数

对于calcBackProjectPatch,整个是基于块的形式,利用直方图做匹配,类似于模板匹配,只不过这些模板转换为直方图,而原图中以某点为基准,抠出来作对比的部分也转换为直方图,两个直方图作匹配,匹配的结果作为此点的值。

结果会是一张概率图,概率越大的地方,代表此区域与模板的相似度越高。而且,当模板小于检测的目标时,得到的结果图也能反映出检测区域的形状。这个结果与模板匹配的结果很相似,但利用直方图的方式,就能去除光照变化、边缘遮挡,旋转等因素的影响。另外
基于块的反向投影。这种方法速度很慢,模版图像别弄的太大了。
例如:
1)当模板图像小与目标的时候,作为区域检测器,测试如下:可以找到手区域

2)当模板等于目标的时候,测试如下:输出图像,较亮的部分就是人的头部大致位置

详情参考:
opencv 直方图反向投影

函数原型:

void cvCalcBackProjectPatch(
IplImage** image,   // 输入图像:是一个单通道图像数组,而非实际图像
CvArr* dst,         // 输出结果:是一个单通道32位浮点图像,它的宽度为W-w+1,高度为H-h+1,这里的W和H是输入图像的宽度和高度,w和h是模板图像的宽度和高度
CvSize patch_size,  // 模板图像的大小:宽度和高度
CvHistogram* hist,  // 模板图像的直方图:直方图的维数和输入图像的个数相同,并且次序要一致;例如:输入图像包含色调和饱和度,那么直方图的第0维是色调,第1维是饱和度
int method,         // 对比方式:跟直方图对比中的方式类似,可以是:CORREL(相关)、CHISQR(卡方)、INTERSECT(相交)、BHATTACHARYYA
float factor        // 归一化因子,一般都设置成1,否则很可能会出错;中文、英文以及各路转载的文档都错了,这个参数的实际类型是double,而非float,我看了源代码才搞定这个地方
)

四、mixChannels()函数

mixChannels()函数用于将输入数组的指定通道复制到输出数组的指定通道。
其实我们接触到的,split()和merge(),以及cvtColor的某些形式,都只是mixChannels()的一部分。
参考:
opencv3/C++ mixChannels()详解:4通道图像分割、HSV通道获取

void mixChannels(
const Mat* src,         //输入数组或向量矩阵,所有矩阵的大小和深度必须相同。
size_t nsrcs,           //第一个参数src矩阵的数量
Mat* dst,               //输出数组或矩阵向量,大小和深度必须与src[0]相同
size_t ndsts,           //第三个参数ndsts矩阵的数量
const int* fromTo,      //指定被复制通道与要复制到的位置组成的索引对
size_t npairs           //fromTo中索引对的数目
);

示例:

#include<opencv2/opencv.hpp>
using namespace cv;int main()
{Mat bgra( 500, 500, CV_8UC4, Scalar(255,255,0,255) );Mat bgr( bgra.rows, bgra.cols, CV_8UC3 );Mat alpha( bgra.rows, bgra.cols, CV_8UC1 );Mat out[] = { rgb, alpha };int from_to[] = { 0, 2, 1, 1, 2, 0, 3, 3 };// 输入1一个矩阵,输出2个举证,4个索引对mixChannels( &bgra, 1, out, 2, from_to, 4 );imshow("bgra", bgra);  // 青色imshow("bgr", bgr);      // 黄色(通道值改变,色彩空间不变)waitKey(0);return 0;
}

五、示例:

使用模型直方图(代表手掌的皮肤色调)来检测测试图像中 的皮肤区域。
1)对测试图像中的每个像素(p(i,j),获取色调数据并找到该色调(h(i,j),s(i,j))在直方图中的bin的位置;
2)查询模型直方图中对应的bin-(hi,j,si,j)并读取该bin的数值;
3)将此数值存储在新的图像中(BackProjection)。你也可以先归一化模型直方图,这样测试图像的输出就可以在屏幕显示了;
4)通过对测试图像中的每个像素采用以上步骤,我们得到了下面的BackProjection结果图:
5)使用统计学的语言,BackProjection中存储的数值代表了测试图像中该像素属于皮肤区域的概率。比如上图为例,亮起的区域是皮肤区域的概率更大,而更暗的区域则表示更低的概率(注意手掌内部和边缘的阴影影响了检测的精度)。

#include <opencv2/opencv.hpp>using namespace cv;
using namespace std;Mat g_srcImage,g_hsvImage,g_hueImage;
int g_bins = 30;//直方图组距int main()
{// 1、载入源图,转化为HSV颜色模型g_srcImage = imread("F:/C++/2. OPENCV 3.1.0/TEST/shou.jpg", 1);if(!g_srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定图片存在~! \n"); return false; }cvtColor( g_srcImage, g_hsvImage, CV_BGR2HSV ); // 转换颜色空间// 2、分离 Hue 色调通道g_hueImage.create( g_hsvImage.size(), g_hsvImage.depth() );  // 创建同尺寸、深度的单通道图int ch[ ] = { 0, 0 };mixChannels( &g_hsvImage, 1, &g_hueImage, 1, ch, 1 );imshow("g_hueImage", g_hueImage);// 3、创建 Trackbar 来输入bin的数目namedWindow( "反向投影图" , CV_WINDOW_AUTOSIZE );createTrackbar("色调组距 ", "反向投影图" , &g_bins, 180, on_BinChange );on_BinChange(0, 0);//进行一次初始化// 4、显示效果图imshow( "【原始图】" , g_srcImage );waitKey(0);return 0;
}

直方图计算 bins(特征空间子区段的数目)回调函数:

void on_BinChange(int, void* )
{// 1、参数准备MatND hist;int histSize = MAX( g_bins, 2 );    // 组距 最小为2float hue_range[] = { 0, 180 };const float* ranges = { hue_range };// 2、计算直方图并归一化// 将handhue取值替换为g_hueImage图像的中心部分,作为特征图像Mat handhue_feature= g_hueImage(Rect(g_hueImage.rows/2-25, g_hueImage.cols/2-25, 50, 50)).clone();// g_hueImageimshow("handhue_feature", handhue_feature); // 显示特征// 将handhue_feature的取值 替换为g_hueImage图像的中心部分,作为特征图像calcHist( &handhue_feature, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false );normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() );     // 归一化直方图数值范围为0~255之间// 3、计算 获取反向投影MatND backproj;calcBackProject( &g_hueImage, 1, 0, hist, backproj, &ranges, 1, true );// 4、显示反向投影imshow( "反向投影图", backproj );// 5、绘制直方图的参数准备int w = 400; int h = 400;int bin_w = cvRound( (double) w / histSize );Mat histImg = Mat::zeros( w, h, CV_8UC3 );// 6、绘制直方图for( int i = 0; i < g_bins; i ++ ){ rectangle( histImg, Point( i*bin_w, h ), Point( (i+1)*bin_w, h - cvRound( hist.at<float>(i)*h/255.0 ) ), Scalar( 100, 123, 255 ), -1 ); }// 7、显示直方图窗口imshow( "直方图", histImg );
}

源图+色调图

特征图:




OpenCV学习(二十二) :反向投影:calcBackProject(),mixChannels()相关推荐

  1. OpenCV学习笔记(十二)——图像分割与提取

    在图像处理的过程中,经常需要从图像中将前景对象作为目标图像分割或者提取出来.例如,在视频监控中,观测到的是固定背景下的视频内容,而我们对背景本身并无兴趣,感兴趣的是背景中出现的车辆.行人或者其他对象. ...

  2. OpenCV学习20-直方图反向投影

    ''' 直方图反向投影是由 Michael J. Swain 和 Dana H. Ballard 在他们的 文章"Indexing via color histograms"中提出 ...

  3. Opencv学习笔记(十二):图片腐蚀和膨胀操作

    文章目录 腐蚀 代码 效果 膨胀 代码 效果 开运算/闭运算 代码 腐蚀 原理:是在原图的小区域内取局部最小值.因为是二值化图,只有 0 和 255,所以小区域内有一个是 0 该像素点就为 0: 作用 ...

  4. opencv学习笔记十二:梯度算子

    [1]Robert算子: || =  由于平方和不便于计算,故近似为绝对值形式: || =| | 实际应用中,经常采用的是另一种近似梯度: |

  5. OpenCV学习笔记(二十六)——小试SVM算法ml OpenCV学习笔记(二十七)——基于级联分类器的目标检测objdect OpenCV学习笔记(二十八)——光流法对运动目标跟踪Video Ope

    OpenCV学习笔记(二十六)--小试SVM算法ml 总感觉自己停留在码农的初级阶段,要想更上一层,就得静下心来,好好研究一下算法的东西.OpenCV作为一个计算机视觉的开源库,肯定不会只停留在数字图 ...

  6. OpenCV学习笔记(二十一)——绘图函数core OpenCV学习笔记(二十二)——粒子滤波跟踪方法 OpenCV学习笔记(二十三)——OpenCV的GUI之凤凰涅槃Qt OpenCV学习笔记(二十

    OpenCV学习笔记(二十一)--绘图函数core 在图像中,我们经常想要在图像中做一些标识记号,这就需要绘图函数.OpenCV虽然没有太优秀的GUI,但在绘图方面还是做得很完整的.这里就介绍一下相关 ...

  7. python做直方图-python OpenCV学习笔记实现二维直方图

    本文介绍了python OpenCV学习笔记实现二维直方图,分享给大家,具体如下: 官方文档 – https://docs.opencv.org/3.4.0/dd/d0d/tutorial_py_2d ...

  8. Tensorflow深度学习之十二:基础图像处理之二

    Tensorflow深度学习之十二:基础图像处理之二 from:https://blog.csdn.net/davincil/article/details/76598474   首先放出原始图像: ...

  9. 花书+吴恩达深度学习(十二)卷积神经网络 CNN 之全连接层

    目录 0. 前言 1. 全连接层(fully connected layer) 如果这篇文章对你有一点小小的帮助,请给个关注,点个赞喔~我会非常开心的~ 花书+吴恩达深度学习(十)卷积神经网络 CNN ...

最新文章

  1. 推理计算过程_初中物理电学计算题第六讲:极值问题推理和限制条件
  2. 如何在ASP.NetCore增加文件上传大小
  3. 统计一个panel中lable的个数
  4. (02)System Verilog logic数据类型详解
  5. 纹理窗口Qt+OpenGL之纹理贴图
  6. “The Stupidity Paradox”作者访谈
  7. 两种查找bapi的方法
  8. QT中ui更改后不能更新的解决方法
  9. Javascript校验含中文的字符串长度
  10. 国内29家视觉企业及最新动态一览
  11. 顺序栈的实验报告c语言,顺序栈的基本操作(C语言)
  12. CS5210 CS5213 CS5212 CS5211 CS5216电路原理图+PCB板
  13. WIN10 任务栏转圈 白屏问题
  14. 错误: 在类 Hello 中找不到 main 方法, 请将 main 方法定义为: public static void main(String[] args)
  15. 稀里糊涂的准备开始了……
  16. 云麦体脂秤华为体脂秤_如果是一个真正的体脂秤就好了:华为智能体脂秤
  17. OPPO消息推送服务器,OPPO推送平台服务端API.PDF
  18. 微信小程序电商项目商品详情页开发实战之数据绑定与事件应用
  19. 通过guest账户无法进入远程计算机,小经验|guest远程关机设置
  20. 可由线性表示且表达式唯一_证明y可由b1.b2--bn线性表出且表示法唯一

热门文章

  1. 数据分析-书籍整理(三)
  2. NLP哪个细分方向最具社会价值?
  3. LightGBM最强解析,从算法原理到代码实现~
  4. 论文浅尝 | GraphSAINT—基于图采样的归纳学习方法
  5. 论文浅尝 | 时序与因果关系联合推理
  6. 科大讯飞2020完整事件抽取系统(bert+数据集)
  7. 工程实践:基于规则模式的军事和医药领域知识图谱问答快速实现
  8. 【原创】论码农的财富修养
  9. Opencv级联分类器实现人脸识别
  10. sublime 设置新建文件自动添加author(作者)等文件头信息