OpenCV学习13 计算直方图

// 直方图简介

// 图像是由不同数值(颜色)的像素构成的,像素值在整幅图像中的分布情况是该图像的一个重要属性。

// 如何计算直方图、如何用直方图修改图像的外观、还可以用直方图来标识图像的内容、检测图像中特定的物体或纹理

// 计算图像直方图

// 可调用cv::calcHist 函数,这是一个通用的直方图计算函数,可处理包含任何值类型和范围的多通道图像。

代码

#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

// 直方图简介
// 图像是由不同数值(颜色)的像素构成的,像素值在整幅图像中的分布情况是该图像的一个重要属性。
// 如何计算直方图、如何用直方图修改图像的外观、还可以用直方图来标识图像的内容、检测图像中特定的物体或纹理


// 计算图像直方图
// 可调用cv::calcHist 函数,这是一个通用的直方图计算函数,可处理包含任何值类型和范围的多通道图像。

// 这里创建一个类,专门用于处理单通道灰度图像
// 输入必须是灰度图

using namespace cv;
class Histogram1D{
private:
    int histSize[1];           // 直方图中箱子的数量
    float hranges[2];          // 值范围
    const float* ranges[1];    // 值范围的指针
    int channels[1];           // 要检查的通道数量

public:
    Histogram1D(){

        // 准备一维直方图的默认参数
        histSize[0] = 256;  // 256个箱子

        hranges[0] = 0.0;   // 从0开始 (含)
        hranges[1] = 256.0; // 到256(不含)
        ranges[0] = hranges;

        channels[0] = 0;    // 先关注通道0
    }

    Mat getHistomgram(const Mat &image){
        Mat hist;

        calcHist(&image, 1, // 仅为一幅图像的直方图
                 channels,  // 使用的通道
                 Mat(),    // 不使用掩码
                 hist,     // 作为结果的直方图, cols=1, rows=图像像素种类
                 1,        // 这是一维的直方图
                 histSize, // 箱子数量
                 ranges);  // 像素值的范围
        return hist;
    }

    // 创建一个表示直方图的图像(静态方法)
    static Mat getImageOfHistogram(const Mat &hist, int zoom){

        // 取得箱子值的最大值和最小值
        double maxVal = 0;
        double minVal = 0;
        minMaxLoc(hist, &minVal, &maxVal, 0, 0);

        // 取得直方图的大小
        int histSize = hist.rows;


        // 用于显示直方图的方形图像
        Mat histImg(histSize*zoom, histSize*zoom,
                    CV_8U, Scalar(255));

        // 图像高度
        int hpt = static_cast<int>(0.9 * histSize);

        int peak=0;
        int loc=0;
        // 在白色方形图像上为每个箱子画垂直线
        for (int h = 0; h<histSize; h++){

            // 每个箱子的值
            float binVal = hist.at<float>(h);

            if(binVal>0){
                int intensity = static_cast<int>(binVal/maxVal * hpt);

                // 寻找 峰值
                if (h>0 and intensity > peak){
                    peak = intensity;
                    loc = h;
                }


                // 画垂直线
                line(histImg, Point(h*zoom, histSize*zoom),
                     Point(h*zoom, (histSize - intensity)*zoom),
                     Scalar(0), zoom);

            }
        }

        // 找出峰值所在位置
        std::cout << "peak bin loc: " << loc <<
                             " bin value:" << peak;

        return histImg;
    }

    //
    Mat getHistogramImage(const Mat &image, int zoom=1){

        // 得到直方图(一维数组)
        Mat hist = getHistomgram(image);

        return getImageOfHistogram(hist, zoom);
    }

};



int main()
{
    Mat dog = imread("/home/jason/work/01-img/dog.png", IMREAD_GRAYSCALE);


    std::cout <<  dog.rows << "*"<<  dog.cols << std::endl;
    Rect rect(90, 50,450,340);
    dog = dog(rect);

    imshow("dog",dog);

    Histogram1D h;

//    Mat histo = h.getHistomgram(dog);

    imshow("Histogram", h.getHistogramImage(dog));

    // 直方图的峰值所在箱子位置是 115
    // 直方图尖峰的两边的像素,分别对应了图像的背景和前景
    // 可以在两部分的汇合处进行阈值化
    //用灰度值115来进行阈值化。
    Mat threshold;
    cv::threshold(dog, threshold, 115, 255, cv::THRESH_BINARY);
    imshow("threshold", threshold);


    waitKey(0);


    return 0;
}

结果

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值