**背景:**当前网上常见的直方图使用方法都是默认使用256的范围,而对于使用特定范围的直方图方法讲的不够清楚。仔细研究后总结如下:
1、常见使用方法,直接对灰度图按256个Bin进行计算。
Mat mHistUn;
int channels[1] = { 0 };
{
bool uniform = true;//使用标准方法-也就是每个bin长度为1
int histSize[1] = { 256 };
float range[2] = { 0, 255 };
const float* ranges[] = { range }; // 指定单个bin的取值范围
cv::calcHist(&src, 1, channels, cv::Mat(), mHistUn, 1, histSize, ranges, uniform);
}
2、使用128个Bin进行计算
Mat mHist;
int channels[1] = { 0 };
{
bool uniform = false;
int histSize[1] = { 128 };
float range[129] = { 0 };
for (size_t i = 0, j = 0; i < 129; i++, j += 2)
range[i] = j;
const float* ranges[] = { range }; // 指定单个bin的取值范围
cv::calcHist(&src, 1, channels, cv::Mat(), mHist, 1, histSize, ranges, uniform);
}
在该方法中,channels为0 ,表示单通道。先将uniform 标志位置为false,表示单个bin不再使用默认的距离1。
再构建每个bin的取值范围ranges,这里bin的宽度按2进行配置 ,那么所有的bin就是[0,2],[2,4],[4,6]…[254,255],总共128个bin。
其中需要注意的是,128个bin,但ranges的大小是129.这和opencv对这块的数据处理相关。
3、观察效果
void showCvHist(Mat srchist, int histSize)
{
int hist_w = 511;
int hist_h = 400;
int bin_w = cvRound((double)hist_w / histSize);
Mat histImage(hist_h, hist_w, CV_8UC1, Scalar(0, 0, 0));
Mat hist = srchist.clone();
normalize(hist, hist, 0, hist_h, NORM_MINMAX, -1, Mat());
for (int i = 1; i < histSize; i++)
{
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(hist.at<float>(i - 1))),
Point(bin_w * i, hist_h - cvRound(hist.at<float>(i))),
Scalar(255, 0, 0), 2, 8, 0);
}
imshow("tt", histImage);
cv::waitKey(0);
}
使用该函数对结果进行显示
256方法:
128的方法
可以看到,直方图的趋势基本类似。我们再看下直方图统计的具体数据。可以看到,在128bin方法中,每个数据正好对应256方法中2个数据之和。说明bin宽度为2正好生效。
4、一点统计的疑问:数据的最尾端,[254,255]合并成[127]时,数据存在3000的差异,不知从何引入的。
有知道的朋友可以帮忙看下