Opencv(C++)学习之cv::calcHist 任意bin数量进行直方图计算

**背景:**当前网上常见的直方图使用方法都是默认使用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方法:
Opencv(C++)学习之cv::calcHist 任意bin数量进行直方图计算_第1张图片
128的方法
Opencv(C++)学习之cv::calcHist 任意bin数量进行直方图计算_第2张图片

可以看到,直方图的趋势基本类似。我们再看下直方图统计的具体数据。可以看到,在128bin方法中,每个数据正好对应256方法中2个数据之和。说明bin宽度为2正好生效。
Opencv(C++)学习之cv::calcHist 任意bin数量进行直方图计算_第3张图片
4、一点统计的疑问:数据的最尾端,[254,255]合并成[127]时,数据存在3000的差异,不知从何引入的。
有知道的朋友可以帮忙看下

Opencv(C++)学习之cv::calcHist 任意bin数量进行直方图计算_第4张图片

你可能感兴趣的:(opencv,c++,图像处理)