引言

在图像处理中,对于直方图这个概念,肯定不会陌生。但是其原理真的可以信手拈来吗?

本文篇幅有点长,在此列个目录,大家可以跳着看:

  • 分析图像直方图的概念,以及opencv函数calcHist()对于RGB图像的直方图的绘制
  • 在其基础上自已定义函数实现对灰度图像直方图的简单绘制
  • 直方图均衡化
  • 直方图的反向投影

图像直方图分析以及opencv函数实现

(一)直方图的介绍

直方图到底可以干什么呢?我觉得最明显的作用就是有利于很直观的对图像进行分析了,直方图就像我们常用的统计图,直方图可以用来描述各种不同的事情,如物体的色彩分布、物体边缘梯度模板,以及表示目标位置的概率分布。

 例如:我们统计了一个有11个学生的班级的身高和体重情况,身高为160cm的有5人,170cm的有4人,180cm的有2人。然后看体重,体重160斤的有3人,170斤的有5人,180斤的有3人。

用直方图统计就是这样:

 在opencv中,对于图像的直方图来说。对应上图数据,也有三个参数:

  1. dims:需要统计的特征的数目。如上面例子里有身高和体重两个特征。
  2. bins:每个特征空间子区段数目。如身高有160,170,180所以子区段数目为3。
  3. range:每个特征空间的取值范围。例如:身高的取值范围就是[160,180]

直方图的意义:

        1. 直方图是图像中像素强度分布的图形表达方式。 
        2. 直方图统计了每一个强度值所具有的像素个数。

任一幅图像,都能唯一地算出一幅与它对应的直方图。但不同的图像,可能有相同的直方图。即图像与直方图之间是多对一的映射关系。

(二)直方图API

直方图是对数据的统计,并把统计值显示到事先设定好的bin(如上表,设置160,170,180)中,bin中的数值是从数据中计算出的特征的统计量。总之,直方图获取的是数据分布的统计图,通常直方图的维数要低于原始数据。

在OpenCV中封装了直方图的计算函数calcHist,为了更为通用,该函数的参数有些复杂,其声明如下:

 calcHist(
        const Mat*   images,    //输入图像的数组(CV_8U,CV_16U,CV_32F)
        int          nimages,   //输入数组个数
        const int*   channels,  //通道索引,可以传一个数组 {0, 1} 表示计算第0通道与第1通道的直方图,此数组长度要与histsize,ranges 数组长度一致
        InputArray   mask;      //Mat(),  //不使用腌膜
        OutputArray  hist,      //输出的目标直方图,一个二维数组
        int       dims,      //需要计算的直方图的维数  例如:灰度,R,G,B,H,S,V等数据
        congst int*  histSize,  // 在每一维上直方图的个数。(简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。)
        const float**    ranges, //每一维数组的取值范围数组
        bool          uniform=true,   
        bool          accumulate = false
          );

opencv实现:

Mat src = imread("D:/opencv练习图片/src1.jpg");
    imshow("原图片", src);
    // //步骤一:分通道显示
    vector<Mat> bgr_plane;
    split(src, bgr_plane);
    //split//把多通道图像分为多个单通道图像 (const Mat &src, //输入图像 Mat* mvbegin //输出的通道图像数组)

    //步骤二:计算直方图
       // 定义参数变量
    const int channels[1] = { 0 };
    const int bins[1] = { 256 };
    float hranges[2] = { 0,255 };
    const float* ranges[1] = { hranges };
    Mat b_hist;
    Mat g_hist;
    Mat r_hist;
       // 计算Blue, Green, Red通道的直方图
    calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
    calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
    calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);
       // 显示直方图
    int hist_w = 512;
    int hist_h = 400;
    int bin_w = cvRound((double)hist_w / bins[0]);//直方图的等级
    Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
       // 归一化直方图数据(范围在0-400)
    normalize(b_hist, b_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
    normalize(g_hist, g_hist, 0, hist_h, NORM_MINMAX, -1, Mat());
    normalize(r_hist, r_hist, 0, hist_h, NORM_MINMAX, -1, Mat());

    //步骤三:绘制直方图并显示
    for (int i = 1; i < bins[0]; i++) {
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
    }
      // 显示直方图
    namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
    imshow("Histogram Demo", histImage);


 自定义函数实现灰度图像直方图绘制

版权声明:本文为xyf327原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/xyf327/p/14799533.html