OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
来源:互联网 发布:2016年非农数据统计 编辑:程序博客网 时间:2024/06/05 09:44
作者:冰山一脚
转自:http://www.cnblogs.com/slysky/archive/2011/10/13/2210745.html
//initializing
for i=1:M
Hist[i] = 0;
end
//voting
for i = 1:N
Hist[x[i]] += 1 ;
end
for j = 1:M
Hist[j] = Hist[j]/sum(Hist) ; //sum(Hist) = Hist[1] + Hist[2] + ... + Hist[M];
end
for i=1:M
Hist[i] = 0;
end
//voting
for i = 1:N
Hist[x[i]] += w[i] ;
end
颜色直方图直观的显示了图像在色彩空间的分布状况,本文将讨论在OpenCv中跟直方图相关的一些基本操作,包括:计算、显示、处理、对比及反向投影.
直方图的计算、显示、处理
OpenCv中,可以用方法cvCalcHist方法计算图像的直方图。不过值得注意的是,该方法的第一个参数image是一个指向数组的IplImage* 类型指针。这允许利用多个图像通道。对于多通道图像(如HSV或者RGB),在调用函数cvCalcHist()之前,先要调用函数cvSplit()将图像分为单通道,此方法与宏cvCvtPixtoPlane等同,然后再选择需要参与直方图计算的通道。下面有几段计算直方图的代码,分别计算单通道(红色)直方图、色调和饱和度直方图。
如何在OpenCV中绘制一个直方图?下面是有关于绘制直方图实验的学习总结:
1.cvCreateHist(dim,&size,flag,**range,uniform):
dim为hist的维度;size为总分区间数;flag为标记图像是什么类型,是CV_HIST_ARRAY,还是CV_HIST_TREE,然后就可以选择如何保存数据,如果CV_HIST_ARRAY,就用CvMatND(多维密集数组);如果CV_HIST_TREE,就使用CvSparseMat(多维稀疏数组);range为每个维度的范围;uniform为归一化标识,这个还不是很好理解。
2.IplImage中有一个属性可以设置图像的原点坐标,0代表左上角,1代表左下角。(image->origin)
3.cvCalcHist(**imge,*hist):
image为统计图像,hist为直方图结构体
4.获取了直方图信息后,可以通过直方图结构体直接访问内部信息:
hist->type;hist->thresh[i][0]和hist->thresh[i][1]分别存储上阀值和下阀值。如果CV_HIST_ARRAY的话,可以通过((CvMatND*)hist->bins)->data.fl[i]获取统计值。不过OpenCV已经提供了一个很好的方法去查询,cvQueryHistValue_*D(hist,d...);
5.可以通过CV_RGB(R,G,B)的宏设置RGB颜色。
6.直方图的绘制,使用cvQueryHistValue_*D去获取统计值,然后绘制在一个创建好的图像中。可以通过cvLine或者cvRectangle方法。
7.还可以通过设置range的范围来获取有需要的区域,如果这样的话,最好在画直方图的时候,计算好每个区间的width值。
8.cvGetMinMaxValue(hist,*min,*max,*minindex,*maxindex):
min和max必须为float类型,minindex和maxindex为最小最大值的位置
9.cvRound方法:四舍五入
10.从HSV颜色转换为RGB颜色:
IplImage* hsv_color = cvCreateImage(cvSize(1,1),8,3);
IplImage* rgb_color = cvCreateImage(cvSize(1,1),8,3);
cvSet2D(hsv_color,0,0,cvScalar(h*180.f/h_bins,s*255.f/s_bins,255,0));
cvCvtColor(hsv_color,rgb_color,CV_HSV2BGR);
CvScalar color = cvGet2D(rgb_color,0,0);
具体代码如下:
直方图对比
OpenCv提供了5种对比直方图的方式:CORREL(相关)、CHISQR(卡方)、INTERSECT(相交)、BHATTACHARYYA、EMD(最小工作距离),其中CHISQR速度最快,EMD速度最慢且有诸多限制,但是EMD的效果最好。世界总是充满了矛盾,而我们的工作就是化解矛盾,把每种方式都测试一下,找到正好能解决问题并且速度最优的方法。
需要注意的是:EMD方式要求先将直方图转换成矩阵:
EMD方法会占用很很很大量的内存,在使用前请注意直方图的维数及区间数目,不然会出现内存不足的异常。关于这点,请参看我的另一篇文章《关于使用cvCalcEMD2计算两个直方图间最小工作距离的限制(Why cvCalcEMD2 Throw Insufficient Memory Exception)》。还有一点值得注意的是,不同的对比方式对待结果的方式很不一样,结果越大不一定说明匹配度更高,具体请参看《学习OpenCv》这本书的相关章节。
对于直方图的相关和相交对比,结果值越大(即亮度较高)的地方表示匹配程度越高;
对于直方图的卡方、Bhattacharyya、EMD对比,结果值越小(即越黑暗)的地方表示匹配程度越高。
陆地移动距离EMD
光线能引起图像颜色值的漂移,尽管这些漂移没有改变颜色直方图的形状,但是这些漂移引起了颜色值位置的变化,从而导致前述匹配策略失效。如果利用颜色直方图的距离测量来代替直方图的匹配策略,那么我们仍然可以像直方图对比一样对比两个直方图的距离,即使第二个直方图发生漂移,也能找到最小的距离度量。
陆地移动距离时一种度量准则,它实际上度量的是怎样将一个直方图的形状转变为另一个直方图的形状,包括移动直方图的部分或者全部到一个新的位置,可以在任何维的直方图上进行这种度量。
0表示最精确匹配,半匹配是成功将直方图的一半转换,将左边直方图的一半转换到下一个直方图。最终移动整个直方图到右边需要整个单位的距离(即将模板直方图转换为完全不匹配直方图)。1表示完全不匹配。
具体代码如下:
直方图的反向投影
1.反向投影的作用是什么?
反向投影用于在输入图像(通常较大)中查找特定图像(通常较小或者仅1个像素,以下将其称为模板图像)最匹配的点或者区域,也就是定位模板图像出现在输入图像的位置。
2.反向投影如何查找(工作)?
查找的方式就是不断的在输入图像中切割跟模板图像大小一致的图像块,并用直方图对比的方式与模板图像进行比较。
假设我们有一张100x100的输入图像,有一张10x10的模板图像,查找的过程是这样的:
(1)从输入图像的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;
(2)生成临时图像的直方图;
(3)用临时图像的直方图和模板图像的直方图对比,对比结果记为c;
(4)直方图对比结果c,就是结果图像(0,0)处的像素值;
(5)切割输入图像从(0,1)至(10,11)的临时图像,对比直方图,并记录到结果图像;
(6)重复(1)~(5)步直到输入图像的右下角。
3.反向投影的结果是什么?
反向投影的结果包含了:以每个输入图像像素点为起点的直方图对比结果。可以把它看成是一个二维的浮点型数组,二维矩阵,或者单通道的浮点型图像。
4.特殊情况怎么样?
如果输入图像和模板图像一样大,那么反向投影相当于直方图对比。如果输入图像比模板图像还小,直接罢工~~。
5.使用时有什么要注意的地方?
需要注意的地方比较多,我们对照反向投影函数来说:
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,我看了源代码才搞定这个地方*/
);
还有最需要注意的地方:这个函数的执行效率非常的低,在使用之前尤其需要注意图像的大小,直方图的维数,对比方式。如果说对比单个直方图对现在的电脑来说是清风拂面,那么反向投影是狂风海啸。对于1010x1010的RGB输入图像,10x10的模板图像,需要生成1百万次3维直方图,对比1百万次3维直方图。
下面为具体代码:
模板匹配(Match Template) 修改版
模板匹配的工作方式
模板匹配的工作方式跟直方图的反向投影基本一样,大致过程是这样的:通过在输入图像上滑动图像块对实际的图像块和输入图像进行匹配。
假设我们有一张100x100的输入图像,有一张10x10的模板图像,查找的过程是这样的:
(1)从输入图像的左上角(0,0)开始,切割一块(0,0)至(10,10)的临时图像;(改者注:其实每次匹配都是在模板的中心点对应的位置来给像素赋值,即第一次比较应该是将模板的(temp.width/2,temp.height/2)中心点开始的1/4面积同输入图像进行比较,匹配得到的结果c保存到模板中心点所在像素值中,具体参照《Learning OpenCV》,所以最终用来保留匹配结果的图像大小应该是size = (images->width - patch_size.x + 1,images->height - patch_size.y + 1))
(2)用临时图像和模板图像进行对比,对比结果记为c;
(3)对比结果c,就是结果图像(0,0)处的像素值;
(4)切割输入图像从(0,1)至(10,11)的临时图像,对比,并记录到结果图像;
(5)重复(1)~(4)步直到输入图像的右下角。
大家可以看到,直方图反向投影对比的是直方图,而模板匹配对比的是图像的像素值;模板匹配比直方图反向投影速度要快一些,但是我个人认为直方图反向投影的鲁棒性会更好。
模板匹配的匹配方式
在OpenCv和EmguCv中支持以下6种对比方式:
CV_TM_SQDIFF 平方差匹配法:该方法采用平方差来进行匹配;最好的匹配值为0;匹配越差,匹配值越大。
CV_TM_CCORR 相关匹配法:该方法采用乘法操作;数值越大表明匹配程度越好。
CV_TM_CCOEFF 相关系数匹配法:1表示完美的匹配;-1表示最差的匹配。
CV_TM_SQDIFF_NORMED 归一化平方差匹配法
CV_TM_CCORR_NORMED 归一化相关匹配法
CV_TM_CCOEFF_NORMED 归一化相关系数匹配法
根据我的测试结果来看,上述几种匹配方式需要的计算时间比较接近(跟《学习OpenCv》书上说的不同),我们可以选择一个能适应场景的匹配方式。
具体代码:
感谢您耐心看完本文,希望对您有所帮助。
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影【转】
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
- 颜色直方图的计算、显示、处理、对比及反向投影(How to Use Histogram? Calculate, Show, Process, Compare and BackProject)
- 颜色直方图的计算、显示、处理、对比及反向投影(How to Use Histogram? Calculate, Show, Process, Compare and BackProject)
- OpenCV之imgproc 模块. 图像处理(4)直方图均衡化 直方图计算 直方图对比 反向投影 模板匹配
- 图像直方图的反向投影的计算
- 直方图的反向投影
- 直方图的反向投影
- 直方图的反向投影
- 直方图的反向投影
- OPENCV直方图计算原理及反向投影检测原理
- OPENCV直方图计算原理及反向投影检测原理
- 关于颜色直方图和反向投影的一些理解
- 关于颜色直方图和反向投影的一些理解
- 用凸包优化两点间最长距离问题
- Qt编写串口通信程序全程图文讲解
- document.getElementById/Name/TagName .
- Activity startActivityForResult启动方式学习
- Bug 7307972 - Excessive waits on 'library cache: mutex x' (文档 ID 7307972.8)
- OpenCV_颜色直方图的计算、显示、处理、对比及反向投影
- Android Handler类 一看就懂
- 编写更好的CSS代码
- Session和Cookie的区别与联系
- 用xStart安装oracle,提示:/usr/X11R6/bin/xterm:No such file or directory 解决方法
- 在python中使用cx_Oracle模块出现“DLL Load failed”的处理方法
- 不能解析el表达式的问题
- 深度优先搜索
- GNU Binutils