【从零学习OpenCV 4】直方图比较
重磅干货,第一时间送达
经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《从零学习OpenCV 4》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。
图像的直方图表示图像像素灰度值的统计特性,因此可以通过比较两张图像的直方图特性比较两张图像的相似程度。从一定程度上来讲,虽然两张图像的直方图分布相似不代表两张图像相似,但是两张图像相似则两张图像的直方图分布一定相似。例如通过插值对图像进行放缩后图像的直方图虽然不会与之前完全一致,但是两者一定具有很高的相似性,因而可以通过比较两张图像的直方图分布相似性对图像进行初步的筛选与识别。
OpenCV 4中提供了用于比较两个图像直方图相似性的compareHist()函数,该函数原型在代码清单4-5中给出。
代码清单4-5 compareHist()函数原型
1. double cv::compareHist(InputArray H1,
2. InputArray H2,
3. int method
4. )
H1:第一张图像直方图。
H2:第二张图像直方图,与H1具有相同的尺寸
method:比较方法标志,可选择参数及含义在表4-2中给出。
该函数前两个参数为需要比较相似性的图像直方图,由于不同尺寸的图像中像素数目可能不相同,为了能够得到两个直方图图像正确的相识性,需要输入同一种方式归一化后的图像直方图,并且要求两个图像直方图具有相同的尺寸。函数第三个参数为比较相似性的方法,选择不同的方法,会得到不同的相识性系数,函数将计算得到的相似性系数以double类型返回。由于不同计算方法的规则不一,因此相似性系数代表的含义也不相同,函数可以选择的计算方式标志在表4-2中给出,接下来介绍每种方法比较相似性的原理。
表4-2 comparaHist()函数比较直方图方法的选择标志参数
标志参数 |
简记 |
作用 |
HISTCMP_CORREL |
0 |
相关法 |
HISTCMP_CHISQR |
1 |
卡方法 |
HISTCMP_INTERSECT |
2 |
直方图相交法 |
HISTCMP_BHATTACHARYYA |
3 |
巴塔恰里雅距离(巴氏距离)法 |
HISTCMP_HELLINGER |
3 |
与HISTCMP_BHATTACHARYYA方法相同 |
HISTCMP_CHISQR_ALT |
4 |
替代卡方法 |
HISTCMP_KL_DIV |
5 |
相对熵法(Kullback-Leibler散度) |
1
01
HISTCMP_CORREL
该方法名为相关法,其计算相似性原理在式(6.1)中给出,在该方法中如果两个图像直方图完全一致,则计算数值为1;如果两个图像直方图完全不相关,则计算值为0。
(6.1)
其中
(6.2)
其中 N是直方图的灰度值个数。
1
02
HISTCMP_CHISQR
该方法名为卡方法,其计算相似性原理在式(6.3)中给出,在该方法中如果两个图像直方图完全一致,则计算数值为0,两个图像的相似性越小,计算数值越大。
(6.3)
1
03
HISTCMP_INTERSECT
该方法名为直方图相交法,其计算相似性原理在式(6.4)中给出,在该方法不会将计算结果归一化,因此即使是两个完全一致的图像直方图,来自于不同图像也会有不同的数值,但是其遵循与同一个图像直方图比较时,数值越大相似性越高,数值越小相似性越低。
(6.4)
1
04
HISTCMP_BHATTACHARYYA
该方法名为巴塔恰里雅距离(巴氏距离)法,其计算相似性原理在式(6.5)中给出,在该方法中如果两个图像直方图完全一致,则计算数值为0,两个图像的相似性越小,计算数值越大。
(6.5)
1
05
HISTCMP_CHISQR_ALT
该方法与巴氏距离法相同,常用于替代巴氏距离法用于纹理比较,计算公式如式(6.6),
(6.6)
1
06
HISTCMP_KL_DIV
该方法名为相对熵法,又名Kullback-Leibler散度法,其计算相似性原理在式(6.7)中给出,在该方法中如果两个图像直方图完全一致,则计算数值为0,两个图像的相似性越小,计算数值越大。
(6.7)
为了验证通过直方图比较两张图像相似性的可行性,在代码清单4-6中提供了三张图像直方图比较的示例程序。在程序中,我们将读取的图像转成灰度图像,之后将图像缩小为原来尺寸的一半,同时读取另外一张图像的灰度图,计算这三张图像的直方图,直方图的结果在图4-4中给出,通过观看直方图的趋势可以发现即使将图像尺寸缩小,两张图像的直方图分布也有一定的相似性。之后利用compareHist()函数对三个直方图进行比较,比较结果也显示图像缩小后的直方图与原来图像的直方图具有很高的相似性,而两张完全不相同的图像的直方图相似性比较小。
代码清单4-6 myCompareHist.cpp比较两个直方图的相似性
1. #include <opencv2\opencv.hpp>
2. #include <iostream>
3.
4. using namespace cv;
5. using namespace std;
6.
7. void drawHist(Mat &hist, int type, string name) //归一化并绘制直方图函数
8. {
9. int hist_w = 512;
10. int hist_h = 400;
11. int width = 2;
12. Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
13. normalize(hist, hist, 1, 0, type, -1, Mat());
14. for (int i = 1; i <= hist.rows; i++)
15. {
16. rectangle(histImage, Point(width*(i - 1), hist_h - 1),
17. Point(width*i - 1, hist_h - cvRound(hist_h*hist.at<float>(i - 1)) - 1),
18. Scalar(255, 255, 255), -1);
19. }
20. imshow(name, histImage);
21. }
22. //主函数
23. int main()
24. {
25. system("color F0"); //更改输出界面颜色
26. Mat img = imread("apple.jpg");
27. if (img.empty())
28. {
29. cout << "请确认图像文件名称是否正确" << endl;
30. return -1;
31. }
32. Mat gray, hist, gray2, hist2, gray3, hist3;
33. cvtColor(img, gray, COLOR_BGR2GRAY);
34. resize(gray, gray2, Size(), 0.5, 0.5);
35. gray3 = imread("lena.png", IMREAD_GRAYSCALE);
36. const int channels[1] = { 0 };
37. float inRanges[2] = { 0,255 };
38. const float* ranges[1] = { inRanges };
39. const int bins[1] = { 256 };
40. calcHist(&gray, 1, channels, Mat(), hist, 1, bins, ranges);
41. calcHist(&gray2, 1, channels, Mat(), hist2, 1, bins, ranges);
42. calcHist(&gray3, 1, channels, Mat(), hist3, 1, bins, ranges);
43. drawHist(hist, NORM_INF, "hist");
44. drawHist(hist2, NORM_INF, "hist2");
45. drawHist(hist3, NORM_INF, "hist3");
46. //原图直方图与原图直方图的相关系数
47. double hist_hist = compareHist(hist, hist, HISTCMP_CORREL);
48. cout << "apple_apple=" << hist_hist << endl;
49. //原图直方图与缩小原图直方图的相关系数
50. double hist_hist2 = compareHist(hist, hist2, HISTCMP_CORREL);
51. cout << "apple_apple256=" << hist_hist2 << endl;
52. //两张不同图像直方图相关系数
53. double hist_hist3 = compareHist(hist, hist3, HISTCMP_CORREL);
54. cout << "apple_lena=" << hist_hist3 << endl;
55. waitKey(0);
56. return 0;
57. }
图4-4 myCompareHist.cp程序运行结果
图4-5 myCompareHist.cp程序中直方图之间的相似度