【opencv学习之十四】Opencv灰度直方图和均值化直方图

什么是直方图,以下摘自opencv国内论坛:

什么是直方图?
直方图是对数据的集合 统计 ,并将统计结果分布于一系列预定义的 bins 中。
这里的 数据 不仅仅指的是灰度值 (如上一篇您所看到的), 统计数据可能是任何能有效描述图像的特征。
先看一个例子吧。 假设有一个矩阵包含一张图像的信息 (灰度值 0-255):
【opencv学习之十四】Opencv灰度直方图和均值化直方图_第1张图片

如果我们按照某种方式去 统计 这些数字,会发生什么情况呢? 既然已知数字的 范围 包含 256 个值, 我们可以将这个范围分割成子区域(称作 bins), 如:

然后再统计掉入每一个 bin_{i} 的像素数目。采用这一方法来统计上面的数字矩阵,我们可以得到下图( x轴表示 bin, y轴表示各个bin中的像素个数)。

【opencv学习之十四】Opencv灰度直方图和均值化直方图_第2张图片
以上只是一个说明直方图如何工作以及它的用处的简单示例。直方图可以统计的不仅仅是颜色灰度, 它可以统计任何图像特征 (如 梯度, 方向等等)。
让我们再来搞清楚直方图的一些具体细节:
dims: 需要统计的特征的数目, 在上例中, dims = 1 因为我们仅仅统计了灰度值(灰度图像)。
bins: 每个特征空间 子区段 的数目,在上例中, bins = 16
range: 每个特征空间的取值范围,在上例中, range = [0,255]
怎样去统计两个特征呢? 在这种情况下, 直方图就是3维的了,x轴和y轴分别代表一个特征, z轴是掉入 (bin_{x}, bin_{y}) 组合中的样本数目。 同样的方法适用于更高维的情形 (当然会变得很复杂)。

不罗嗦了吧 下面直接上实验代码,还是之前的环境,在Qt mainwindow 程序里修改main函数,直方图函数应用,代码里有注解:

#include "mainwindow.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace cv;
using namespace std;

Mat globalMat;//全局变量
void RGBHistogram(Mat intMat);//rgb的直方图统计
void GrayHistogram(Mat intMat);//显示灰度直方图
void GrayHistogram2(Mat intMat);//显示灰度直方图
void EqualizeHistogram(Mat intMat);//均值化图及灰度直方图
void EqualizeHistogram2(Mat intMat);//均值化图及灰度直方图

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);//QT mainwindow程序自带不用管
    globalMat = imread("D:/source.png", 1 );//j加载图片,0为灰度,1为彩色
    RGBHistogram(globalMat);//rgb 直方图
    GrayHistogram(globalMat);//显示灰度直方图
    GrayHistogram2(globalMat);//显示灰度直方图
    EqualizeHistogram(globalMat);//均值化图及灰度直方图
    EqualizeHistogram2(globalMat);//均值化图及灰度直方图
    MainWindow w;//QT mainwindow程序自带不用管
    w.show();//QT mainwindow程序自带不用管
    return a.exec();//QT mainwindow程序自带不用管
}

//RGBHistogram黑底直方图
void RGBHistogram(Mat intMat)
{
    /// 分割成3个单通道图像 ( R, G 和 B )
    vector rgb_planes;
    split(intMat, rgb_planes );
    /// 设定bin数目
    int histSize = 255;
    /// 设定取值范围 ( R,G,B) )
    float range[] = { 0, 255 } ;
    const float* histRange = { range };
    bool uniform = true;
    bool accumulate = false;
    Mat r_hist, g_hist, b_hist;
    /// 计算直方图:
    calcHist( &rgb_planes[0], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );
    calcHist( &rgb_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
    calcHist( &rgb_planes[2], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
    // 创建直方图画布
    int hist_w = 400; int hist_h = 400;
    int bin_w = cvRound( (double) hist_w/histSize );
    Mat histImage( hist_w, hist_h, CV_8UC3, Scalar( 0,0,0) );
    /// 将直方图归一化到范围 [ 0, histImage.rows ]
    normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
    normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
    normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
    /// 在直方图画布上画出直方图
    for( int i = 1; i < histSize; i++ )
    {
        line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at(i-1)) ) ,
              Point( bin_w*(i), hist_h - cvRound(r_hist.at(i)) ),
              Scalar( 0, 0, 255), 2, 8, 0  );
        line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at(i-1)) ) ,
              Point( bin_w*(i), hist_h - cvRound(g_hist.at(i)) ),
              Scalar( 0, 255, 0), 2, 8, 0  );
        line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at(i-1)) ) ,
              Point( bin_w*(i), hist_h - cvRound(b_hist.at(i)) ),
              Scalar( 255, 0, 0), 2, 8, 0  );
    }

    /// 显示直方图
    namedWindow("RGB Histogram", CV_WINDOW_AUTOSIZE );//创建窗口
    imshow("RGB Histogram", histImage );//窗口中显示直方图
    namedWindow("original image", CV_WINDOW_AUTOSIZE );//创建窗口
    imshow("original image", globalMat );//窗口中显示原图
    waitKey(0);
}

//黑底直方图
void GrayHistogram(Mat intMat)
{
#define cvQueryHistValue_1D( hist, idx0 )\
    ((float)cvGetReal1D( (hist)->bins, (idx0)))
//    宏 cvQueryHistValue_*D 返回 1D, 2D, 3D 或 N-D 直方图的指定直方块
//    的值。对稀疏直方图,如果方块在直方图中不存在,函数返回 0, 而且不创
//    建新的直方块。

    IplImage *src= &IplImage(intMat);
    IplImage* gray_plane= cvCreateImage(cvGetSize(src),8,1);//根据原图创建一个空白图
    cvCvtColor(src,gray_plane,CV_RGB2GRAY);//转成灰度图

    int hist_size = 256;    //直方图尺寸
    int hist_height = 256;//直方图高度
    float range[] = {0,255};  //灰度级的范围
    float* ranges[]={range};//创建一个数组

    //创建一维直方图,统计图像在[0 255]像素的均匀分布
    CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);     
    // ************************cvCreateHist()函数解释 *******************************
    //        函数 cvCreateHist 创建一个指定尺寸的直方图,并且返回创建的直方图的
    //        指针。 如果数组的 ranges 是 0, 则直方块的范围必须由函数
    //        cvSetHistBinRanges 或者cvCalcHist 和 cvCalcBackProject稍后指定。
    //        虽然 cvCalcHist 和 cvCalcBackProject可以处理 8-比特图像而无需设
    //        置任何直方块的范围,但它们都被假设等分0..255 之间的空间。
    ///
    //            CvHistogram* cvCreateHist( int dims,           // 直方图维数的数目
    //                                      int* sizes,          //直方图维数尺寸的数组
    //                                      int type,            // 直方图的表示格式
    //                                      float** ranges=NULL, //图中方块范围的数组
    //                                      int uniform=1 );     //归一化标识
    //         type 
    //         直方图的表示格式: CV_HIST_ARRAY 意味着直方图数据表示为多维密集数组 CvMatND;
    //         CV_HIST_TREE 意味着直方图数据表示为多维稀疏数组  CvSparseMat;
    //        ranges
    //         图中方块范围的数组. 它的内容取决于参数 uniform 的值。这个范围的用处是确定何时计算直方
    //         图或决定反向映射(backprojected ),每个方块对应于输入图像的哪个/哪组值。
    //        uniform
    //        归一化标识。 如果不为 0,则ranges[i](0<=ibins, (idx0)))

    IplImage *src= &IplImage(intMat);//加载图片转换成IplImage
    IplImage* gray_plane = cvCreateImage(cvGetSize(src),8,1);
    cvCvtColor(src,gray_plane,CV_RGB2GRAY);//彩色转灰度

    int hist_size = 256;    //直方图尺寸
    int hist_height = 256; //直方图尺寸
    float range[] = {0,255};  //灰度级的范围
    float* ranges[]={range};//创建一个数组

    //创建一维直方图,统计图像在[0 255]像素的均匀分布
    CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
    cvCalcHist(&gray_plane,gray_hist,0,0);//计算灰度图像的一维直方图

    IplImage *pHistImage = cvCreateImage(cvSize(hist_size * 2, hist_height), IPL_DEPTH_8U, 1);
    cvRectangle(pHistImage, cvPoint(0, 0), cvPoint(pHistImage->width, pHistImage->height), CV_RGB(255, 255, 255), CV_FILLED);
    float fMaxHistValue = 0;//统计直方图中的最大直方块
    cvGetMinMaxHistValue(gray_hist, NULL, &fMaxHistValue, NULL, NULL);//统计直方图中的最大直方块
    //分别将每个直方块的值绘制到图中
    for( int i = 0; i < 256; i++)
    {
        float fHistValue = cvQueryHistValue_1D(gray_hist, i); //像素为i的直方块大小
        int nRealHeight = cvRound((fHistValue / fMaxHistValue) *256);  //要绘制的高度
        cvRectangle(pHistImage,
                    cvPoint(i * 2, 256 - 1),
                    cvPoint((i + 1) * 2 - 1, 256 - nRealHeight),
                    cvScalar(i, 0, 0, 0),
                    CV_FILLED);
    }
    Mat outMat=cvarrToMat(pHistImage);//IplImage转Mat
    // 显示直方图
    namedWindow("Gray Histogram2", CV_WINDOW_AUTOSIZE );//创建窗口
    imshow("Gray Histogram2", outMat);//窗口中显示直方图
    namedWindow("original image", CV_WINDOW_AUTOSIZE );//创建窗口
    imshow("original image", globalMat );//窗口中显示原图
    waitKey(0);
}

//黑底直方图
void EqualizeHistogram(Mat intMat)
{
#define cvQueryHistValue_1D( hist, idx0 )\
    ((float)cvGetReal1D( (hist)->bins, (idx0)))

    IplImage *src= &IplImage(intMat);
    IplImage* gray_plane = cvCreateImage(cvGetSize(src),8,1);
    IplImage* EqualizeImg = cvCreateImage(cvGetSize(src),8,1);
    cvCvtColor(src,gray_plane,CV_RGB2GRAY);
    cvEqualizeHist(gray_plane, EqualizeImg); // 均衡化

    int hist_size = 256;    //直方图尺寸
    int hist_height = 256;
    float range[] = {0,255};  //灰度级的范围
    float* ranges[]={range};
    //创建一维直方图,统计图像在[0 255]像素的均匀分布
    CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
    cvCalcHist(&EqualizeImg,gray_hist,0,0);//计算灰度图像的一维直方图
    cvNormalizeHist(gray_hist,1.0);//归一化直方图

    int scale = 2;
    //创建一张一维直方图的“图,横坐标为灰度级,纵坐标为像素个数(*scale)
    IplImage* hist_image = cvCreateImage(cvSize(hist_size*scale,hist_height),8,3);
    cvZero(hist_image);
    //统计直方图中的最大直方块
    float max_value = 0;
    cvGetMinMaxHistValue(gray_hist, 0,&max_value,0,0);
    //分别将每个直方块的值绘制到图中
    for(int i=0;ibins, (idx0)))

    IplImage *src= &IplImage(intMat);
    IplImage* gray_plane = cvCreateImage(cvGetSize(src),8,1);
    IplImage* EqualizeImg = cvCreateImage(cvGetSize(src),8,1);
    cvCvtColor(src,gray_plane,CV_RGB2GRAY);//彩色转灰度
    cvEqualizeHist(gray_plane, EqualizeImg); // 均衡化

    int hist_size = 256;    //直方图尺寸
    int hist_height = 256; //直方图尺寸
    float range[] = {0,255};  //灰度级的范围
    float* ranges[]={range};
    CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);//创建一维直方图,统计图像在[0 255]像素的均匀分布
    cvCalcHist(&EqualizeImg,gray_hist,0,0);//计算灰度图像的一维直方图
    cvNormalizeHist(gray_hist,1.0);//归一化直方图
    IplImage *pHistImage = cvCreateImage(cvSize(hist_size * 2, hist_height), IPL_DEPTH_8U, 1);
    cvRectangle(pHistImage, cvPoint(0, 0), cvPoint(pHistImage->width, pHistImage->height), CV_RGB(255, 255, 255), CV_FILLED);
    float fMaxHistValue = 0;//统计直方图中的最大直方块
    cvGetMinMaxHistValue(gray_hist, NULL, &fMaxHistValue, NULL, NULL);//统计直方图中的最大直方块
    //分别将每个直方块的值绘制到图中
    for(int i = 0; i < 256; i++)
    {
        float fHistValue = cvQueryHistValue_1D(gray_hist, i); //像素为i的直方块大小
        int nRealHeight = cvRound((fHistValue / fMaxHistValue) *256);  //要绘制的高度
        cvRectangle(pHistImage,
                    cvPoint(i * 2, 256 - 1),
                    cvPoint((i + 1) * 2 - 1, 256 - nRealHeight),
                    cvScalar(i, 0, 0, 0),
                    CV_FILLED);
    }
    Mat outMat=cvarrToMat(pHistImage);//IplImage转Mat
    Mat outMat2=cvarrToMat(EqualizeImg);//IplImage转Mat
    // 显示直方图
    namedWindow("Equalize Histogram", CV_WINDOW_AUTOSIZE );//创建窗口
    imshow("Equalize Histogram", outMat);//窗口中显示直方图
    namedWindow("Equalize", CV_WINDOW_AUTOSIZE );//创建窗口
    imshow("Equalize",outMat2);//窗口中显示直方图
    namedWindow("original image", CV_WINDOW_AUTOSIZE );//创建窗口
    imshow("original image", globalMat );//窗口中显示原图
    waitKey(0);
}


RGB直方图:

【opencv学习之十四】Opencv灰度直方图和均值化直方图_第3张图片

灰度直方图白底:

【opencv学习之十四】Opencv灰度直方图和均值化直方图_第4张图片

灰度直方图黑底:

【opencv学习之十四】Opencv灰度直方图和均值化直方图_第5张图片

均值化直方图白底:

【opencv学习之十四】Opencv灰度直方图和均值化直方图_第6张图片

均值化直方图黑底:

【opencv学习之十四】Opencv灰度直方图和均值化直方图_第7张图片

均值化图和原图:

【opencv学习之十四】Opencv灰度直方图和均值化直方图_第8张图片



你可能感兴趣的:(opencv,opencv,实例)