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

来源:互联网 发布:用别人身份证开淘宝店 编辑:程序博客网 时间:2024/06/18 05:22

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

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


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

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


以上只是一个说明直方图如何工作以及它的用处的简单示例。直方图可以统计的不仅仅是颜色灰度, 它可以统计任何图像特征 (如 梯度, 方向等等)。
让我们再来搞清楚直方图的一些具体细节:
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 <QApplication>#include <math.h>#include <opencv/cv.h>#include <opencv/highgui.h>#include <opencv2/highgui/highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <opencv2/core/core.hpp>#include <iostream>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<Mat> 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<float>(i-1)) ) ,              Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),              Scalar( 0, 0, 255), 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(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  );    }    /// 显示直方图    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<=i<cDims,译者注: cDims为    //        直方图的维数,对于灰度图为 1,彩色图为 3)是包含两个元素的范围数组,    //        包括直方图第i维的上界和下界。在第i维上的整个区域 [lower,upper]被分割    //        成 dims[i] 个相等的块(译者注: dims[i]表示直方图第i维的块数),这些块    //        用来确定输入象素的第 i 个值(译者注:对于彩色图像, i确定R, G,或者B)    //        的对应的块;如果为 0,则ranges[i]是包含dims[i]+1个元素的范围数组,包    //        括lower0, upper0, lower1, upper1 == lower2, ..., upperdims[i]-1, 其中lowerj 和    //        upperj分别是直方图第i维上第 j 个方块的上下界(针对输入象素的第 i 个    //        值)。任何情况下,输入值如果超出了一个直方块所指定的范围外,都不会    //        被 cvCalcHist 计数,而且会被函数 cvCalcBackProject 置零。    cvCalcHist(&gray_plane,gray_hist,0,0); //计算灰度图像的一维直方图    //    计算图像 image(s) 的直方图    //    函数 cvCalcHist 计算单通道或多通道图像的直方图。 用来增加直方块的    //    数组元素可从相应输入图像的同样位置提取。    //    void cvCalcHist( IplImage** image,         //输入图像    //                     CvHistogram* hist,        //输入图像    //                     int accumulate=0,         // 累计标识    //                     const CvArr* mask=NULL ); // 操作 mask, 确定输入图像的哪个象素被计数    //    image    //    输入图像 s (虽然也可以使用 CvMat** ).    //    hist    //    输入图像    //    accumulate    //    累计标识。如果设置,则直方图在开始时不被清零。这个特征保证可以为多    //    个图像计算一个单独的直方图,或者在线更新直方图。    //    mask    //    操作 mask, 确定输入图像的哪个象素被计数    int scale = 2;    //创建一张一维直方图的“图”,横坐标为灰度级,纵坐标为像素个数(*scale)      IplImage* hist_image = cvCreateImage(cvSize(hist_size*scale,hist_height),8,3);    //    IplImage* cvCreateImage( CvSize size, int depth, int channels );    //    size 图像宽、高.    //    depth    //    图像元素的位深度,可以是下面的其中之一:    //    IPL_DEPTH_8U - 无符号 8 位整型    //    IPL_DEPTH_8S - 有符号 8 位整型    //    IPL_DEPTH_16U - 无符号 16 位整型    //    IPL_DEPTH_16S - 有符号 16 位整型    //    IPL_DEPTH_32S - 有符号 32 位整型    //    IPL_DEPTH_32F - 单精度浮点数    //    IPL_DEPTH_64F - 双精度浮点数    //    channels    //    每个元素(像素)通道号.可以是 1, 2, 3 或 4.通道是交叉存取的,例如通常    //    的彩色图像数据排列是:    //    b0 g0 r0 b1 g1 r1 ...    //    虽然通常 IPL 图象格式可以存贮非交叉存取的图像,并且一些 OpenCV 也    //    能处理他, 但是这个函数只能创建交叉存取图像.      cvZero(hist_image);//这个宏使得背景为黑色    //统计直方图中的最大直方块    float max_value = 0;    cvGetMinMaxHistValue(gray_hist, 0,&max_value,0,0);    //分别将每个直方块的值绘制到图中    for(int i=0;i<hist_size;i++)    {        float bin_val = cvQueryHistValue_1D(gray_hist,i); //像素i的概率        int intensity = cvRound(bin_val*hist_height/max_value);  //要绘制的高度        cvRectangle(hist_image,//图像                    cvPoint(i*scale,hist_height-1),//矩形的一个顶点                    cvPoint((i+1)*scale - 1, hist_height - intensity),//矩形的对角线上顶点                    Scalar(0,255,255) ); //线条颜色 (RGB) 或亮度(灰度图像 )(grayscale image)CV_RGB(0,255,255)    }    //创建方块图实例    cvRectangle(hist_image,            //图像                cvPoint(20,200),       //矩形的一个顶点                cvPoint(200,300),      //矩形的对角线上顶点                Scalar(0,255,255),     //线条颜色 (RGB) 或亮度(灰度图像 )(grayscale image)                1,                     //组成矩形的线条的粗细程度。取负值时(如 CV_FILLED)函数绘制填充了色彩的矩形。                1,                     //线条的类型。见cvLine的描述                0);                    //坐标点的小数点位数。    Mat outMat=cvarrToMat(hist_image);//IplImage转Mat    // 显示直方图    namedWindow("Gray Histogram", CV_WINDOW_AUTOSIZE );//创建窗口    imshow("Gray Histogram", outMat);//窗口中显示直方图    namedWindow("original image", CV_WINDOW_AUTOSIZE );//创建窗口    imshow("original image", globalMat );//窗口中显示原图    waitKey(0);}//白底直方图带灰度阶的void GrayHistogram2(Mat intMat){    //cvQueryHistValue_1D这个宏必须加#define cvQueryHistValue_1D( hist, idx0 )\    ((float)cvGetReal1D( (hist)->bins, (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;i<hist_size;i++)    {        float bin_val = cvQueryHistValue_1D(gray_hist,i); //像素i的概率        int intensity = cvRound(bin_val*hist_height/max_value);  //要绘制的高度        cvRectangle(hist_image,                    cvPoint(i*scale,hist_height-1),                    cvPoint((i+1)*scale - 1, hist_height - intensity),                    CV_RGB(255,255,255));    }    Mat outMat=cvarrToMat(hist_image);//IplImage转Mat    Mat outMat2=cvarrToMat(EqualizeImg);//IplImage转Mat    // 显示直方图    namedWindow("Gray Histogram", CV_WINDOW_AUTOSIZE );//创建窗口    imshow("Gray Histogram", outMat);//窗口中显示直方图    namedWindow("Equalize", CV_WINDOW_AUTOSIZE );//创建窗口    imshow("Equalize",outMat2);//窗口中显示直方图    namedWindow("original image", CV_WINDOW_AUTOSIZE );//创建窗口    imshow("original image", globalMat );//窗口中显示原图    waitKey(0);}//白底直方图void EqualizeHistogram2(Mat intMat){    //cvQueryHistValue_1D这个宏必须加#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};    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直方图:


灰度直方图白底:


灰度直方图黑底:


均值化直方图白底:


均值化直方图黑底:


均值化图和原图:



原创粉丝点击