重磅干貨,第一時間送達
經過幾個月的努力,小白終于完成了市面上第一本OpenCV 4入門書籍《從零學習OpenCV 4》。為了更讓小伙伴更早的了解最新版的OpenCV 4,小白與出版社溝通,提前在公眾號上連載部分內容,請持續(xù)關注小白。
圖像直方圖是圖像處理中非常重要的像素統(tǒng)計結果,圖像直方圖不再表征任何的圖像紋理信息,而是對圖像像素的統(tǒng)計。由于同一物體無論是旋轉還是平移在圖像中都具有相同的灰度值,因此直方圖具有平移不變性、放縮不變性等優(yōu)點,因此可以用來查看圖像整體的變化形式,例如圖像是否過暗、圖像像素灰度值主要集中在哪些范圍等,在特定的條件下也可以利用圖像直方圖進行圖像的識別,例如對數(shù)字的識別。
圖像直方圖簡單來說就是統(tǒng)計圖像中每個灰度值的個數(shù),之后將圖像灰度值作為橫軸,以灰度值個數(shù)或者灰度值所占比率作為縱軸繪制的統(tǒng)計圖。通過直方圖可以看出圖像中哪些灰度值數(shù)目較多,哪些較少,可以通過一定的方法將灰度值較為集中的區(qū)域映射到較為稀疏的區(qū)域,從而使得圖像在像素灰度值上分布更加符合期望狀態(tài)。通常情況下,像素灰度值代表亮暗程度,因此通過圖像直方圖可以分析圖像亮暗對比度,并調整圖像的亮暗程度。
在OpenCV 4中只提供了圖像直方圖的統(tǒng)計函數(shù)calcHist(),該函數(shù)能夠統(tǒng)計出圖像中每個灰度值的個數(shù),但是對于直方圖的繪制需要使用者自行繪制。我們首先學習統(tǒng)計灰度值數(shù)目的函數(shù)calcHist()的使用,該函數(shù)的原型在代碼清單4-1中給出。
代碼清單4-1 calcHist()函數(shù)原型
1. void cv::calcHist(const Mat * images,
2. int nimages,
3. const int * channels,
4. InputArray mask,
5. OutputArray hist,
6. int dims,
7. const int * histSize,
8. const float ** ranges,
9. bool uniform = true,
10. bool accumulate = false
11. )
images:待統(tǒng)計直方圖的圖像數(shù)組,數(shù)組中所有的圖像應具有相同的尺寸和數(shù)據(jù)類型,并且數(shù)據(jù)類型只能是CV_8U、CV_16U和CV_32F三種中的一種,但是不同圖像的通道數(shù)可以不同。
nimages:輸入的圖像數(shù)量
channels:需要統(tǒng)計的通道索引數(shù)組,第一個圖像的通道索引從0到images[0].channels()-1,第二個圖像通道索引從images[0].channels()到images[0].channels()+ images[1].channels()-1,以此類推。
mask:可選的操作掩碼,如果是空矩陣則表示圖像中所有位置的像素都計入直方圖中,如果矩陣不為空,則必須與輸入圖像尺寸相同且數(shù)據(jù)類型為CV_8U。
hist:輸出的統(tǒng)計直方圖結果,是一個dims維度的數(shù)組。
dims:需要計算直方圖的維度,必須是整數(shù),并且不能大于CV_MAX_DIMS,在OpenCV 4.0和OpenCV 4.1版本中為32。
histSize:存放每個維度直方圖的數(shù)組的尺寸。
ranges:每個圖像通道中灰度值的取值范圍。
uniform:直方圖是否均勻的標志符,默認狀態(tài)下為均勻(true)。
accumulate:是否累積統(tǒng)計直方圖的標志,如果累積(true),則統(tǒng)計新圖像的直方圖時之前圖像的統(tǒng)計結果不會被清除,該同能主要用于統(tǒng)計多個圖像整體的直方圖。
該函數(shù)用于統(tǒng)計圖像中每個灰度值像素的個數(shù),例如統(tǒng)計一張CV_8UC1的圖像,需要統(tǒng)計灰度值從0到255中每一個灰度值在圖像中的像素個數(shù),如果某個灰度值在圖像中沒有,那么該灰度值的統(tǒng)計結果就是0。由于該函數(shù)具有較多的參數(shù),并且每個參數(shù)都較為復雜,因此作者建議讀者在使用該函數(shù)時只統(tǒng)計單通道圖像的灰度值分布,對于多通道圖像可以將圖像每個通道分離后再進行統(tǒng)計。
為了使讀者更加了解函數(shù)的使用方法,我們在代碼清單4-2中提供了繪制灰度圖像的圖像直方圖的示例程序。在程序中我們首先使用calcHist()函數(shù)統(tǒng)計灰度圖像里面每個灰度值的數(shù)目,之后通過不斷繪制矩形的方式實現(xiàn)直方圖的繪制。由于圖像中部分灰度值像素數(shù)目較多,因此我們將每個灰度值數(shù)目縮小了20倍后再進行繪制,繪制的直方圖在圖4-1中所示。在程序中我們使用了OpenCV 4提供的四舍五入的取整函數(shù)cvRound(),該函數(shù)輸入?yún)?shù)為double類型的變量,返回值為對該變量四舍五入后的int型數(shù)值。
代碼清單4-2 myCalHist.cpp繪制圖像直方圖
1. #include <opencv2\opencv.hpp>
2. #include <iostream>
3.
4. using namespace cv;
5. using namespace std;
6.
7. int main()
8. {
9. Mat img = imread("apple.jpg");
10. if (img.empty())
11. {
12. cout << "請確認圖像文件名稱是否正確" << endl;
13. return -1;
14. }
15. Mat gray;
16. cvtColor(img, gray, COLOR_BGR2GRAY);
17. //設置提取直方圖的相關變量
18. Mat hist; //用于存放直方圖計算結果
19. const int channels[1] = { 0 }; //通道索引
20. float inRanges[2] = { 0,255 };
21. const float* ranges[1] = { inRanges }; //像素灰度值范圍
22. const int bins[1] = { 256 }; //直方圖的維度,其實就是像素灰度值的最大值
23. calcHist(&img, 1, channels, Mat(), hist, 1, bins, ranges); //計算圖像直方圖
24. //準備繪制直方圖
25. int hist_w = 512;
26. int hist_h = 400;
27. int width = 2;
28. Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
29. for (int i = 1; i <= hist.rows; i++)
30. {
31. rectangle(histImage, Point(width*(i - 1), hist_h - 1),
32. Point(width*i - 1, hist_h - cvRound(hist.at<float>(i - 1) / 20)),
33. Scalar(255, 255, 255), -1);
34. }
35. namedWindow("histImage", WINDOW_AUTOSIZE);
36. imshow("histImage", histImage);
37. imshow("gray", gray);
38. waitKey(0);
39. return 0;
40. }
圖4-1 myCalHist.cpp程序運行結果
聯(lián)系客服