【從零學習OpenCV 4】直方圖比較
- 2019 年 12 月 13 日
- 筆記
經過幾個月的努力,小白終於完成了市面上第一本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 <opencv2opencv.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程式中直方圖之間的相似度
