(转)opencv--直方图&最大熵分割

来源:互联网 发布:专业java培训 编辑:程序博客网 时间:2024/06/07 07:05

来源: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轴方向)看的三维柱状图。

[cpp] view plaincopyprint?
  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实现最大熵模型

信息熵:

最大熵分割:


 

[cpp] view plaincopyprint?
  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. }  
原创粉丝点击