直方圖是一個影像像素的統計表,橫軸為影像中所有可能的像素值,假使為8位元圖,範圍即為0到255,縱軸為此橫軸強度的像素個數,直方圖可以被歸一化,歸一化後所有項和為一,在這種情況下,縱軸值表示此強度的像素佔影像的比例。
直方圖是影像的一個重要特性,我們可以從這看出強度分布狀況,像是否太暗或過曝,或者分布太過集中,進而評估影像的品質。在影像檢索時,直方圖可以當成是一段獨特的紋理,或者是獨特的物體,透過直方圖的比較協助我們搜尋物體。
OpenCV計算直方圖
OpenCV的calcHist()函式可得到一個影像的直方圖,為了使用上的彈性,參數有點複雜。
void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false)
- images:輸入圖,可以一個或多個圖,深度必須為CV_8U或CV_32F,可為任意通道數,但是每張圖的尺寸和深度必須相同。
- nimages:有幾張輸入圖。
- channels:直方圖通道清單。
- mask:可有可無的遮罩。
- hist:輸出的直方圖
- dims:直方圖維度,必須為正數且不能超過CV_MAX_DIMS(目前為32),假設為灰階圖的直方圖,每個像素只有強度資料,此時維度為1。
- histSize:直方圖橫軸(也稱bin)數目。
- ranges:直方圖的強度範圍,以8位元無負號的影像,就是[0,255]。
- uniform:各維度取值是否一致。
- accumulate:如果設定為true的話,在呼叫calcHist()這函式的時候,hist的內容不會被清掉,方便我們做多次的直方圖計算的累加。
繪製直方圖
OpenCV本身沒有提供繪製直方圖的函式,因此我們這邊自行撰寫drawHistImg()函式,輸入從得到的直方圖,輸出直方圖視覺化影像,流程如下:
- 找出輸入直方圖的最大值。
- 將最高點設定成輸出影像高度的0.9倍(也就是256*0.9)。
- 算出直方圖內各個像素強度,所對應的高度。
- 逐行畫出各強度的高度。
以下程式碼我們讀入一張圖,用calcHist()計算出直方圖,再用drawHistImg()將直方圖畫出: