直方图(opencv)

一、介绍

 图像直方图是用一表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素数。可以借助观察该直方图了解需要如何调整亮度分布的直方图。这种直方图中,横坐标的左侧为纯黑、较暗的区域,而右侧为较亮、纯白的区域。因此,一张较暗图片的图像直方图中的数据多集中于左侧和中间部分,而整体明亮、只有少量阴影的图像则相反。计算机视觉邻域常借助图像直方图来实现图像的二值化。


二、API函数

C++ Void calcHist(
	        const Mat* images,//输入图像指针
	        int images,// 图像数目
	        const int* channels,// 通道数
	        InputArray mask,// 输入mask,可选,不用
	        OutputArray hist,//输出的直方图数据
	        int dims,// 维数
	        const int* histsize,// 直方图级数
	        const float* ranges,// 值域范围
	        bool uniform,// true by default
	        bool accumulate)// false by defaut
函数cvRound,cvFloor,cvCeil 都是用一种舍入的方法将输入浮点数转换成整数:

cvRound():返回跟参数最接近的整数值,即四舍五入;
cvFloor():返回不大于参数的最大整数值,即向下取整;
cvCeil():返回不小于参数的最小整数值,即向上取整;

三、绘制图像直方图

1、使用API函数 calcHist计算图像直方图;

2、进行直方图归一化;

3、绘制各级直方图;

#include<opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
    Mat src, dst;
    src = imread("1.jpg");
    cvtColor(src, src, COLOR_BGR2GRAY);
    int histSize = 16;
    float range[] = { 0, 256 };
    const float* histRange = { range };
    if (src.data && src.channels()==1)
    {
        cout << "您输入的是灰度图像" << endl;
        Mat hist;
        calcHist(&src, 1, 0, Mat(), hist, 1, &histSize, &histRange, true, false);

        //绘制直方图
        int hist_w = 512, hist_h = 400;
        //直方图中各点x轴距离
        int distance = cvRound((double)hist_w / histSize);
        //创建一个图像以显示直方图
        Mat histImage1(hist_h, hist_w, src.type(), Scalar(255, 255, 255));
        //归一化直方图
        normalize(hist, hist, 0, hist_h, NORM_MINMAX, -1,Mat());
        for (int i = 1; i < histSize; i++)
        {
            // hist_h - cvRound(hist.at<float>(i)):hist.at<float>(i)存储的值是从图像
            //左上角为0开始计算的,所以需要使用hist_h减以后才是坐标轴的纵轴值
            line(histImage1, Point(distance * (i-1), hist_h - cvRound(hist.at<float>(i-1))),
                 Point(distance * (i), hist_h - cvRound(hist.at<float>(i))),
                 Scalar(0,0,255),2,8,0);
        }
        namedWindow("calcHist1", WINDOW_AUTOSIZE);
        imshow("calcHist1", histImage1);
    }

    else if (src.data && src.channels() == 3)
    {
        cout << "您输入的是彩色图像" << endl;
        vector<Mat> mv;
        split(src, mv);
        Mat b_hist, g_hist, r_hist;
        calcHist(&mv[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, true, false);
        calcHist(&mv[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, true, false);
        calcHist(&mv[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, true, false);


        // 绘制直方图
        int hist_w = 512,hist_h = 400;
        int distance = cvRound((double)hist_w / histSize);
        Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(255, 255, 255));
        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 < histSize; i++)
        {
            //
            line(histImage, Point(distance * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
                Point(distance * (i), hist_h - cvRound(b_hist.at<float>(i))),
                Scalar(255, 0, 0), 2, 8, 0);
            line(histImage, Point(distance * (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
                Point(distance * (i), hist_h - cvRound(g_hist.at<float>(i))),
                Scalar(0, 255, 0), 2, 8, 0);
            line(histImage, Point(distance * (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
                Point(distance * (i), hist_h - cvRound(r_hist.at<float>(i))),
                Scalar(0, 0, 255), 2, 8, 0);
        }
        namedWindow("calcHist", WINDOW_AUTOSIZE);
        imshow("calcHist", histImage);
    }

    else
    {
        cout << "您未输入图像" << endl;
        return -1;
    }
    
    waitKey(0);
    return 0;
}

四、直方图比较

  1. 为了比较两个直方图( H1 和 H2 ),首先我们必须选择度量( d(H1,H2)来表示两个直方图的匹配度。
  2. OpenCV实现函数cv :: compareHist进行比较。它还提供4种不同的指标来计算匹配:
  • 相关性(CV_COMP_CORREL)(1为最相似)

直方图(opencv)

其中:

直方图(opencv)

N是直方图库的总数。

  • Chi-Square(CV_COMP_CHISQR)(0为最相似)

直方图(opencv)

  • 交点(method= CV_COMP_INTERSECT)(越大越相似)

直方图(opencv)

  • Bhattacharyya distance ( CV_COMP_BHATTACHARYYA )(0为最相似)

直方图(opencv)

 

*Method* Base - Base
*Correlation* 1.000000
*Chi-square* 0.000000
*Intersection* 24.391548
*Bhattacharyya* 0.000000
#include<opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
    Mat src, dst;
    src = imread("12.bmp");
    namedWindow("原图", WINDOW_AUTOSIZE);
    imshow("原图", src);
    int histSize = 16;
    float range[] = { 0, 256 };
    const float* histRange = { range };
    if (src.data && src.channels()==1)
    {
        cout << "您输入的是灰度图像" << endl;
        Mat hist;
        calcHist(&src, 1, 0, Mat(), hist, 1, &histSize, &histRange, true, false);

        //绘制直方图
        int hist_w = 512, hist_h = 400;
        //直方图中各点x轴距离
        int distance = cvRound((double)hist_w / histSize);
        //创建一个图像以显示直方图
        Mat histImage1(hist_h, hist_w, src.type(), Scalar(255, 255, 255));
        //归一化直方图
        normalize(hist, hist, 0, hist_h, NORM_MINMAX, -1,Mat());
        for (int i = 1; i < histSize; i++)
        {
            // hist_h - cvRound(hist.at<float>(i)):hist.at<float>(i)存储的值是从图像
            //左上角为0开始计算的,所以需要使用hist_h减以后才是坐标轴的纵轴值
            line(histImage1, Point(distance * (i-1), hist_h - cvRound(hist.at<float>(i-1))),
                 Point(distance * (i), hist_h - cvRound(hist.at<float>(i))),
                 Scalar(0,0,255),2,8,0);
        }
        namedWindow("calcHist1", WINDOW_AUTOSIZE);
        imshow("calcHist1", histImage1);
    }

    else if (src.data && src.channels() == 3)
    {
        cout << "您输入的是彩色图像" << endl;
        vector<Mat> mv;
        split(src, mv);
        Mat b_hist, g_hist, r_hist;
        calcHist(&mv[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, true, false);
        calcHist(&mv[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, true, false);
        calcHist(&mv[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, true, false);


        // 绘制直方图
        int hist_w = 512,hist_h = 400;
        int distance = cvRound((double)hist_w / histSize);
        Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(255, 255, 255));
        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 < histSize; i++)
        {
            //
            line(histImage, Point(distance * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
                Point(distance * (i), hist_h - cvRound(b_hist.at<float>(i))),
                Scalar(255, 0, 0), 2, 8, 0);
            line(histImage, Point(distance * (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
                Point(distance * (i), hist_h - cvRound(g_hist.at<float>(i))),
                Scalar(0, 255, 0), 2, 8, 0);
            line(histImage, Point(distance * (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
                Point(distance * (i), hist_h - cvRound(r_hist.at<float>(i))),
                Scalar(0, 0, 255), 2, 8, 0);
        }

        //比较直方图相似度
        double similar = compareHist(b_hist, b_hist, CV_COMP_CORREL);
        cout << similar << endl;

        namedWindow("calcHist", WINDOW_AUTOSIZE);
        imshow("calcHist", histImage);
    }

    else
    {
        cout << "您未输入图像" << endl;
        return -1;
    }
    
    waitKey(0);
    return 0;
}

 

直方图(opencv)

 直方图(opencv)

 直方图(opencv)

 

上一篇:opencv 图像旋转和仿射变换


下一篇:Opencv 解决问题 !_src.empty() in function 'cv::cvtColor'