对输入的两张图像进行直方图均衡化及直方图计算步骤后,可以对两个图像的直方图进行对比,两张图像的直方图反映了该图像像素的分布情况,可以利用图像的直方图,来分析两张图像的关系。

如果我们有两张图像,并且这两张图像的直方图一样,或者有极高的相似度,那么在一定程度上,我们可以认为这两幅图是一样的,这就是直方图比较的应用之一。

直方图比较原理

要比较两个直方图(H1 和 H2),首先必须要选择一个衡量直方图相似度的对比标准,我们设为d(H1,H2),对输入的两张图像计算得到直方图H1与H2,归一化到相同的尺度空间,然后可以通过计算H1与H2的之间的距离得到两个直方图的相似程度进而比较图像本身的相似程度。Opencv提供的比较方法有四种:

  1. Correlation 相关性比较   ( CV_COMP_CORREL 0)
  2. Chi-Square 卡方比较       ( CV_COMP_CHISQR 1)
  3. Intersection 十字交叉性   ( CV_COMP_INTERSECT 2)
  4. Bhattacharyya distance 巴氏距离 ( CV_COMP_BHATTACHARYYA 3)

OpenCV使用compareHist函数进行相似性计算,该函数返回一个数值,相关性方法范围为0到1,1为最好匹配,卡方法和Bhattacharyya距离法是值为0最好,而交集法为值越大越好。函数原型:

CV_EXPORTS_W double compareHist( InputArray H1, InputArray H2, int method );//! compares two histograms stored in sparse arrays
CV_EXPORTS double compareHist( const SparseMat& H1, const SparseMat& H2, int method );

(1)相关性比较(Correlation)(method=CV_COMP_CORREL)

相关性比较公式如下:

             

 其中:

N等于直方图中bin的个数。 如果H1 = H2,即两个图的直方图一样,分子等于分母,值为1,所以在不严格的情况下,当值为1时,可以认为两个图是一样的。但是也有可能会出现两个图不一样,但是两个图的直方图是一样的情况。因为直方图计算的是像素点个数的分布情况,但是不会显示像素点的位置,所以有可能会出现两幅图片不一样,但是相同像素的个数完全一样,那他们的直方图也是一样的,不过这种情况,不常有。

相关性比较公式来源于统计学中的相关系数,是研究变量之间线性相关程度的量,一般用字母 r 表示。
                                                       

其中,Cov(X,Y)为X与Y的协方差,Var[X]为X的方差,Var[Y]为Y的方差。

2)卡方,Chi-Square(method=CV_COMP_CHISQR)


   通过这个公式我们能够发现,卡方比较和相关性比较恰恰相反,相关性比较的值为0,相似度最低,越趋近于1,相似度越低;卡方比较则是,值为0时说明H1= H2,这个时候相似度最高。

卡方比较来源于卡方检验,卡方检验就是统计样本的实际观测值与理论推断值之间的偏离程度,实际观测值与理论推断值之间的偏离程度就决定卡方值的大小,卡方值越大,越不符合;卡方值越小,偏差越小,越趋于符合,若两个值完全相等时,卡方值就为0,表明理论值完全符合。

卡方检验的公式如下,其中fi是观测频率,npi是期望频率,X²是卡方值。

3)Intersection(十字交叉性)(method-CV_COMP_INTERSECT)


    这个就比较简单了,对比H1,H2并求出最小值,最后求和。

 4)Bhattacharyya距离,(method=CV_COMP_BHATTACHARYYA)

定义:对于在X 数域上的两个离散概率分布p 和q,巴氏距离定义为: DB(p,q) = -ln(BC(p,q))

其中 BC(p,q) = Σsqrt(p(x)*q(x)),BC 被称作Bhattacharyya 系数(巴氏系数),0≤BC≤1 且0≤DB≤∞

巴氏系数全称为巴塔恰里雅(Bhattacharyya coefficient) 系数,是向量相似度匹配中(如:用于衡量参考模版与候选模版的颜色概率分布的相似度或者说相关性测量)最常用的小算法。

              
      在直方图相似度计算时,巴氏距离获得的效果最好,但计算是最为复杂的。巴氏距离的计算结果,其值完全匹配为1,完全不匹配则为0。上式中的分数是一个归一化系数。

图像相似性度量-------EMD

EMD算法是用来比较两幅图像相似性的方法。在颜色直方图中,由于光线等的变化会引起图像颜色值的漂移,它们会引起颜色值位置的变化,从而导致直方图匹配失效。对于两个形状相同,但只是相对平移的两个直方图,距离度量会给出一个很大的值,我们需要一个对这种平移不敏感的距离度量方法。EMD的思想是求得从一幅图像转化为另一幅图像的代价,用直方图来表示就是求得一个直方图转化为另一个直方图的代价,代价越小,越相似。所以EMD可以理解为:直方图A转化为直方图B时,需要把A中的每一个bin进行分割给B中的每一个bin,在乘上bin之间的代价。

先介绍一下signature的概念。大家都知道,一个图像的直方图就是把图像像素值量化为一系列bin,统计落在相应bin的像素个数,就形成了直方图。

signature的定义为:,    对于一个一维直方图,m为直方图的bin索引,w为该bin上的数量。它代表了一系列特征类别。每个s代表一类特征,m为其类中心,w为属于该类中心的数量。

为什么要用signature呢?作者的说法是经常性的直方图的内容会聚集在某些bin上,而传统的完整表达的直方图显然太过于浪费空间。而用signature可以很方便的表达比较稀疏的直方图内容。(一个灰度图形成的一维直方图可能不会稀疏,但是想象一个三维直方图,它可能就会比较稀疏了)

EMD本身是一个线性规划问题。定义如下两个signature P和Q,分别有m和n个类。
                                            

另外定义一个类别的距离矩阵,每一项为pi和qj的距离(在均匀的直方图中,距离就可以简化为bin的索引的差值的绝对值)。可以发现它是mxn的矩阵::

那么问题就是我们希望找到一个矩阵[],每一项代表从pi到qj的流动数量,从而最小化整体的代价函数:


     这里就可以把EMD的本质说出来了,说白了,就是把P中的m个坑的土,用最小的代价搬到Q中的n个坑中,pi到qj的两个坑的距离由dij来表示。是从pi搬到qj的土的量;是pi位置到qj位置的代价(距离)。要最小化WORK工作量。EMD是把这个工作量归一化以后的表达,即除以对的求和。

假如:A和B都有两个bin,且A到B的距离代价分别为d11=0.4和d12=0.7,d21=0.2,d22=0.6;A的bin1为0.5,且分成0.1和0.4给B的bin1和bin2,同样,A的bin2分成0.3和0.2给B的bin1和bin2,则EMD=0.1*0.4+0.7*0.4+0.2*0.3+0.6*0.2 

EMD( InputArray signature1, InputArray signature2,int distType, InputArray cost=noArray(),float* lowerBound=0, OutputArray flow=noArray() );
  • signature1 大小为 size1×(dims+1) 的浮点数矩阵,每一行依次存储点的权重和点的坐标。矩阵允许只有一列(即仅有权重),如果使用用户自定义的代价矩阵。
  • signature2 与 signature1 的格式一样size2×(dims+1),尽管行数可以不同(列数要相同)。当一个额外的虚拟点加入 signature1 或 signature2 中的时候,权重也可不同。
  • distance_type 使用的准则, CV_DIST_L1, CV_DIST_L2, 和 CV_DIST_C 分别为标准的准则。
  • cost自定义大小为 size1×size2 的代价矩阵。
  • flow 产生的大小为 size1×size2 流矩阵(flow matrix): flowij 是从 signature1 的第 i 个点到 signature2 的第 j 个点的流(flow)。
  • lowerbound 可选的输入/输出参数:两个签名之间的距离下边界,是两个质心之间的距离。如果使用自定义代价矩阵,点集的所有权重不等,或者有签名只包含权重(即该签名矩阵只有单独一列),则下边界也许不会计算。用户必须初始化 *lower_bound. 如果质心之间的距离大于获等于 *lower_bound (这意味着签名之间足够远), 函数则不计算 EMD. 任何情况下,函数返回时 *lower_bound 都被设置为计算出来的质心距离。因此如果用户想同时计算质心距离和T EMD, *lower_bound 应该被设置为 0.

过程:

  1. 把图像从RGB色彩空间转换到HSV色彩空间(因为直方图都是基于亮度和灰度级别,二HSV色彩空间对色彩亮度表示比较好的方式,转换成HSV空间以后然后只取HS通道)
  2. 计算图像的直方图,然后归一化到[0~1]之间calcHist和normalize;
  3. 使用上述四种比较方法之一进行比较compareHist.

实例展示

a.加载图像

b.将图像从BGR空间转化为HSV空间

c.计算直方图并归一化处理

d.直方图比较

e.展示图像

#include<iostream>
#include<opencv2\opencv.hpp>using namespace std;
using namespace cv;int main() {
//直方图相似度比较vector<Mat> src;//迭代器push_backMat temp = imread("0.jpg", 1);int m=temp.rows / 2;int n = temp.cols;//将一幅图分割为上下两部分Mat image_cut =Mat(temp, Rect(0, 0, n, m)).clone();//Rect(x,y,w,h)Mat image_cut2 = Mat(temp, Rect(0, m, n, m)).clone();src.push_back(image_cut); src.push_back(image_cut2);temp = imread("1.jpg", 1);src.push_back(temp);temp = imread("2.jpg", 1);src.push_back(temp);vector<Mat> hsv(4), hist(4),hist_img(4);int scale=10,histSize[] = { 8,8 }, ch[] = { 0,1 };//30rows,32colsfloat h_ranges[] = { 0,180 };float s_ranges[] = { 0,255 };const float* ranges[] = { h_ranges,s_ranges };for (int i = 0; i < 4 ; i++) {cvtColor(src[i], hsv[i], COLOR_RGB2HSV);calcHist(&hsv[i], 1, ch, noArray(), hist[i], 2, histSize, ranges, true);normalize(hist[i], hist[i], 0, 255, NORM_MINMAX);hist_img[i]=Mat::zeros(histSize[0] * scale, histSize[1] * scale, CV_8UC3);for (int h = 0; h < histSize[0]; h++) {for (int s = 0; s < histSize[1]; s++) {float hval = hist[i].at<float>(h, s);rectangle(hist_img[i], Rect(h * scale, s * scale, 10, 10), Scalar::all(hval), -1);}}}//displayimshow("0", src[0]); imshow("1", src[1]); imshow("2", src[2]); imshow("3", src[3]);imshow("hist0", hist_img[0]); imshow("hist1", hist_img[1]); imshow("hist2", hist_img[2]); imshow("hist3", hist_img[3]);for (int i = 0; i < 4; i++){cout << "hist[0] vs hist[" << i <<"]"<< endl;for (int j = 0; j < 4; j++) {cout << "method[" << j <<"]"<< compareHist(hist[0], hist[i], j)<<endl;}}//do EMD vector<Mat> sig(4);for (int i = 0; i < 4; i++) {vector<Vec3f> sigv;normalize(hist[i], hist[i], 1, 0, NORM_L1);for (int h = 0; h < histSize[0]; h++) for (int s = 0; s < histSize[1]; s++) {float hval = hist[i].at<float>(h, s);if (hval != 0)sigv.push_back(Vec3f(hval, (float)h, (float)s));}sig[i] = Mat(sigv).clone().reshape(1);if (i > 0)cout << EMD(sig[0], sig[i], CV_DIST_L2) << endl;}
waitKey();
}

结果:

原图像src存放4张图片,0,1是一张亮的手掌图片的上下两部分,2,3亮度变暗,将4张图片转换HSV空间,计算直方图。

   

下面是图0与4张图片的直方图相似度的比较:

EMD结果:

from :https://blog.csdn.net/wangdonggg/article/details/32329879

OpenCV3学习(8.2)直方图相似度比较compareHist函数与EMD距离相关推荐

  1. OpenCV3学习(5.2)——图像修复inpaint函数和图像去噪fastNlMeansDenoising系列函数

    inpaint图像修复 利用inpaint函数进行图像修复.函数原型: CV_EXPORTS_W void inpaint( InputArray src, InputArray inpaintMas ...

  2. Scheduler 学习之二:主调度器_schedule函数

    Summary 1.1 _schedule函数是又被称作为主调度器,负责选择新的task run到当前的cpu当中 1.2 _scheduler将选核的功能交给各调度类完成 1.3 pick_next ...

  3. 《OpenCV3编程入门》学习笔记9 直方图与匹配(三)直方图对比

    9.3 直方图对比 9.3.1 对比直方图:compareHist()函数 1.作用:   比较两幅直方图 2.函数原型: (1)double compareHist(InputArray H1,In ...

  4. OpenCV3学习(12.5) opencv实现粒子滤波目标跟踪

    OpenCV高版本已经把粒子滤波的CV方面的condensation算法给去掉了,以前学的condensation算法不能用C++开发还是只能用C版本,(OpenCV3学习(12.4) 粒子滤波Con ...

  5. 利用OpenCV的compareHist函数作直方图的相似度对比的源程序

    图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 图像处理开发资料.图像处理技术交流请加QQ群,群号 271891601 OpenCV的compareHist函数用来计算 ...

  6. OPENCV-3 学习笔记

    OPENCV-3 学习笔记 imread()读入图,第一个参数,const string&类型的filename,填我们需要载入的图片路径名, 第二个参数,int类型的flags,为载入标识, ...

  7. OpenCV与图像处理学习二——图像直方图与色彩空间

    OpenCV与图像处理学习二--图像直方图与色彩空间 2.4 图像直方图(Image Histogram) 2.4.1 直方图的绘制 2.4.2 三通道直方图绘制 2.5 颜色空间 2.5.1 RGB ...

  8. python opencv 直方图均衡_详解python OpenCV学习笔记之直方图均衡化

    本文介绍了python OpenCV学习笔记之直方图均衡化,分享给大家,具体如下: 官方文档 – https://docs.opencv.org/3.4.0/d5/daf/tutorial_py_hi ...

  9. OpenCV学习-P29-P32 Opencv直方图均衡化、掩膜

    OpenCV学习-P29-P32 Opencv直方图均衡化及掩膜 1 直方图 2 直方图均衡化 3 直方图自适应均衡化 1 直方图 直方图原理:统计图像各个灰度区间的像素数 cv2.calcHist( ...

最新文章

  1. 启动ubuntu什么时候按shift_找回消失的ubuntu启动选项
  2. JAVA接口返回面积_java – 将接口的返回值限制为实现类的范围
  3. 安卓linux环境 查看进程,查看基于Android 系统单个进程内存、CPU使用情况的几种方法...
  4. qt往mysql中添加数据_qt往数据库添加数据
  5. Java安全(一) : java类 | 反射
  6. 华为新系统鸿蒙有哪些手机_如今鸿蒙手机之后,华为启用新系统,谷歌微软措手不及...
  7. 【Java从0到架构师】基本概念 + 环境搭建
  8. 学生信息管理系统[有软件截图]
  9. linux系统uptime解读,Linux中的uptime命令详解
  10. 从零开始学UC(1)之Microsoft Lync Server介绍
  11. 从0开始学习C#第二天
  12. 统计通话次数和时间的软件_手机通话时间统计软件下载
  13. PageHelper.startPage(pageNum,pageSize)分页不起作用
  14. AdxMenu真的不错!我写了个中文的使用说明如下,希望大家用得着
  15. Chrome保存的知乎网页,本地打开后闪频刷新问题处理
  16. PHP:40+开发工具推荐
  17. Gitlab: 常用设置
  18. bootstrap表单验证
  19. 量子密钥分发和BB84协议
  20. 三调成果共享服务平台算不算一个伪命题

热门文章

  1. Android自定义滑动进度条,Android自定义View实现圆形水波进度条
  2. python情感分析预测模型_python snownlp情感分析简易demo
  3. 前端异步编程之Promise和async的用法
  4. 7.16-7.22第二周
  5. 百度地图api公交路线,IE下跳转百度地图后中文变成乱码的解决办法
  6. Java的三大特性:封装、继承、多态
  7. Winrunner与QTP
  8. WCF读取配置动态生成客户端对象
  9. 测试方案和测试计划的区别
  10. Android获取所有Activity