calcHist函数

来源:互联网 发布:淘宝seo从入门到精通 编辑:程序博客网 时间:2024/06/05 10:50

 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


多通道场景:

[cpp] view plain copy
print?
  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);  
[cpp] view plain copy
print?
  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. }  


阅读全文
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 脑梗脾气大怎么办好啊 牙齿喝饮料烂了怎么办 大门牙缝里黑了怎么办 椰汁拧不开瓶盖怎么办 装蜂蜜的玻璃罐打不开怎么办 蚂蚱没有草吃了怎么办 笔记本电源已接通未充电怎么办 电源已接通未充电怎么办 遮盖纹身好了颜色淡了怎么办 致炫方向盘变重怎么办 xp音频图标没了怎么办 狙击精英3没子弹怎么办 干活干的手腕疼怎么办 干了活不给钱怎么办 干了活要不到钱怎么办 活干完了钱不给怎么办 微信语音聊天音量很小怎么办 一手软件崩溃钱卡住了怎么办 身上皮肤很黑怎么办?好想穿短裙 家里有很多小飞虫怎么办 家里有垃圾中飞出虫子怎么办 雷蛇笔记本很烫怎么办 登录监控器的账号锁了怎么办 悦借钱登录账号被锁怎么办 365账号登录被锁怎么办 台式电脑cpu温度过高怎么办 UG2.0打不开错误—15怎么办 键盘空格键删除键失灵怎么办 耳麦检测声音不分左右怎么办 吃生萝卜胃疼怎么办 幼兔拉稀怎么办没精神 自酿米酒酸了怎么办 用冰敷脸感觉红烫了怎么办 吃了海兔的内脏怎么办 吃了鱿鱼的吸盘怎么办 想开个烧烤店没学过怎么办 墨鱼汁弄衣服上怎么办 干鱿鱼泡开发黄怎么办 吃了芥末胃疼怎么办 手撕鱿鱼咸了怎么办 孕妇吃了点芥末怎么办