1.23【OpenCV圖像處理】直方圖均衡化和計算

均衡化equalizeHist()、分通道split()、計算calcHist()、繪製直方圖line()

1.23.1 直方圖

直方圖(histogram):直方圖是對數據的集合統計,並將統計結果分布於一系列預定義的bins中。

圖像直方圖:是指對整個圖像在灰度範圍內的像素值(0~255)統計出現頻率次數,反映了圖像灰度的分布情況,是圖像的統計學特徵。圖像直方圖的另一個定義是圖像中像素強度分布的圖形表達方式,它統計了每一個強度值所具有的像素個數。pixel(像素個數) intensity(強度灰度)

直方圖可以幫助尋找二值化閾值。

上述直方圖概念是基於圖像像素灰度值,統計數據可能是任何能有效描述圖像的特徵,如灰度值直方圖、RGB值直方圖、梯度直方圖、方向直方圖等。

直方圖的屬性:

- dims:表示維度(特徵空間),對灰度圖像來說只有一個通道值dims=1

- bins:表示在維度中子區域大小劃分(級數),bins=256則劃分為256個級別;上例中bins=16則劃分為16個子區域

- range:表示值域範圍,上例中灰度值範圍為range=[0~255];如HSI空間中H=[0-360],S [0-180]。

直方圖也可以是3維的,x軸和y軸分別代表一個特徵,z軸是掉入 組合中的樣本數目。 同樣的方法適用於更高維的情形 (當然會變得很複雜)。

1.23.2 直方圖均衡化

直方圖均衡化: 是通過拉伸像素強度分布範圍來增強圖像對比度的一種方法。

作用:提高對比度。

如圖像素主要集中在中間的一些強度值上,直方圖均衡化要做的就是拉伸這個灰度值範圍,綠圈圈出了少數像素分布其上的強度值。

均衡化實現方法:指的是把一個分布 (給定的直方圖) 映射(remap)到另一個分布 (一個更寬更統一的強度值分布), 所以強度值分布會在整個範圍內展開。

1)要想實現均衡化的效果, 映射函數應該是一個累積分布函數 (cdf) 。

對於直方圖 , 它的 累積分布 是:

2)要使用其作為映射函數, 我們必須對最大值為255 (或者用圖像的最大強度值) 的累積分布 進行歸一化. 同上例, 累積分布函數為:

3)最後, 我們使用一個簡單的映射過程來獲得均衡化後像素的強度值:

1.23.3 API說明

(1)直方圖均衡化(提高對比度)

equalizeHist(

InputArray src,//輸入圖像,必須是8-bit的單通道圖像

OutputArray dst// 輸出結果

)

/*直方圖均衡化*/ncvtColor(src, src_gray, CV_BGR2GRAY); //轉灰度nequalizeHist(src_gray, src_equalize); //直方圖均衡化,輸入8位單通道圖像n

(2)分通道(把多通道圖像分為多個單通道圖像)

split(

const Mat &src, //輸入多通道圖像

Mat* mvbegin)// 輸出的單通道圖像數組

/*分通道顯示*/nvector<Mat> bgr_planes; //定義一個數組nsplit(src, bgr_planes); //分通道顯示,輸入多通道圖像,輸出的單通道圖像數組nimshow("b_split image", bgr_planes[0]); //顯示b通道圖像nimshow("g_split image", bgr_planes[1]);nimshow("r_split image", bgr_planes[2]);n

(3)計算直方圖

calcHist(

const Mat* images,//輸入圖像指針

int images,// 圖像數目

const int* channels,// 通道數

InputArray mask,// 輸入掩膜mask,可選, 如果未定義,則不使用掩碼Mat()

OutputArray hist,//輸出的直方圖數據矩陣

int dims,// 維數 (1維頻次)

const int* histsize,// 直方圖級數bins

const float* ranges,// 值域範圍常量指針(0-255)

bool uniform,// 標誌指示是否直方圖是否一致,true by default

bool accumulate// 積累標誌,默認為非false by defaut

)

/*直方圖計算*/nint histSize = 255; //bins等級nfloat range[] = { 0, 255 }; //range值域範圍nconst float *histRanges = { range }; //值域常量指針nMat b_hist, g_hist, r_hist; //b_hist.at<float>(i)就是第i級b通道直方圖的值ncalcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRanges, true, false);//b通道直方圖計算,輸入圖像指針,圖像數,第幾通道數,輸入掩膜,輸出直方圖,維度,等級,值域ncalcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);//g通道直方圖計算,輸入圖像指針,圖像數,通道數,輸入掩膜,輸出直方圖,維度,等級,值域ncalcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);//r通道直方圖計算,輸入圖像指針,圖像數,通道數,輸入掩膜,輸出直方圖,維度,等級,值域n

(4)繪製直方圖 - line()線法

/*繪製直方圖 render histogram chart*/nfor (int i = 1; i < histSize; i++) {n line(histImage, Point((i - 1)*bin_v, hist_h - cvRound(b_hist.at<float>(i - 1))),Point((i)*bin_v, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, LINE_AA); //b_hist.at<float>(i)就是第i級b通道直方圖的值n}nimshow("output image", histImage);n


完整程序:

/*1.23 直方圖均衡化和計算*/n#include <opencv2/opencv.hpp>n#include <iostream> n#include <math.h>nusing namespace cv;nusing namespace std;nnMat src, dst, src_equalize, src_gray;nnint main(int argc, char** argv) {n src = imread("E:/OpenCV/testimage/test7.jpg");nif (src.empty()) {n printf("could not load image...n");nreturn -1;n }nchar input_title[] = "input image";n namedWindow(input_title, CV_WINDOW_AUTOSIZE);n imshow(input_title, src);nn/*直方圖均衡化*/n cvtColor(src, src_gray, CV_BGR2GRAY); //轉灰度nequalizeHist(src_gray, src_equalize); //直方圖均衡化,輸入8位單通道圖像n imshow("gray image", src_gray);n imshow("Equalized image", src_equalize);nn/*分通道顯示*/nvector<Mat> bgr_planes; //定義一個數組nsplit(src, bgr_planes); //分通道顯示,輸入多通道圖像,輸出的單通道圖像數組n imshow("b_split image", bgr_planes[0]); //顯示b通道圖像n imshow("g_split image", bgr_planes[1]);n imshow("r_split image", bgr_planes[2]);nn/*直方圖計算*/nint histSize = 255; //bins等級nfloat range[] = { 0, 255 }; //range值域範圍nconst float *histRanges = { range }; //值域常量指針nMat b_hist, g_hist, r_hist;ncalcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRanges, true, false);//b通道直方圖計算,輸入圖像指針,圖像數,通道數,輸入掩膜,輸出直方圖,維度,等級,值域n calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);//g通道直方圖計算,輸入圖像指針,圖像數,通道數,輸入掩膜,輸出直方圖,維度,等級,值域n calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);//r通道直方圖計算,輸入圖像指針,圖像數,通道數,輸入掩膜,輸出直方圖,維度,等級,值域nn/*創建直方圖畫布、歸一化*/nint hist_h = 400; //直方圖高度nint hist_v = 512; //直方圖寬度nint bin_v = hist_v / histSize; //bin的寬度=直方圖寬度/等級nMat histImage(hist_v, hist_h, CV_8UC3, Scalar(0, 0, 0)); //定義8位3通道黑色圖像nnormalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat()); //歸一化,將直方圖的頻次歸一化到0-400內,低值,高值(高於此高值的取此高值)n normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat()); //歸一化,將直方圖的頻次歸一化到0-400內,低值,高值n normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat()); //歸一化,將直方圖的頻次歸一化到0-400內,低值,高值nn /*繪製直方圖 render histogram chart*/nfor (int i = 1; i < histSize; i++) {n line(histImage, Point((i - 1)*bin_v, hist_h - cvRound(b_hist.at<float>(i - 1))),nPoint((i)*bin_v, hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, LINE_AA); //b_hist.at<float>(i)就是第i級b通道直方圖的值n line(histImage, Point((i - 1)*bin_v, hist_h - cvRound(g_hist.at<float>(i - 1))),nPoint((i)*bin_v, hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, LINE_AA);n line(histImage, Point((i - 1)*bin_v, hist_h - cvRound(r_hist.at<float>(i - 1))),nPoint((i)*bin_v, hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, LINE_AA);n }n imshow("output image", histImage);nn waitKey(0);nreturn 0;n}n

運行結果:


推薦閱讀:

遙感圖像亮度地形糾正
1.29【OpenCV圖像處理】輪廓邊界框
[171118] PyQt5 滑動條控制 Canny 邊緣閾值並繪製 OpenCV 圖像
數字圖像處理專業如何快速入門?謝謝。

TAG:OpenCV | 图像处理 |