对输入的两张图像计算得到直方图H1与H2,归一化到相同的尺度空间然后可以通过计算H1与H2的之间的距离得到两个直方图的相似程度进而比较图像本身的相似程度。Opencv提供的比较方法有四种:
- Correlation 相关性比较 -(计算结果范围为 -1到1 -1很不相关,1完全一样 )
- Chi-Square 卡方比较 -(计算结果越接近0,两个直方图越相似)
- Intersection 十字交叉性 -(计算为取两个直方图每个相同位置的值的最小值,然后求和,该比较方式不是很好,不建议使用)
- Bhattacharyya distance 巴氏距离 - (比较结果是很准的,计算结果范围为 0-1 ,0表示两个直方图非常相关,1最不相似)
操作流程
首先把图像从RGB色彩空间转换到HSV色彩空间:cvtColor计算图像的直方图,然后归一化到[0~1]之间:calcHist、normalize;
使用上述四种比较方法之一进行比较:compareHist
compareHist(
InputArray h1, // 直方图数据1
InputArray H2,//直方图数据2
int method// 比较方法,上述四种方法之一
)//返回一个double类型的数据。
(1)相关性计算(CV_COMP_CORREL)
(2)卡方计算(CV_COMP_CHISQR)
(3)十字计算(CV_COMP_INTERSECT)
(4)巴氏距离计算(CV_COMP_BHATTACHARYYA )
#include<iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
int main()
{
//申请用于存储图像数据的Mat容器,src表示原始图像,hsv表示转换成hsv格式的图像
Mat srcImage_base,hsvImage_base;
Mat srcImage_test1,hsvImage_test1;
Mat srcImage_test2,hsvImage_test2;
Mat hsvImage_halfDown;
//我用的图,一张基准图,两张相似的测试图
srcImage_base=imread("n01443537_84.JPEG");
srcImage_test1=imread("n01443537_129.JPEG");
srcImage_test2=imread("n01443537_130.JPEG");
imshow("base",srcImage_base);
imshow("test1",srcImage_test1);
imshow("test2",srcImage_test2);
//转换图像格式
cvtColor(srcImage_base,hsvImage_base,COLOR_BGR2HSV);
cvtColor(srcImage_test1,hsvImage_test1,COLOR_BGR2HSV);
cvtColor(srcImage_test2,hsvImage_test2,COLOR_BGR2HSV);
//截取原始图像的半身图用于对比测试
hsvImage_halfDown=hsvImage_base(Range(hsvImage_base.rows/2,hsvImage_base.rows-1),Range(0,hsvImage_base.cols-1));
//h,s对应的bin的数目分别是50,60,即是把h范围是(0,255)的数分成50份分别统计每一份中的像素数。
int h_bins=50;int s_bins=60;
int histSize[]={h_bins,s_bins};
float h_ranges[]={0,256};
float s_ranges[]={0,180};
const float* ranges[]={h_ranges,s_ranges};
//只计算了h,s两个通道,所以channels是0和1
int channels[]={0,1};
//MatND 类型的容器用于存储calcHist计算出的直方图
MatND baseHist;
MatND halfDownHist;
MatND testHist1;
MatND testHist2;
calcHist(&hsvImage_base,1,channels,Mat(),baseHist,2,histSize,ranges,true,false);
normalize(baseHist,baseHist,0,1,NORM_MINMAX,-1,Mat());
calcHist(&hsvImage_halfDown,1,channels,Mat(),halfDownHist,2,histSize,ranges,true,false);
normalize(halfDownHist,halfDownHist,0,1,NORM_MINMAX,-1,Mat());
calcHist(&hsvImage_test1,1,channels,Mat(),testHist1,2,histSize,ranges,true,false);
normalize(testHist1,testHist1,0,1,NORM_MINMAX,-1,Mat());
calcHist(&hsvImage_test2,1,channels,Mat(),testHist2,2,histSize,ranges,true,false);
normalize(testHist2,testHist2,0,1,NORM_MINMAX,-1,Mat());
//分别用上述4种基准计算直方图之间的相似度
//基准图和基准图,基准图和半身基准图,基准图和测试图1,基准图和测试图2
for(int i=0;i<4;i++)
{
int compare_method=i;
double base_base=compareHist(baseHist,baseHist,compare_method);
double base_half=compareHist(baseHist,halfDownHist,compare_method);
double base_test1=compareHist(baseHist,testHist1,compare_method);
double base_test2=compareHist(baseHist,testHist2,compare_method);
printf("method[%d]result: \n\n base-base: %f, base-halfbase: %f, base-test1: %f, base-test2: %f \n----------------------------\n",i,base_base,base_half,base_test1,base_test2);
}
printf("All done");
waitKey(0);
return 0;
}