calcHist函数

 1、calcHist函数

函数作用:

calcHist函数来计算图像直方图

2、calcHist函数调用形式

C++: void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false )


参数详解:

onst Mat* images:输入图像

 int nimages:输入图像的个数

const int* channels:需要统计直方图的第几通道

InputArray mask:掩膜,,计算掩膜内的直方图  ...Mat()

OutputArray hist:输出的直方图数组

int dims:需要统计直方图通道的个数

const int* histSize:指的是直方图分成多少个区间,,,就是 bin的个数

const float** ranges: 统计像素值得区间

bool uniform=true::是否对得到的直方图数组进行归一化处理

bool accumulate=false:在多个图像时,是否累计计算像素值得个数

3、opencv代码

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;

/** @函数 main */
int main( int argc, char** argv )
{
  Mat src, dst;

 /// 装载图像
 src = imread( argv[1], 1 );

 if( !src.data )
   { return -1; }

 /// 分割成3个单通道图像 ( R, G 和 B )
 vector<Mat> rgb_planes;
 split( src, 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("calcHist Demo", CV_WINDOW_AUTOSIZE );
 imshow("calcHist Demo", histImage );

 waitKey(0);

 return 0;

}

解释

  1. 创建一些矩阵:

    Mat src, dst;
    
  2. 装载原图像

    src = imread( argv[1], 1 );
    
    if( !src.data )
      { return -1; }
    
  3. 使用OpenCV函数 split 将图像分割成3个单通道图像:

    vector<Mat> rgb_planes;
    split( src, rgb_planes );
    

    输入的是要被分割的图像 (这里包含3个通道), 输出的则是Mat类型的的向量。

  4. 现在对每个通道配置 直方图 设置, 既然我们用到了 R, G 和 B 通道, 我们知道像素值的范围是 [0,255]

    1. 设定bins数目 (5, 10...):

      int histSize = 255;
      
    2. 设定像素值范围 (前面已经提到,在 0 到 255之间 )

      /// 设定取值范围 ( R,G,B) )
      float range[] = { 0, 255 } ;
      const float* histRange = { range };
      
    3. 我们要把bin范围设定成同样大小(均一)以及开始统计前先清除直方图中的痕迹:

      bool uniform = true; bool accumulate = false;
      
    4. 最后创建储存直方图的矩阵:

      Mat r_hist, g_hist, b_hist;
      
    5. 下面使用OpenCV函数 calcHist 计算直方图:

      /// 计算直方图:
      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 );
      

      参数说明如下:

      • &rgb_planes[0]: 输入数组(或数组集)
      • 1: 输入数组的个数 (这里我们使用了一个单通道图像,我们也可以输入数组集 )
      • 0: 需要统计的通道 (dim)索引 ,这里我们只是统计了灰度 (且每个数组都是单通道)所以只要写 0 就行了。
      • Mat(): 掩码( 0 表示忽略该像素), 如果未定义,则不使用掩码
      • r_hist: 储存直方图的矩阵
      • 1: 直方图维数
      • histSize: 每个维度的bin数目
      • histRange: 每个维度的取值范围
      • uniform 和 accumulate: bin大小相同,清楚直方图痕迹
  5. 创建显示直方图的画布:

    // 创建直方图画布
    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) );
    
  6. 在画直方图之前,先使用 normalize 归一化直方图,这样直方图bin中的值就被缩放到指定范围:

    /// 将直方图归一化到范围 [ 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() );
    

    该函数接受下列参数:

    • r_hist: 输入数组
    • r_hist: 归一化后的输出数组(支持原地计算)
    • 0 及 histImage.rows: 这里,它们是归一化 r_hist 之后的取值极限
    • NORM_MINMAX: 归一化方法 (例中指定的方法将数值缩放到以上指定范围)
    • -1: 指示归一化后的输出数组与输入数组同类型
    • Mat(): 可选的掩码
  7. 请注意这里如何读取直方图bin中的数据 (此处是一个1维直方图):

      /// 在直方图画布上画出直方图
      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  );
        }
    
    
    使用了以下表达式:
    
    .. code-block:: cpp
    
       r_hist.at<float>(i)
    
    
      :math:`i` 指示维度,假如我们要访问2维直方图,我们就要用到这样的表达式:
    
    .. code-block:: cpp
    
       r_hist.at<float>( i, j )
  8. 最后显示直方图并等待用户退出程序:

    namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE );
    imshow("calcHist Demo", histImage );
    
    waitKey(0);
    
    return 0;
    

结果

  1. 使用下图作为输入图像:

    ../../../../../_images/Histogram_Calculation_Original_Image.jpg
  2. 产生以下直方图:

    ../../../../../_images/Histogram_Calculation_Result.jpg


多通道场景:

  1.     Mat src, hsv;  
  2.     if(!(src=imread("d:/picture/lena.bmp")).data)  
  3.         return -1;  
  4.     cvtColor(src, hsv, CV_BGR2HSV);  
  5.     vector<Mat> hsv_plane;  
  6.     split(hsv, hsv_plane);  
  7.     Mat inputs[]={hsv_plane[1], hsv_plane[2], hsv_plane[0]};  
  8.       
  9.     vector<Mat> mixmat_plane;  
  10.     mixmat_plane.push_back(hsv_plane[2]);  
  11.     mixmat_plane.push_back(hsv_plane[0]);  
  12.     Mat mixmat;  
  13.     merge(mixmat_plane, mixmat);  
  14.     Mat mixed[]={mixmat,hsv_plane[1]};  
  15.   
  16.     int vbins = 128, sbins = 128, hbins = 128;  
  17.     int histSize[] = {sbins, vbins, hbins};  
  18.     float sranges[] = { 0, 256};  
  19.     float vranges[] = { 0, 256};  
  20.     float hranges[] = { 0, 256};  
  21.     const float*ranges[] = {sranges, vranges, hranges};  
  22.     MatND hist;  
  23.   
  24. //#define SINGLE_MAT  
  25. #define MIX_MAT  
  26.   
  27. #ifdef SINGLE_MAT     
  28. /* 
  29. use one multi-channel mat, channels param gives the channels used;  
  30. 使用多通道的图像计算多维直方图,可以计算1,2,3维的; 
  31. */  int channels[] = {1, 2};  
  32.     calcHist(&hsv, 1, channels, Mat(),hist, 2, histSize, ranges,truefalse );  
  33. #elif defined MIX_MAT   
  34. /* 
  35. use mix mat array, the first elem is a single channel mat, second is a two channel mat; 
  36. 使用混合通道图像数组,第1个图像是2通道的,第2个是单通道的; 
  37. channels指定每一维对应的通道; 
  38. */    
  39.     int channels[] = {1, 2, 0};  
  40.   
  41. // #define DIM_2  
  42. #ifdef DIM_2  
  43. //统计二维直方图;  
  44.     calcHist(mixed, 2, channels, Mat(),hist, 2, histSize, ranges,truefalse);  
  45. #else  
  46. //统计三维直方图;  
  47.     calcHist(mixed, 2, channels, Mat(),hist, 3, histSize, ranges,truefalse);  
  48. #endif  
  49.   
  50. #else  
  51. /* 
  52. use multi-mat arrays, channels param gives the array mat and its channels used; 
  53. 使用都是单通道图像数组计算2维直方图--也可以计算3维的; 
  54. */    
  55.     int channels[] = {2, 1};  
  56.     hbins = 1;  
  57.     calcHist(inputs, 3, channels, Mat(),hist, 2, histSize, ranges,truefalse );  
  58. #endif  
  59.   
  60. #ifndef MIX_MAT  
  61.     double maxVal=0;  
  62.     minMaxLoc(hist, 0, 0, 0, 0);//only can process mat that dims<=2--minMaxLoc只能处理2维以下的;  
  63. #endif  
  64.   
  65.     int scale = 4;  
  66.     Mat histImg = Mat::zeros(vbins*scale, sbins*scale, CV_8UC3);  
  67.     float *hist_sta = new float[sbins];  
  68.     float *hist_val = new float[vbins];  
  69.     float *hist_hue = new float[hbins];  
  70.     memset(hist_val, 0, vbins*sizeof(float));  
  71.     memset(hist_sta, 0, sbins*sizeof(float));  
  72.     memset(hist_hue, 0, hbins*sizeof(float));  
  73.   
  74.     forint s = 0; s < sbins; s++ )  
  75.     {  
  76.         forint v = 0; v < vbins; v++ )  
  77.         {  
  78.             for(int h=0; h<hbins; h++)  
  79.             {  
  80. #ifdef MIX_MAT  
  81. //-----------------------------------------------------------//  
  82. #ifdef DIM_2  
  83.                 float binVal = hist.at<float>(s, v);  
  84. #else  
  85.                 float binVal = hist.at<float>(s, v, h);  
  86.                 hist_hue[h] += binVal;  
  87. #endif  
  88. //-----------------------------------------------------------//               
  89. #else  
  90.                 float binVal = hist.at<float>(s, v);  
  91.                 int intensity = cvRound(binVal*255/maxVal);  
  92.                 rectangle( histImg, Point(s*scale, v*scale),Point((s+1)*scale-1, (v+1)*scale-1), Scalar::all(intensity), CV_FILLED);  
  93. #endif  
  94.                 hist_val[v] += binVal;  
  95.                 hist_sta[s] += binVal;  
  96.   
  97.             }  
  98.         }  
  99.     }  
  100.     //find max bin value;  
  101.     double max_sta=.0, max_val=.0,max_hue=.0;  
  102.     for(int i=0; i<sbins; ++i)  
  103.     {  
  104.         if(hist_sta[i]>max_sta)  
  105.             max_sta = hist_sta[i];  
  106.     }  
  107.     for(int i=0; i<vbins; ++i)  
  108.     {  
  109.         if(hist_val[i]>max_val)  
  110.             max_val = hist_val[i];  
  111.     }  
  112.     for(int i=0; i<hbins; ++i)  
  113.     {  
  114.         if(hist_hue[i]>max_hue)  
  115.             max_hue = hist_hue[i];  
  116.     }  
  117.   
  118.     Mat sta_img = Mat::zeros(310, sbins*scale+20, CV_8UC3);  
  119.     Mat val_img = Mat::zeros(310, vbins*scale+20, CV_8UC3);  
  120.     Mat hue_img = Mat::zeros(310, hbins*scale+20, CV_8UC3);  
  121.   
  122.     for(int i=0; i<sbins; ++i)  
  123.     {  
  124.         int intensity = cvRound(hist_sta[i]*(sta_img.rows-10)/max_sta);  
  125.         rectangle(sta_img, Point(i*scale+10, sta_img.rows-intensity),Point((i+1)*scale-1+10, sta_img.rows-1), Scalar(0,255,0), 1);  
  126.     }  
  127.     for(int i=0; i<vbins; ++i)  
  128.     {  
  129.         int intensity = cvRound(hist_val[i]*(val_img.rows-10)/max_val);  
  130.         rectangle(val_img, Point(i*scale+10, val_img.rows-intensity),Point((i+1)*scale-1+10, val_img.rows-1), Scalar(0,0,255), 1);  
  131.     }  
  132.     for(int i=0; i<hbins; ++i)  
  133.     {  
  134.         int intensity = cvRound(hist_hue[i]*(hue_img.rows-10)/max_hue);  
  135.         rectangle(hue_img, Point(i*scale+10, hue_img.rows-intensity),Point((i+1)*scale-1+10, hue_img.rows-1), Scalar(255,0,0), 1);  
  136.     }  
  137.   
  138.     namedWindow( "Source");  
  139.     imshow( "Source", src );  
  140.     namedWindow( "Histogram");  
  141.     imshow( "Histogram", histImg );  
  142.     namedWindow("dim1");  
  143.     imshow("dim1", sta_img);  
  144.     namedWindow("dim2");  
  145.     imshow("dim2", val_img);      
  146.     namedWindow("dim3");  
  147.     imshow("dim3", hue_img);  
	Mat src, hsv;
	if(!(src=imread("d:/picture/lena.bmp")).data)
		return -1;
	cvtColor(src, hsv, CV_BGR2HSV);
	vector<Mat> hsv_plane;
	split(hsv, hsv_plane);
	Mat inputs[]={hsv_plane[1], hsv_plane[2], hsv_plane[0]};
	
	vector<Mat> mixmat_plane;
	mixmat_plane.push_back(hsv_plane[2]);
	mixmat_plane.push_back(hsv_plane[0]);
	Mat mixmat;
	merge(mixmat_plane, mixmat);
	Mat mixed[]={mixmat,hsv_plane[1]};

	int vbins = 128, sbins = 128, hbins = 128;
	int histSize[] = {sbins, vbins, hbins};
	float sranges[] = { 0, 256};
	float vranges[] = { 0, 256};
	float hranges[] = { 0, 256};
	const float*ranges[] = {sranges, vranges, hranges};
	MatND hist;

//#define SINGLE_MAT
#define MIX_MAT

#ifdef SINGLE_MAT	
/*
use one multi-channel mat, channels param gives the channels used; 
使用多通道的图像计算多维直方图,可以计算1,2,3维的;
*/	int channels[] = {1, 2};
	calcHist(&hsv, 1, channels, Mat(),hist, 2, histSize, ranges,true, false );
#elif defined MIX_MAT 
/*
use mix mat array, the first elem is a single channel mat, second is a two channel mat;
使用混合通道图像数组,第1个图像是2通道的,第2个是单通道的;
channels指定每一维对应的通道;
*/	
	int channels[] = {1, 2, 0};

// #define DIM_2
#ifdef DIM_2
//统计二维直方图;
	calcHist(mixed, 2, channels, Mat(),hist, 2, histSize, ranges,true, false);
#else
//统计三维直方图;
	calcHist(mixed, 2, channels, Mat(),hist, 3, histSize, ranges,true, false);
#endif

#else
/*
use multi-mat arrays, channels param gives the array mat and its channels used;
使用都是单通道图像数组计算2维直方图--也可以计算3维的;
*/	
	int channels[] = {2, 1};
	hbins = 1;
	calcHist(inputs, 3, channels, Mat(),hist, 2, histSize, ranges,true, false );
#endif

#ifndef MIX_MAT
	double maxVal=0;
	minMaxLoc(hist, 0, 0, 0, 0);//only can process mat that dims<=2--minMaxLoc只能处理2维以下的;
#endif

	int scale = 4;
	Mat histImg = Mat::zeros(vbins*scale, sbins*scale, CV_8UC3);
	float *hist_sta = new float[sbins];
	float *hist_val = new float[vbins];
	float *hist_hue = new float[hbins];
	memset(hist_val, 0, vbins*sizeof(float));
	memset(hist_sta, 0, sbins*sizeof(float));
	memset(hist_hue, 0, hbins*sizeof(float));

	for( int s = 0; s < sbins; s++ )
	{
		for( int v = 0; v < vbins; v++ )
		{
			for(int h=0; h<hbins; h++)
			{
#ifdef MIX_MAT
//-----------------------------------------------------------//
#ifdef DIM_2
				float binVal = hist.at<float>(s, v);
#else
				float binVal = hist.at<float>(s, v, h);
				hist_hue[h] += binVal;
#endif
//-----------------------------------------------------------//				
#else
				float binVal = hist.at<float>(s, v);
				int intensity = cvRound(binVal*255/maxVal);
				rectangle( histImg, Point(s*scale, v*scale),Point((s+1)*scale-1, (v+1)*scale-1), Scalar::all(intensity), CV_FILLED);
#endif
				hist_val[v] += binVal;
				hist_sta[s] += binVal;

			}
		}
	}
	//find max bin value;
	double max_sta=.0, max_val=.0,max_hue=.0;
	for(int i=0; i<sbins; ++i)
	{
		if(hist_sta[i]>max_sta)
			max_sta = hist_sta[i];
	}
	for(int i=0; i<vbins; ++i)
	{
		if(hist_val[i]>max_val)
			max_val = hist_val[i];
	}
	for(int i=0; i<hbins; ++i)
	{
		if(hist_hue[i]>max_hue)
			max_hue = hist_hue[i];
	}

	Mat sta_img = Mat::zeros(310, sbins*scale+20, CV_8UC3);
	Mat val_img = Mat::zeros(310, vbins*scale+20, CV_8UC3);
	Mat hue_img = Mat::zeros(310, hbins*scale+20, CV_8UC3);

	for(int i=0; i<sbins; ++i)
	{
		int intensity = cvRound(hist_sta[i]*(sta_img.rows-10)/max_sta);
		rectangle(sta_img, Point(i*scale+10, sta_img.rows-intensity),Point((i+1)*scale-1+10, sta_img.rows-1), Scalar(0,255,0), 1);
	}
	for(int i=0; i<vbins; ++i)
	{
		int intensity = cvRound(hist_val[i]*(val_img.rows-10)/max_val);
		rectangle(val_img, Point(i*scale+10, val_img.rows-intensity),Point((i+1)*scale-1+10, val_img.rows-1), Scalar(0,0,255), 1);
	}
	for(int i=0; i<hbins; ++i)
	{
		int intensity = cvRound(hist_hue[i]*(hue_img.rows-10)/max_hue);
		rectangle(hue_img, Point(i*scale+10, hue_img.rows-intensity),Point((i+1)*scale-1+10, hue_img.rows-1), Scalar(255,0,0), 1);
	}

	namedWindow( "Source");
	imshow( "Source", src );
	namedWindow( "Histogram");
	imshow( "Histogram", histImg );
	namedWindow("dim1");
	imshow("dim1", sta_img);
	namedWindow("dim2");
	imshow("dim2", val_img);	
	namedWindow("dim3");
	imshow("dim3", hue_img);
  1. </pre><pre name="code" class="cpp">  
  2. <pre name="code" class="cpp">#include "opencv2/highgui/highgui.hpp"  
  3. #include "opencv2/imgproc/imgproc.hpp"  
  4. #include <iostream>  
  5. #include <stdio.h>  
  6.   
  7. using namespace std;  
  8. using namespace cv;  
  9.   
  10. /** @函数 main */  
  11. int main( int argc, char** argv )  
  12. {  
  13.   Mat src, dst;  
  14.   
  15.  /// 装载图像  
  16.  src = imread( argv[1], 1 );  
  17.   
  18.  if( !src.data )  
  19.    { return -1; }  
  20.   
  21.  /// 分割成3个单通道图像 ( R, G 和 B )  
  22.  vector<Mat> rgb_planes;  
  23.  split( src, rgb_planes );  
  24.   
  25.  /// 设定bin数目  
  26.  int histSize = 255;  
  27.   
  28.  /// 设定取值范围 ( R,G,B) )  
  29.  float range[] = { 0, 255 } ;  
  30.  const float* histRange = { range };  
  31.   
  32.  bool uniform = truebool accumulate = false;  
  33.   
  34.  Mat r_hist, g_hist, b_hist;  
  35.   
  36.  /// 计算直方图:  
  37.  calcHist( &rgb_planes[0], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );  
  38.  calcHist( &rgb_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );  
  39.  calcHist( &rgb_planes[2], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );  
  40.   
  41.  // 创建直方图画布  
  42.  int hist_w = 400; int hist_h = 400;  
  43.  int bin_w = cvRound( (double) hist_w/histSize );  
  44.   
  45.  Mat histImage( hist_w, hist_h, CV_8UC3, Scalar( 0,0,0) );  
  46.   
  47.  /// 将直方图归一化到范围 [ 0, histImage.rows ]  
  48.  normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );  
  49.  normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );  
  50.  normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );  
  51.   
  52.  /// 在直方图画布上画出直方图  
  53.  forint i = 1; i < histSize; i++ )  
  54.    {  
  55.      line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) ,  
  56.                       Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ),  
  57.                       Scalar( 0, 0, 255), 2, 8, 0  );  
  58.      line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) ,  
  59.                       Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ),  
  60.                       Scalar( 0, 255, 0), 2, 8, 0  );  
  61.      line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) ,  
  62.                       Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ),  
  63.                       Scalar( 255, 0, 0), 2, 8, 0  );  
  64.     }  
  65.   
  66.  /// 显示直方图  
  67.  namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE );  
  68.  imshow("calcHist Demo", histImage );  
  69.   
  70.  waitKey(0);  
  71.   
  72.  return 0;  
  73.   
  74. }  
</pre><pre name="code" class="cpp">
<pre name="code" class="cpp">#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;

/** @函数 main */
int main( int argc, char** argv )
{
  Mat src, dst;

 /// 装载图像
 src = imread( argv[1], 1 );

 if( !src.data )
   { return -1; }

 /// 分割成3个单通道图像 ( R, G 和 B )
 vector<Mat> rgb_planes;
 split( src, 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("calcHist Demo", CV_WINDOW_AUTOSIZE );
 imshow("calcHist Demo", histImage );

 waitKey(0);

 return 0;

}


 
  • 10
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值