opencv图像直方图的计算及绘制

OpenCV 中提供了 calcHist 函数来计算图像直方图,其函数原型是:

void calcHist(const Mat* images, 
    int nimages, 
    const int* channels, 
    InputArray mask, 
    SparseMat& hist, 
    int dims, 
    const int* histSize, 
    const float** ranges, 
    bool uniform=true, 
    bool accumulate=false )
各个参数的含义如下:
images:输入的图像的指针,可以是多幅图像,但要求所有的图像必须有同样的深度(CV_8U or CV_32F)。
nimages:输入的图像的个数。
channels:计算直方图的 channels 的数组。
mask:掩码,如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和输入的图像的大小相同,值非 0 的点将用来计算直方图。
hist:输出参数,计算出来的直方图。
dims:直方图的维数,不能大于 CV_MAX_DIMS 。
histSize:在每一维上直方图的元素个数。
ranges:直方图每一维的范围,ranges 是指向数组的数组,它指向的那些数组为 ranges 的元素,元素大小也就是这些数组的长度。
如果参数uniform为 true,这此时的ranges 里元素的大小为 2(也就是说 ranges 指向一系列长度为 2 的数组);如果参数 uniform 为 false,则此时每一维的坐标值不一定是均匀的,需要人为指定。

uniform: 如果为 true 的话,则说明所需计算的直方图的每一维按照它的范围和尺寸大小均匀取值;如果为 false 的话,说明直方图的每一维不是均匀分布取值的,参考参数 ranges 的解释。
accumulate: 表示是否对传入的 hist 清零。不清零的话可以将多幅图像的直方图累加。

#include  
#include  
#include   
using namespace cv;  
using namespace std;  
  
int main()  
{  
    Mat srcImage = imread("E://IM_VIDEO//kobe.jpg");  
    imshow("ScrImage", srcImage);  
    int channels = 0;  
    MatND dstHist;  
    int histSize[] = { 256 };       //如果写成int histSize = 256;调用计算直方图的函数的时,该变量需写成&histSize  
    float midRanges[] = { 0, 256 };  
    const float *ranges[] = { midRanges };  
    calcHist(&srcImage, 1, &channels, Mat(), dstHist, 1, histSize, ranges, true, false);  
  
    //绘制直方图,首先先创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像  
    Mat drawImage = Mat::zeros(Size(256, 256), CV_8UC3);  
    //任何一个图像的某个像素的总个数有可能会很多,甚至超出所定义的图像的尺寸,
    //所以需要先对个数进行范围的限制,用minMaxLoc函数来得到计算直方图后的像素的最大个数  
    double g_dHistMaxValue;  
    minMaxLoc(dstHist, 0, &g_dHistMaxValue, 0, 0);  
    //将像素的个数整合到图像的最大范围内  
    for (int i = 0; i < 256; i++)  
    {  
        int value = cvRound(dstHist.at(i) * 256 * 0.9 / g_dHistMaxValue);  
        line(drawImage, Point(i, drawImage.rows - 1), Point(i, drawImage.rows - 1 - value), Scalar(0, 0, 255));  
    }  
  
    imshow("hist", drawImage);  
    waitKey(0);  
    return 0;  
}  
运行结果如下:

opencv图像直方图的计算及绘制_第1张图片


实例二:将计算和绘制直方图写成函数

#include "opencv2/highgui/highgui.hpp"  
#include "opencv2/imgproc/imgproc.hpp"  
#include   
#include   
  
using namespace std;  
using namespace cv;  
// 得到图像的直方图
 MatND getHistogram(Mat &image)    
{  
    MatND hist;  
    int channels[] = {0};  
    int dims = 1;  
    int histSize[] = {256};   
    float granges[] = {0, 255};  
    const float *ranges[] = {granges};  
    calcHist(&image, 1, channels, Mat(), hist, dims, histSize, ranges);  
    return hist;  
}  
 //  将图像直方图展示出来  
 Mat getHistogramImage(Mat &image) 
{  
    MatND hist = getHistogram(image);  
    Mat showImage(256,256, CV_8U,Scalar(0));  
    int i;  
    double maxValue = 0;  
    minMaxLoc(hist, 0, &maxValue, 0, 0);  
    for(i = 0; i < 256; i++)  
    {  
        float value = hist.at(i);  
        int intensity = saturate_cast(256 - 256* (value/maxValue));  
        rectangle(showImage, Point(i,256 - 1), Point((i+1)-1, intensity), Scalar(255));  
    }  
    return showImage;  
}
 //主函数
 int main()  
{  
    Mat image = imread("E://IM_VIDEO//kobe.jpg");  
    if(!image.data)  
    {  
        cout << "fail to load the image" << endl;  
        return 0;  
    }  
    Mat showImage = getHistogramImage(image);  
    namedWindow("image");  
    imshow("image", image);  
    namedWindow("showImage");  
    imshow("showImage", showImage);  
    waitKey(0);  
    return 0;  
} 
运行结果:

opencv图像直方图的计算及绘制_第2张图片


实例三:计算和绘制多通道图像的直方图

#include "opencv2/highgui/highgui.hpp"  
#include "opencv2/imgproc/imgproc.hpp"  
#include   
#include   
  
using namespace std;  
using namespace cv;  
  
int main( int argc, char** argv )  
{  
  Mat src, dst;  
 src = imread("E://IM_VIDEO//kobe.jpg");  
  
 if( !src.data )  
   { return -1; }  
  
 vector rgb_planes;  
 split( src, rgb_planes );  
  
 int histSize = 255;  
 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("calcHist Demo", CV_WINDOW_AUTOSIZE );  
 imshow("calcHist Demo", histImage );  
  
 waitKey(0);  
  
 return 0;  
  
}  
运行结果如下:

opencv图像直方图的计算及绘制_第3张图片

参考:

http://blog.csdn.net/liyuanbhu/article/details/50708912

http://blog.csdn.net/qq_23880193/article/details/49669297

http://blog.csdn.net/zhouzhouzf/article/details/9272299

http://blog.csdn.net/lu597203933/article/details/17061173

你可能感兴趣的:(opencv)