来源:http://blog.csdn.net/yangtrees/article/details/8785377
原来一直觉得OpenCV里的直方图函数十分简单,今天临时需要用才发现原来OpenCV的calcHist功能如此强大,不仅能计算常见的1D Hist, calcHist理论上支持32维以下的Hist.(32维啊 有木有!)
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轴方向)看的三维柱状图。
- int main( )
- {
- Mat src, hsv;
- src = imread("D:/demo.jpg", 1);
- cvtColor(src, hsv, CV_BGR2HSV);
- // Quantize the hue to 30 levels
- // and the saturation to 32 levels
- int hbins = 30, sbins = 32;
- int histSize[] = {hbins, sbins};
- // hue varies from 0 to 179, see cvtColor
- float hranges[] = { 0, 180 };
- // saturation varies from 0 (black-gray-white) to
- // 255 (pure spectrum color)
- float sranges[] = { 0, 256 };
- const float* ranges[] = { hranges, sranges };
- MatND hist;
- // we compute the histogram from the 0-th and 1-st channels
- int channels[] = {0, 1};
- calcHist( &hsv, 1, channels, Mat(), // do not use mask
- hist, 2, histSize, ranges,
- true, // the histogram is uniform
- false );
- double maxVal=0;
- minMaxLoc(hist, 0, &maxVal, 0, 0);
- int scale = 10;
- Mat histImg = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);
- for( int h = 0; h < hbins; h++ )
- for( int s = 0; s < sbins; s++ )
- {
- float binVal = hist.at<float>(h, s);
- int intensity = cvRound(binVal*255/maxVal);
- rectangle( histImg, Point(h*scale, s*scale),
- Point( (h+1)*scale - 1, (s+1)*scale - 1),
- Scalar::all(intensity),
- CV_FILLED );
- }
- namedWindow( "Source", 1 );
- imshow( "Source", src );
- namedWindow( "H-S Histogram", 1 );
- imshow( "H-S Histogram", histImg );
- waitKey();
- }
最大熵分割
利用Hist实现最大熵模型
信息熵:
最大熵分割:
- #include <iostream>
- #include <opencv/cv.h>
- #include <opencv/highgui.h>
- using namespace std;
- using namespace cv;
- typedef enum {back,object} entropy_state;
- float total;
- //绘制hist;
- 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;
- }
- //计算直方图;
- Mat Hist(const Mat& src)
- {
- Mat hist;
- int bins=256;
- int histSize[] = {bins};
- float range[] = {0,256};
- const float* ranges[] = {range};
- int channels[] = {0};
- calcHist(&src,1,channels,Mat(),hist,1,histSize,ranges,true,false);
- Mat histImg = drawHist(hist,bins,200,Scalar(255,0,0));
- imshow("histRGB",histImg);
- return hist;
- }
- //计算当前熵;
- float calEntropy(const Mat& hist,int threshold)
- {
- float total_back=0,total_object=0;
- float entropy_back=0,entropy_object=0;
- float entropy = 0;
- int i=0;
- const float* hist_p = (float*) hist.ptr<float>(0);
- for (i=0; i<threshold; i++)
- {
- total_back += hist_p[i];
- }
- total_object=total-total_back;
- //背景熵;
- for (i=0; i<threshold; i++)
- {
- // if(hist_p[i]==0)
- // continue;
- float percentage = hist_p[i]/total_back;
- entropy_back += -percentage * logf(percentage); // 能量的定义公式
- }
- //前景熵;
- for (i=threshold; i<hist.cols; i++)
- {
- // if(hist_p[i]==0)
- // {
- // continue;
- // }
- float percentage = hist_p[i]/total_object;
- entropy_object += -percentage * logf(percentage); // 能量的定义公式;
- }
- entropy = entropy_object+entropy_back;
- return entropy;
- }
- void MaxEntropy(Mat img, Mat hist)
- {
- total = sum(hist)[0];
- float MaxEntropyValue = 0.0, MaxEntropyThreshold=0.0;
- float tmp;
- for (int i=0; i<hist.cols; i++)
- {
- tmp = calEntropy(hist,i);
- if(tmp>MaxEntropyValue)
- {
- MaxEntropyValue = tmp;
- MaxEntropyThreshold = i;
- }
- }
- threshold(img,img,MaxEntropyThreshold,255,CV_THRESH_BINARY);
- imshow("thresholdImg",img);
- imwrite("D:/thresholdImg.png",img);
- cout<<MaxEntropyThreshold<<endl;
- cout<<MaxEntropyValue<<endl;
- }
- int main()
- {
- Mat src = imread("D:/test1.jpg",0);
- imshow("SRC",src);
- Mat hist = Hist(src).t();
- MaxEntropy(src, hist);
- waitKey();
- return 1;
- }