1.前言
想了解直方图比较中每种比较的方式,比较的原理,希望大家能有一定的概率论基础,或者统计学基础,如果对这块理论不太了解,还想深入学习算法,建议先学习一下概率论或统计学。
如果你想了解更多有关于计算机视觉、OpenCV、机器学习、深度学习等相关技术的内容,想与更多大佬一起沟通,那就扫描下方二维码加入我们吧!
2.直方图比较概述
对输入的两张图像进行直方图均衡化及直方图计算步骤后,可以对两个图像的直方图进行对比,并通过对比的结果得到一些我们想要的结论。
3.直方图比较应用
(1)图像相似度比较
如果我们有两张图像,并且这两张图像的直方图一样,或者有极高的相似度,那么在一定程度上,我们可以认为这两幅图是一样的,这就是直方图比较的应用之一。
(2)分析图像之间关系
两张图像的直方图反映了该图像像素的分布情况,可以利用图像的直方图,来分析两张图像的关系。
4.直方图比较原理
要比较两个直方图(H1 和 H2),首先必须要选择一个衡量直方图相似度的对比标准,我们设为d(H1,H2),
5.直方图比较方法
(1)相关性比较(Correlation)
相关性比较公式如下:
其中
如果H1 = H2,即两个图的直方图一样,分子等于分母,值为1,所以在不严格的情况下,当值为1时,可以认为两个图是一样的。但是也有可能会出现两个图不一样,但是两个图的直方图是一样的情况。因为直方图计算的是像素点个数的分布情况,但是不会显示像素点的位置,所以有可能会出现两幅图片不一样,但是相同像素的个数完全一样,那他们的直方图也是一样的,不过这种情况,不常有。
相关性比较公式来源于统计学中的相关系数,最早由统计学家卡尔·皮尔逊设计的统计指标,是研究变量之间线性相关程度的量,一般用字母 r 表示。
其中,Cov(X,Y)为X与Y的协方差,Var[X]为X的方差,Var[Y]为Y的方差。如果想学算法,但是又觉得数学很枯燥的话,可以推荐大家一本书,据说很有趣,叫《漫画统计学》。当然,如果是做研究,还是养成不怕枯燥的好习惯。
在那本书上讲到:相关系数适合数值与数值之间的关联性分析。这个公式里面比上面多了一点,是这个公式的取值范围
下面是该公式更加详细的取值范围分析:并且如果两个变量的相关性越强,相关系数就会越接近±1,相关性越弱,相关系数越接近0。
相关系数的值若为正值,称为正相关;相关系数的值若为负值,称为负相关;相关系数的值为0,称为不相关。
(2)Chi-Square(卡方比较)
通过这个公式我们能够发现,卡方比较和相关性比较恰恰相反,相关性比较的值为0,相似度最低,越趋近于1,相似度越低;卡方比较则是,值为0时说明H1= H2,这个时候相似度最高。
卡方比较来源于卡方检验,卡方检验就是统计样本的实际观测值与理论推断值之间的偏离程度,实际观测值与理论推断值之间的偏离程度就决定卡方值的大小,卡方值越大,越不符合;卡方值越小,偏差越小,越趋于符合,若两个值完全相等时,卡方值就为0,表明理论值完全符合。卡方检验的公式如下,其中fi是观测频率,npi是期望频率,X²是卡方值。
(3)Intersection(十字交叉性)
这个就比较简单了,对比H1,H2并求出最小值,最后求和。
(4)Bhattacharyya distance(巴氏距离)
在直方图相似度计算时,巴氏距离获得的效果最好,但计算是最为复杂的。巴氏距离的计算结果,其值完全匹配为1,完全不匹配则为0。
在统计学中,巴氏距离(巴塔恰里雅距离 / Bhattacharyya distance)用于测量两离散概率分布。它常在分类中测量类之间的可分离性。在同一定义域X中,概率分布p和q的巴氏距离定义如下:离散概率分布;连续概率分布。
6.API介绍——compareHist
(1)步骤
a.先用cvtColor()把图像从RGB色彩空间转换到HSV色彩空间;
b.计算图像的直方图,然后归一化到[0~1]之间,用到函数 calcHist() 和 normalize() ;
c.使用上述的四种方法之一进行比较,用到函数compareHist()。
(2)API介绍
函数一共有三个参数,一个输入图像,一个输出图像,一个比较方法。比较方法的取值的情况为上面的四种方法,在OpenCV中,每个都有自己的名字:Correlation ( CV_COMP_CORREL );Chi-Square ( CV_COMP_CHISQR );Intersection ( CV_COMP_INTERSECT );Bhattacharyya 距离( CV_COMP_BHATTACHARYYA )。
7.效果展示
(1)步骤分解
a.加载图像
b.将图像从BGR空间转化为HSV空间
c.计算直方图并归一化处理
d.直方图比较
e.展示图像
(2)源码及效果
-
#define INPUT_TITLE0 "input image src"
-
#define INPUT_TITLE1 "input image srctest1"
-
#define INPUT_TITLE2 "input image srctest2"
-
#define OUTPUT_TITLE "name"
-
#include<iostream>
-
#include<math.h>
-
#include<opencv2\opencv.hpp>
-
using namespace std;
-
using namespace cv;
-
string convertToString(double d);
-
int main() {
-
// 加载图像
-
Mat src, srctest1, srctest2;
-
src = imread("D:/SunWuKong.jpg");
-
srctest1 = imread("D:/SunWuKong1.jpg");
-
srctest2 = imread("D:/GraySunWuKong.jpg");
-
if (!src.data|| !srctest1.data|| !srctest2.data)
-
{
-
cout << "ERROR : could not load image.";
-
return -1;
-
}
-
imshow("【src 原图】", src);
-
imshow("【srctest1 原图】", srctest1);
-
imshow("【srctest2 原图】", srctest2);
-
//从RGB色彩空间转化为HSV色彩空间
-
cvtColor(src, src, CV_BGR2HSV);
-
cvtColor(srctest1, srctest1, CV_BGR2HSV);
-
cvtColor(srctest2, srctest2, CV_BGR2HSV);
-
//定义直方图计算所需要的各种参数
-
int h_bins = 50;
-
int s_bins = 60;
-
int histSize[] = { h_bins,s_bins };
-
float h_ranges[] = { 0,180 };
-
float s_ranges[] = { 0,256 };
-
const float* ranges[] = { h_ranges, s_ranges };
-
int channels[] = { 0,1 };
-
//MatND 是 Mat的别名,方便区分经过直方图计算处理后和输入图像
-
MatND hist_src;
-
MatND hist_srctest1;
-
MatND hist_srctest2;
-
//计算直方图并归一化处理
-
calcHist(&src, 1, channels, Mat(), hist_src, 2, histSize, ranges, true, false);
-
normalize(hist_src, hist_src, 0, 1, NORM_MINMAX, -1, Mat());
-
calcHist(&srctest1, 1, channels, Mat(), hist_srctest1, 2, histSize, ranges, true, false);
-
normalize(hist_srctest1, hist_srctest1, 0, 1, NORM_MINMAX, -1, Mat());
-
calcHist(&srctest2, 1, channels, Mat(), hist_srctest2, 2, histSize, ranges, true, false);
-
normalize(hist_srctest2, hist_srctest2, 0, 1, NORM_MINMAX, -1, Mat());
-
//直方图比较
-
double src_src = compareHist(hist_src, hist_src, CV_COMP_CORREL);
-
double src_srctest1 = compareHist(hist_src, hist_srctest1, CV_COMP_CORREL);
-
double src_srctest2 = compareHist(hist_src, hist_srctest2, CV_COMP_CORREL);
-
double srctest1_srctest2 = compareHist(hist_srctest1, hist_srctest2, CV_COMP_CORREL);
-
cout << "src compare with src correlation value : " << src_src << endl;
-
cout << "src compare with srctest1 correlation value : " << src_srctest1 << endl;
-
cout << "src compare with srctest2 correlation value : " << src_srctest2 << endl;
-
//给每个图像上添加文字,内容为该图片和原始图片的比较结果
-
putText(src, convertToString(src_src), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 255, 255), 2, LINE_AA);
-
putText(srctest1, convertToString(src_srctest1), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(0, 0, 255), 2, LINE_AA);
-
putText(srctest2, convertToString(src_srctest2), Point(50, 50), CV_FONT_HERSHEY_COMPLEX, 1, Scalar(255, 0, 255), 2, LINE_AA);
-
//图像的显示
-
namedWindow(INPUT_TITLE0, CV_WINDOW_AUTOSIZE);
-
namedWindow(INPUT_TITLE1, CV_WINDOW_AUTOSIZE);
-
namedWindow(INPUT_TITLE2, CV_WINDOW_AUTOSIZE);
-
//namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
-
imshow(INPUT_TITLE0, src);
-
imshow(INPUT_TITLE1, srctest1);
-
imshow(INPUT_TITLE2, srctest2);
-
waitKey(0);
-
return 0;
-
}
-
string convertToString(double d) {
-
ostringstream os;
-
if (os<<d)
-
{
-
return os.str();
-
}
-
return "invalid conversion";
-
}
【原图】
【相关性比较】
取值为[0,1],越接近1,直方图相似度越高。
【卡方比较】
取值大于0,越接近0,直方图相似度越高。
下面两种方式图像跟上面相同,只有数值不同,下面将得数分享给大家:
【十字交叉性】
src compare with src correlation value : 53.7653
src compare with srctest1 correlation value : 29.2811
src compare with srctest2 correlation value : 0.56726
【巴氏距离】
src compare with src correlation value : 0
src compare with srctest1 correlation value : 0.562044
src compare with srctest2 correlation value : 0.947251