(轉)opencv--直方圖&最大熵分割

來源:http://blog.csdn.net/yangtrees/article/details/8785377

原來一直覺得OpenCV裏的直方圖函數十分簡單,今天臨時需要用才發現原來OpenCV的calcHist功能如此強大,不僅能計算常見的1D Hist, calcHist理論上支持32維以下的Hist.(32維啊 有木有!)

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 )

image: 輸入圖像序列

nimages: 源圖像數量

channels: 用於計算hist的通道List

mask:不解釋

hist:生成的hist

dims:hist的維數(必須大於0,目前版本支持不大於CV_MAX_DIMS=32

histSzie:每一維的size(即bins)

ranges: 直方圖每一維的bins的邊界的序列

uniform:是否對齊

accumlate:如果set爲true,則直方圖在使用之前不clear,用於在一個hist內保存多個圖像集的直方圖,或者及時更新hist。



實現代碼:

在此實現兩個直方圖繪製函數,分別繪製1D,2D直方圖。


BGR三通道1D直方圖:


附帶的在程序裏實現了一個窗口內顯示多幅圖像,也可以使用Mat1.put_back(Mat2),但是push_back是向y軸方向push mat ,醬紫顯示的就是細長細長窗口,所以還是使用ROI的用戶體驗比較好。

Mat drawHist(Mat hist,int bins,int height,Scalar rgb)  
{  
    double maxVal=0;  
    minMaxLoc(hist,0,&maxVal,0,0);  
    int scale=1;  
    Mat histImg = Mat::zeros(height, bins, CV_8UC3);  
    float *binVal = hist.ptr<float>(0);  
    for (int i=0; i<bins; i++)  
    {  
        int intensity = cvRound(binVal[i]*height/maxVal);  
        rectangle(histImg,Point(i*scale,0),  
            Point((i+1)*scale,(intensity)),rgb,CV_FILLED);  
    }  
    flip(histImg,histImg,0);  
    return histImg;  
}  
  
void darwHistRGB(const Mat& src)  
{  
    Mat histB,histG,histR;  
  
    int bins=256;  
    int histSize[] = {bins};  
    float range[] = {0,256};  
    const float* ranges[] = {range};  
    int channelsB[] = {0};  
        int channelsG[] = {1};  
        int channelsR[] = {2};  
    calcHist(&src,1,channelsB,Mat(),histB,1,histSize,ranges,true,false);  
    calcHist(&src,1,channelsG,Mat(),histG,1,histSize,ranges,true,false);  
    calcHist(&src,1,channelsR,Mat(),histR,1,histSize,ranges,true,false);  
  
    Mat histBImg = drawHist(histB,bins,200,Scalar(255,0,0));  
    Mat histGImg = drawHist(histG,bins,200,Scalar(0,255,0));  
    Mat histRImg = drawHist(histR,bins,200,Scalar(0,0,255));  
      
    //在一個窗口中顯示多幅圖像  
    Mat display(200,bins*3,CV_8UC3);  
    Mat displayROI = display(Rect(0,0,bins,200));  
    resize(histBImg,displayROI,displayROI.size());  
    displayROI = display(Rect(bins,0,bins,200));  
    resize(histGImg,displayROI,displayROI.size());  
    displayROI = display(Rect(bins*2,0,bins,200));  
    resize(histRImg,displayROI,displayROI.size());  
  
    imshow("histRGB",display);  
    waitKey();  
}  
  
int main()  
{  
   	Mat src = imread("e:/test/5.jpg",1);
	/*或者可以做Mat hsv=Mat::zeros( src.rows, src.cols, CV_8UC3 );;

	cvtColor(src,hsv,CV_RGB2HSV,0);
	imshow("hsv",hsv);*/
    darwHistRGB(src);  
    return 1;  
}  




HSV的H-S通道2D直方圖:


灰度值的大小代表了直方圖的高度。可以看做是一個從上向下(-Z軸方向)看的三維柱狀圖。

  1. int main(  )  
  2. {  
  3.     Mat src, hsv;  
  4.     src = imread("D:/demo.jpg", 1);  
  5.   
  6.   
  7.     cvtColor(src, hsv, CV_BGR2HSV);  
  8.   
  9.     // Quantize the hue to 30 levels  
  10.     // and the saturation to 32 levels  
  11.     int hbins = 30, sbins = 32;  
  12.     int histSize[] = {hbins, sbins};  
  13.     // hue varies from 0 to 179, see cvtColor  
  14.     float hranges[] = { 0, 180 };  
  15.     // saturation varies from 0 (black-gray-white) to  
  16.     // 255 (pure spectrum color)  
  17.     float sranges[] = { 0, 256 };  
  18.     const float* ranges[] = { hranges, sranges };  
  19.     MatND hist;  
  20.     // we compute the histogram from the 0-th and 1-st channels  
  21.     int channels[] = {0, 1};  
  22.   
  23.     calcHist( &hsv, 1, channels, Mat(), // do not use mask  
  24.         hist, 2, histSize, ranges,  
  25.         true// the histogram is uniform  
  26.         false );  
  27.     double maxVal=0;  
  28.     minMaxLoc(hist, 0, &maxVal, 0, 0);  
  29.   
  30.     int scale = 10;  
  31.     Mat histImg = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);  
  32.   
  33.     forint h = 0; h < hbins; h++ )  
  34.         forint s = 0; s < sbins; s++ )  
  35.         {  
  36.             float binVal = hist.at<float>(h, s);  
  37.             int intensity = cvRound(binVal*255/maxVal);  
  38.             rectangle( histImg, Point(h*scale, s*scale),  
  39.                 Point( (h+1)*scale - 1, (s+1)*scale - 1),  
  40.                 Scalar::all(intensity),  
  41.                 CV_FILLED );  
  42.         }  
  43.   
  44.         namedWindow( "Source", 1 );  
  45.         imshow( "Source", src );  
  46.   
  47.         namedWindow( "H-S Histogram", 1 );  
  48.         imshow( "H-S Histogram", histImg );  
  49.         waitKey();  
  50. }  


最大熵分割

利用Hist實現最大熵模型

信息熵:

最大熵分割:


 

  1. #include <iostream>  
  2. #include <opencv/cv.h>  
  3. #include <opencv/highgui.h>  
  4.   
  5.   
  6. using namespace std;  
  7. using namespace cv;  
  8.   
  9. typedef enum {back,object} entropy_state;  
  10. float total;  
  11.   
  12. //繪製hist;  
  13. Mat drawHist(Mat hist,int bins,int height,Scalar rgb)  
  14. {  
  15.     double maxVal=0;  
  16.     minMaxLoc(hist,0,&maxVal,0,0);  
  17.     int scale=1;  
  18.     Mat histImg = Mat::zeros(height, bins, CV_8UC3);  
  19.     float *binVal = hist.ptr<float>(0);  
  20.     for (int i=0; i<bins; i++)  
  21.     {  
  22.         int intensity = cvRound(binVal[i]*height/maxVal);  
  23.         rectangle(histImg,Point(i*scale,0),  
  24.             Point((i+1)*scale,(intensity)),rgb,CV_FILLED);  
  25.     }  
  26.     flip(histImg,histImg,0);  
  27.     return histImg;  
  28. }  
  29. //計算直方圖;  
  30. Mat Hist(const Mat& src)  
  31. {  
  32.     Mat hist;  
  33.     int bins=256;  
  34.     int histSize[] = {bins};  
  35.     float range[] = {0,256};  
  36.     const float* ranges[] = {range};  
  37.     int channels[] = {0};  
  38.     calcHist(&src,1,channels,Mat(),hist,1,histSize,ranges,true,false);  
  39.     Mat histImg = drawHist(hist,bins,200,Scalar(255,0,0));  
  40.     imshow("histRGB",histImg);  
  41.     return hist;  
  42. }  
  43. //計算當前熵;  
  44. float calEntropy(const Mat& hist,int threshold)  
  45. {  
  46.     float total_back=0,total_object=0;  
  47.     float entropy_back=0,entropy_object=0;  
  48.     float entropy = 0;  
  49.     int i=0;  
  50.   
  51.     const float* hist_p = (float*) hist.ptr<float>(0);  
  52.     for (i=0; i<threshold; i++)  
  53.     {  
  54.         total_back += hist_p[i];  
  55.     }  
  56.     total_object=total-total_back;  
  57.   
  58.     //背景熵;  
  59.     for (i=0; i<threshold; i++)  
  60.     {  
  61. //      if(hist_p[i]==0)  
  62. //          continue;  
  63.         float percentage = hist_p[i]/total_back;  
  64.         entropy_back += -percentage * logf(percentage); // 能量的定義公式  
  65.     }  
  66.     //前景熵;  
  67.     for (i=threshold; i<hist.cols; i++)  
  68.     {  
  69. //      if(hist_p[i]==0)  
  70. //      {  
  71. //          continue;  
  72. //      }  
  73.         float percentage = hist_p[i]/total_object;  
  74.         entropy_object += -percentage * logf(percentage); // 能量的定義公式;  
  75.     }  
  76.   
  77.     entropy = entropy_object+entropy_back;  
  78.     return entropy;  
  79. }  
  80.   
  81. void MaxEntropy(Mat img, Mat hist)  
  82. {  
  83.     total = sum(hist)[0];  
  84.     float MaxEntropyValue = 0.0, MaxEntropyThreshold=0.0;  
  85.     float tmp;  
  86.     for (int i=0; i<hist.cols; i++)  
  87.     {  
  88.         tmp = calEntropy(hist,i);  
  89.         if(tmp>MaxEntropyValue)  
  90.         {  
  91.             MaxEntropyValue = tmp;  
  92.             MaxEntropyThreshold = i;  
  93.         }  
  94.     }  
  95.     threshold(img,img,MaxEntropyThreshold,255,CV_THRESH_BINARY);  
  96.     imshow("thresholdImg",img);  
  97.     imwrite("D:/thresholdImg.png",img);  
  98.     cout<<MaxEntropyThreshold<<endl;  
  99.     cout<<MaxEntropyValue<<endl;  
  100. }  
  101.   
  102. int main()  
  103. {  
  104.     Mat src = imread("D:/test1.jpg",0);  
  105.     imshow("SRC",src);  
  106.     Mat hist = Hist(src).t();  
  107.     MaxEntropy(src, hist);  
  108.     waitKey();  
  109.     return 1;  
  110. }  
發佈了19 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章