学习OpenCV——直方图&最大熵分割

原来一直觉得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的用户体验比较好。


 
 
  1. Mat drawHist(Mat hist,int bins,int height,Scalar rgb)
  2. {
  3. double maxVal= 0;
  4. minMaxLoc(hist, 0,&maxVal, 0, 0);
  5. int scale= 1;
  6. Mat histImg = Mat::zeros(height, bins, CV_8UC3);
  7. float *binVal = hist.ptr< float>( 0);
  8. for ( int i= 0; i<bins; i++)
  9. {
  10. int intensity = cvRound(binVal[i]*height/maxVal);
  11. rectangle(histImg,Point(i*scale, 0),
  12. Point((i+ 1)*scale,(intensity)),rgb,CV_FILLED);
  13. }
  14. flip(histImg,histImg, 0);
  15. return histImg;
  16. }
  17. void darwHistRGB(const Mat& src)
  18. {
  19. Mat histB,histG,histR;
  20. int bins= 256;
  21. int histSize[] = {bins};
  22. float range[] = { 0, 256};
  23. const float* ranges[] = {range};
  24. int channelsB[] = { 0};
  25. int channelsG[] = { 1};
  26. int channelsR[] = { 2};
  27. calcHist(&src, 1,channelsB,Mat(),histB, 1,histSize,ranges, true, false);
  28. calcHist(&src, 1,channelsG,Mat(),histG, 1,histSize,ranges, true, false);
  29. calcHist(&src, 1,channelsR,Mat(),histR, 1,histSize,ranges, true, false);
  30. Mat histBImg = drawHist(histB,bins, 200,Scalar( 255, 0, 0));
  31. Mat histGImg = drawHist(histG,bins, 200,Scalar( 0, 255, 0));
  32. Mat histRImg = drawHist(histR,bins, 200,Scalar( 0, 0, 255));
  33. //在一个窗口中显示多幅图像
  34. Mat display(200,bins*3,CV_8UC3);
  35. Mat displayROI = display(Rect( 0, 0,bins, 200));
  36. resize(histBImg,displayROI,displayROI.size());
  37. displayROI = display(Rect(bins, 0,bins, 200));
  38. resize(histGImg,displayROI,displayROI.size());
  39. displayROI = display(Rect(bins* 2, 0,bins, 200));
  40. resize(histRImg,displayROI,displayROI.size());
  41. imshow( "histRGB",display);
  42. waitKey();
  43. }
  44. int main()
  45. {
  46. Mat src = imread( "D:/demo.jpg", 1);
  47. darwHistRGB(src);
  48. return 1;
  49. }



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


灰度值的大小代表了直方图的高度。可以看做是一个从上向下(-Z轴方向)看的三维柱状图。


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


最大熵分割

利用Hist实现最大熵模型

信息熵:

最大熵分割:


 


 
 
  1. #include <iostream>
  2. #include <opencv/cv.h>
  3. #include <opencv/highgui.h>
  4. using namespace std;
  5. using namespace cv;
  6. typedef enum {back,object} entropy_state;
  7. float total;
  8. //绘制hist;
  9. Mat drawHist(Mat hist,int bins,int height,Scalar rgb)
  10. {
  11. double maxVal= 0;
  12. minMaxLoc(hist, 0,&maxVal, 0, 0);
  13. int scale= 1;
  14. Mat histImg = Mat::zeros(height, bins, CV_8UC3);
  15. float *binVal = hist.ptr< float>( 0);
  16. for ( int i= 0; i<bins; i++)
  17. {
  18. int intensity = cvRound(binVal[i]*height/maxVal);
  19. rectangle(histImg,Point(i*scale, 0),
  20. Point((i+ 1)*scale,(intensity)),rgb,CV_FILLED);
  21. }
  22. flip(histImg,histImg, 0);
  23. return histImg;
  24. }
  25. //计算直方图;
  26. Mat Hist(const Mat& src)
  27. {
  28. Mat hist;
  29. int bins= 256;
  30. int histSize[] = {bins};
  31. float range[] = { 0, 256};
  32. const float* ranges[] = {range};
  33. int channels[] = { 0};
  34. calcHist(&src, 1,channels,Mat(),hist, 1,histSize,ranges, true, false);
  35. Mat histImg = drawHist(hist,bins, 200,Scalar( 255, 0, 0));
  36. imshow( "histRGB",histImg);
  37. return hist;
  38. }
  39. //计算当前熵;
  40. float calEntropy(const Mat& hist,int threshold)
  41. {
  42. float total_back= 0,total_object= 0;
  43. float entropy_back= 0,entropy_object= 0;
  44. float entropy = 0;
  45. int i= 0;
  46. const float* hist_p = ( float*) hist.ptr< float>( 0);
  47. for (i= 0; i<threshold; i++)
  48. {
  49. total_back += hist_p[i];
  50. }
  51. total_object=total-total_back;
  52. //背景熵;
  53. for (i= 0; i<threshold; i++)
  54. {
  55. // if(hist_p[i]==0)
  56. // continue;
  57. float percentage = hist_p[i]/total_back;
  58. entropy_back += -percentage * logf(percentage); // 能量的定义公式
  59. }
  60. //前景熵;
  61. for (i=threshold; i<hist.cols; i++)
  62. {
  63. // if(hist_p[i]==0)
  64. // {
  65. // continue;
  66. // }
  67. float percentage = hist_p[i]/total_object;
  68. entropy_object += -percentage * logf(percentage); // 能量的定义公式;
  69. }
  70. entropy = entropy_object+entropy_back;
  71. return entropy;
  72. }
  73. void MaxEntropy(Mat img, Mat hist)
  74. {
  75. total = sum(hist)[ 0];
  76. float MaxEntropyValue = 0.0, MaxEntropyThreshold= 0.0;
  77. float tmp;
  78. for ( int i= 0; i<hist.cols; i++)
  79. {
  80. tmp = calEntropy(hist,i);
  81. if(tmp>MaxEntropyValue)
  82. {
  83. MaxEntropyValue = tmp;
  84. MaxEntropyThreshold = i;
  85. }
  86. }
  87. threshold(img,img,MaxEntropyThreshold, 255,CV_THRESH_BINARY);
  88. imshow( "thresholdImg",img);
  89. imwrite( "D:/thresholdImg.png",img);
  90. cout<<MaxEntropyThreshold<< endl;
  91. cout<<MaxEntropyValue<< endl;
  92. }
  93. int main()
  94. {
  95. Mat src = imread( "D:/test1.jpg", 0);
  96. imshow( "SRC",src);
  97. Mat hist = Hist(src).t();
  98. MaxEntropy(src, hist);
  99. waitKey();
  100. return 1;
  101. }





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值