【OpenCV】直方图应用:直方图均衡化,直方图匹配,对比直方图
本文鏈接:https://blog.csdn.net/xiaowei_cqu/article/details/7606607
? ? ? ? ? ? ? ??
? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
前面介紹了 數字圖像灰度直方圖,現在來嘗試直方圖的應用。
直方圖均衡化
直方圖均衡化(Histogram Equalization)是直方圖最典型的應用,是圖像點運算的一種。對于一幅輸入圖像,通過運算產生一幅輸出圖像,點運算是指輸出圖像的每個像素點的灰度值由輸入像素點決定,即:
直方圖均衡化是通過灰度變換將一幅圖像轉換為另一幅具有均衡直方圖,即在每個灰度級上都具有相同的象素點數過程。從分布圖上的理解就是希望原始圖像中y軸的值在新的分布中盡可能的展開。變換過程是利用累積分布函數對原始分布進行映射,生成新的均勻拉伸的分布。因此對應每個點的操作是尋找原始分布中y值在均勻分布中的位置,如下圖是理想的單純高斯分布映射的示意圖:
(圖片來源:《Learnning OpenCV》 p189)
OpenCV中的cvEqualizeHist
OpenCV中有灰度直方圖均衡化的函數cvEqualizeHist,接口很明朗:
void cvEqualizeHist( const CvArr* src, CvArr* dst );
注意此函數只能處理單通道的灰色圖像,對于彩色圖像,我們可以把每個信道分別均衡化,再Merge為彩色圖像。
實踐:圖像直方圖均衡化
int main(){?? ?IplImage * image= cvLoadImage("baboon.jpg");?? ?//顯示原圖及直方圖?? ?myShowHist("Source",image);?? ??? ?IplImage* eqlimage=cvCreateImage(cvGetSize(image),image->depth,3);?? ?//分別均衡化每個信道?? ?IplImage* redImage=cvCreateImage(cvGetSize(image),image->depth,1);?? ?IplImage* greenImage=cvCreateImage(cvGetSize(image),image->depth,1);?? ?IplImage* blueImage=cvCreateImage(cvGetSize(image),image->depth,1);?? ?cvSplit(image,blueImage,greenImage,redImage,NULL); ?? ?cvEqualizeHist(redImage,redImage);?? ?cvEqualizeHist(greenImage,greenImage); ?? ?cvEqualizeHist(blueImage,blueImage); ?? ?//均衡化后的圖像?? ?cvMerge(blueImage,greenImage,redImage,NULL,eqlimage);?? ?myShowHist("Equalized",eqlimage);}原始圖像及灰度直方圖如下:
均衡化后的直方圖:
直方圖匹配
直方圖匹配又叫直方圖規定化(Histogram Normalization/Matching)是指對一副圖像進行變換,使其直方圖與另一幅圖像的直方圖或特定函數形式的直方圖進行匹配。應用場景如不同光照條件下的兩幅圖像,我們可以在比較兩幅圖像前先進行匹配變化。
參考shlkl99上傳的直方圖匹配代碼,將圖像規定化為高斯分布函數。
//將圖像與特定函數分布histv[]匹配void myHistMatch(IplImage *img,double histv[]){?? ?int bins = 256;?? ?int sizes[] = {bins};?? ?CvHistogram *hist = cvCreateHist(1,sizes,CV_HIST_ARRAY);?? ?cvCalcHist(&img,hist);?? ?cvNormalizeHist(hist,1);?? ?double val_1 = 0.0;?? ?double val_2 = 0.0;?? ?uchar T[256] = {0};?? ?double S[256] = {0};?? ?double G[256] = {0};?? ?for (int index = 0; index<256; ++index)?? ?{?? ??? ?val_1 += cvQueryHistValue_1D(hist,index);?? ??? ?val_2 += histv[index];?? ??? ?G[index] = val_2;?? ??? ?S[index] = val_1;?? ?} ?? ?double min_val = 0.0;?? ?int PG = 0;?? ?for ( int i = 0; i<256; ++i)?? ?{?? ??? ?min_val = 1.0;?? ??? ?for(int j = 0;j<256; ++j)?? ??? ?{?? ??? ??? ?if( (G[j] - S[i]) < min_val && (G[j] - S[i]) >= 0)?? ??? ??? ?{?? ??? ??? ??? ?min_val = (G[j] - S[i]);?? ??? ??? ??? ?PG = j;?? ??? ??? ?} ?? ??? ?}?? ??? ?T[i] = (uchar)PG;?? ?} ?? ?uchar *p = NULL;?? ?for (int x = 0; x<img->height;++x)?? ?{ ?? ??? ?p = (uchar*)(img->imageData + img->widthStep*x);?? ??? ?for (int y = 0; y<img->width;++y)?? ??? ?{?? ??? ??? ?p[y] = T[p[y]];?? ??? ?}?? ?}} // 生成高斯分布void GenerateGaussModel(double model[]){?? ?double m1,m2,sigma1,sigma2,A1,A2,K;?? ?m1 = 0.15;?? ?m2 = 0.75;?? ?sigma1 = 0.05;?? ?sigma2 = 0.05;?? ?A1 = 1;?? ?A2 = 0.07;?? ?K = 0.002; ?? ?double c1 = A1*(1.0/(sqrt(2*CV_PI))*sigma1);?? ?double k1 = 2*sigma1*sigma1;?? ?double c2 = A2*(1.0/(sqrt(2*CV_PI))*sigma2);?? ?double k2 = 2*sigma2*sigma2;?? ?double p = 0.0,val= 0.0,z = 0.0;?? ?for (int zt = 0;zt < 256;++zt)?? ?{?? ??? ?val = K + c1*exp(-(z-m1)*(z-m1)/k1) + c2*exp(-(z-m2)*(z-m2)/k2);?? ??? ?model[zt] = val;?? ??? ?p = p +val;?? ??? ?z = z + 1.0/256;?? ?}?? ?for (int i = 0;i<256; ++i)?? ?{?? ??? ?model[i] = model[i]/p;?? ?}}?
實踐:直方圖匹配
對示例圖片每個信道分別進行匹配處理
對比直方圖
OpenCV中提供了cvCompareHist函數用以對比兩個直方圖的相似度:
double cvCompareHist( ? ? ? ? ? ? ?const CvHistogram* hist1, //直方圖1 ? ? ? ? ? ? const CvHistogram* hist2, //直方圖2 ? ? ? ? ? ? int method//對比方法);method有CV_COMP_CORREL, CV_COMP_CHISQR,CV_COMP_INTERSECT,CV_COMP_BHATTACHARYYA四種方法,對應公式如下:
實踐:對比不同光照條件的兩幅圖像直方圖
直方圖的對比主要用以判斷兩幅圖像的匹配度,我們試驗以下兩幅圖像直方圖對比的結果:
? ? ??
int main(){?? ?IplImage * image= cvLoadImage("myhand1.jpg");?? ?IplImage * image2= cvLoadImage("myhand2.jpg");?? ?int hist_size=256;?? ?float range[] = {0,255};?? ?float* ranges[]={range};?? ??? ?IplImage* gray_plane = cvCreateImage(cvGetSize(image),8,1);?? ?cvCvtColor(image,gray_plane,CV_BGR2GRAY);?? ?CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);?? ?cvCalcHist(&gray_plane,gray_hist,0,0); ??? ?IplImage* gray_plane2 = cvCreateImage(cvGetSize(image2),8,1);?? ?cvCvtColor(image2,gray_plane2,CV_BGR2GRAY);?? ?CvHistogram* gray_hist2 = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);?? ?cvCalcHist(&gray_plane2,gray_hist2,0,0); ?? ?//相關:CV_COMP_CORREL ? ??? ?//卡方:CV_COMP_CHISQR?? ?//直方圖相交:CV_COMP_INTERSECT?? ?//Bhattacharyya距離:CV_COMP_BHATTACHARYYA?? ?double ?com=cvCompareHist(gray_hist,gray_hist2,CV_COMP_BHATTACHARYYA); ?? ?cout<<com<<endl;}
輸出結果為:0.396814
cvCompareHist的結果為【0,1】的浮點數,越小表示兩幅圖匹配度越高,0.0時兩幅圖精確匹配。(可以試驗兩幅完全一樣的圖即為0.0)。
針對上面兩幅圖,我們分別先進行直方圖匹配變化:
?
之后使用cvCompareHist()對比兩幅圖像的直方圖,輸出結果為0.267421
表明兩幅圖的匹配度變高了。
注意method用不同的方法對比結果是不同的。
應用
通過對比我們可以設置EMD的閾值來判定皮膚或手的ROI。《Learnning OpenCV》后面有相應的練習題:收集手的膚色直方圖,對比室內,室外手的直方圖的EMD距離,利用這些測量值設置一個距離閾值。
a.利用該閾值檢測第三幅圖(如室外陰影),看能能否很好的檢測膚色直方圖。
b.隨機選擇不是膚色的背景塊直方圖,觀測EMD變化,試驗與真實膚色對比時能否很好的拒絕背景。
如上也即是直方圖對比可以應用的場景。
轉載請注明出處:http://blog.csdn.net/xiaowei_cqu/article/details/7606607
實驗代碼下載:http://download.csdn.net/detail/xiaowei_cqu/4332914
————————————————
版權聲明:本文為CSDN博主「xiaowei_cqu」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/xiaowei_cqu/article/details/7606607
總結
以上是生活随笔為你收集整理的【OpenCV】直方图应用:直方图均衡化,直方图匹配,对比直方图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Node.js -- Stream 使用
- 下一篇: WindowsService服务程序开发