OpenCV 学习笔记之直方图

大纲

1.直方图介绍

2.绘制直方图


1.直方图介绍

去除掉物理的坐标信息,只保留像素的大小。

如下图灰度图像所示:图片中某一个像素大小出现的频率,与其位置无关。

OpenCV 学习笔记之直方图

定义:图像直方图是图像像素值的统计学特征、计算代价较小,具有图像平移、旋转

缩放不变性等众多优点,广泛地应用于图像处理的各个领域,特别是灰度图像的阈值

分割、基于颜色的图像检索以及图像分类、反向投影跟踪。

分类:

   (1) 灰度直方图

   (2) 颜色直方图

OpenCV中相关API

calcHist(&bgr_plane[0],1,0,Mat(),b_hist,1,bins,ranges);


2.绘制图像三通道直方图

效果图

OpenCV 学习笔记之直方图

source code

void QuickDemo::histogram_demo(Mat& image)     //图像直方图
{
    //三通道分离
    std::vector<Mat>bgr_plane;
    split(image, bgr_plane);  //分离通道到容器 bgr_plane
    //定义参数变量
    const int channels[1] = { 0 };   //通道的个数
    const int bins[1] = { 256 };     //直方图分割成多少个区间,就是bin的个数
    float hranges[2] = { 0,255 };   //像素取值范围在0-255,直方图分割成多少个区间
    const float* ranges[1] = { hranges };
    Mat b_hist;
    Mat g_hist;
    Mat r_hist;
    //calculate Blue,green,red chaneels histogram
    //直方图的结果存放到b_hist,g_hist,r_hist中,是一个256x1的列数组
    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;
    //划分x轴的数据,通过之前定义的区间个数
    int bin_w = cvRound((double)hist_w / bins[0]);        //OpenCV 四舍五入的函数,把它分割成256分
    Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);  //创建与指定的图片的尺寸相同的画布

    //归一化直方图数据(限定数据范围在0-histImage.rows 之间)
    normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());   
    normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    //MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化
    //Mask :Mat()
    //-1 表达式数据类型和通道相同
    //NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围。
    
    //绘制直方图曲线
    //在x轴方向上沿着从左到右绘制直线。
    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);
}

分解divide

(1)通道分离(channels divide)

    //三通道分离
    std::vector<Mat>bgr_plane;
    split(image, bgr_plane);  //分离通道到容器 bgr_plane

(2)定义参数变量(parameter varies)

    const int bins[1] = { 256 };     //直方图分割成多少个区间,就是bin的个数
    float hranges[2] = { 0,255 };   //像素取值范围在0-255,直方图分割成多少个区间
    const float* ranges[1] = { hranges };

(3)定义存放直方图的结果变量

    Mat b_hist;
    Mat g_hist;
    Mat r_hist;

(4)Calculates a histogram of a set of arrays.得到的是一个一维数组

    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);

OpenCV 学习笔记之直方图

(5)设计绘制直方图的大小,并设置x轴方向上的最小值,创建一个直方图大小的画布矩阵histImage

    //自己设计--->直方图(尺寸)
    int hist_w = 512;
    int hist_h = 400;
    //划分x轴的数据,通过之前定义的区间个数
    int bin_w = cvRound((double)hist_w / bins[0]);        //OpenCV 四舍五入的函数,把它分割成256分
    Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);  //创建与指定的图片的尺寸相同的画布

(6)归一化处理,(限定数据范围:0 - histImage.rows 之间)

//MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化
//Mask :Mat()
//-1 表达式数据类型和通道相同
//NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围。

OpenCV 学习笔记之直方图

    //MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化
    //Mask :Mat()
    //-1 表达式数据类型和通道相同
    //NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围。

(7)绘制直方图曲线

//在x轴方向上沿着从左到右绘制直线。

    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);
    }

代码解释:

(8)输出图片

    //显示直方图
    namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
    imshow("Histogram Demo", histImage);

 

DATE:2021-12-23  

上一篇:opencv-Hough霍夫变换


下一篇:opencv-getRotationMatrix2D旋转函数