OpenCV深入学习(5)--直方图之calcHist使用

这次再深入学习一下calcHist函数，即用于计算直方图的函数，主要是分析一下该函数的众多的参数，看看应该如何使用，先给出一段代码，其中包括两部分，一部分来自opencv_tutorials中的例子，一部分来自opencv2refman中，都进行了修改，opencv版本为2.3.1。

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

#pragma comment(lib, "opencv_core231d.lib")
#pragma comment(lib, "opencv_highgui231d.lib")
#pragma comment(lib, "opencv_imgproc231d.lib")

using namespace cv;
using namespace std;

#define HIST_DIM1

int main( int argc, char** argv )
{
#ifdef HIST_DIM1
//----------------------example 1-------------------------------//
Mat src, dst;

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

/// Separate the image in 3 places ( R, G and B )
vector<Mat> rgb_planes;
#define SHOW_HSV
#ifdef SHOW_HSV
Mat hsv;
cvtColor(src, hsv, COLOR_BGR2HSV);
split(hsv, rgb_planes );
#else
split(src, rgb_planes );
#endif
/// Establish the number of bins
int histSize = 256;

/// Set the ranges ( for R,G,B) )
float range[] = { 0, 255 } ;
const float* histRange = { range };

bool uniform = true; bool accumulate = false;

Mat r_hist, g_hist, b_hist;

/// Compute the histograms:
calcHist( &rgb_planes[2], 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[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );

// Draw the histograms for R, G and B
int hist_w = 600; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );

Mat rgb_hist[3];
for(int i=0; i<3; ++i)
{
rgb_hist[i] = Mat(hist_h, hist_w, CV_8UC3, Scalar::all(0));
}

Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0,0,0));

/// Normalize the result to [ 0, histImage.rows-10]
normalize(r_hist, r_hist, 0, histImage.rows-10, NORM_MINMAX);
normalize(g_hist, g_hist, 0, histImage.rows-10, NORM_MINMAX);
normalize(b_hist, b_hist, 0, histImage.rows-10, NORM_MINMAX);

/// Draw for each channel
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), 1);
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), 1);
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), 1);
}

for (int j=0; j<histSize; ++j)
{
int val = saturate_cast<int>(r_hist.at<float>(j));
rectangle(rgb_hist[0], Point(j*2+10, rgb_hist[0].rows), Point((j+1)*2+10, rgb_hist[0].rows-val), Scalar(0,0,255),1,8);

val = saturate_cast<int>(g_hist.at<float>(j));
rectangle(rgb_hist[1], Point(j*2+10, rgb_hist[1].rows), Point((j+1)*2+10, rgb_hist[1].rows-val), Scalar(0,255,0),1,8);

val = saturate_cast<int>(b_hist.at<float>(j));
rectangle(rgb_hist[2], Point(j*2+10, rgb_hist[2].rows), Point((j+1)*2+10, rgb_hist[2].rows-val), Scalar(255,0,0),1,8);
}

/// Display
namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE );
namedWindow("wnd");
imshow("calcHist Demo", histImage );
imshow("wnd", src);

imshow("R", rgb_hist[0]);
imshow("G", rgb_hist[1]);
imshow("B", rgb_hist[2]);
#else
//----------------------example 2-------------------------------//
Mat src, hsv;
return -1;
cvtColor(src, hsv, CV_BGR2HSV);
// Quantize the hue to 30 levels
// and the saturation to 32 levels
int hbins = 60, sbins = 64;
int histSize[] = {hbins, sbins};
// hue varies from 0 to 179, see cvtColor
float hranges[] = { 0, 180 };
// saturation varies from 0 (black-gray-white) to
// 255 (pure spectrum color)
float sranges[] = { 0, 256};
const float*ranges[] = { hranges, sranges };
MatND hist;
// we compute the histogram from the 0-th and 1-st channels
int channels[] = {0, 1};
calcHist( &hsv, 1, channels, Mat(),hist, 2, histSize, ranges,true, false );
double maxVal=0;
minMaxLoc(hist, 0, &maxVal, 0, 0);
int scale = 8;
Mat histImg = Mat::zeros(sbins*scale, hbins*scale, CV_8UC3);
for( int h = 0; h < hbins; h++ )
{
for( int s = 0; s < sbins; s++ )
{
float binVal = hist.at<float>(h, s);
int intensity = cvRound(binVal*255/maxVal);
rectangle( histImg, Point(h*scale, s*scale),Point((h+1)*scale-1, (s+1)*scale-1), Scalar::all(intensity), CV_FILLED);
}
}
namedWindow( "Source", 1 );
imshow( "Source", src );
namedWindow( "H-S Histogram", 1 );
imshow( "H-S Histogram", histImg );
#endif
//-------------------------------------------------------------------------//
waitKey(0);
destroyAllWindows();
return 0;
}

1、原先的程序中对加载的彩色rgb图像的通道有问题(看例子给的图应该是在linux下的，不知道是不是因为linux和windows下加载的不同)，在windows下默认加载的通道排列顺序是B-G-R，

2、原先程序的histImage将参数顺序弄错了，该构造函数的第一个参数是rows行数，对应图像的高度，即hist_h，而不是hist_w,这里同时还将大小变换了一下

calcHist--计算矩阵的直方图函数;
--------------------------------------------------------------------------------------------------------------

###---given in manual---###
void calcHist(const Mat*arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims,
const int* histSize, const float** ranges, bool uniform=true, boolaccumulate=false)
void calcHist(const Mat*arrays, int narrays, const int* channels, InputArray mask, SparseMat& hist, int dims,
const int* histSize, const float** ranges, bool uniform=true, boolaccumulate=false)

###---declaration in imgproc.hpp---###
//! computes the joint dense histogram for a set of images.
CV_EXPORTS 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 );

//! computes the joint sparse histogram for a set of images.
CV_EXPORTS 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 );

CV_EXPORTS_W void calcHist( InputArrayOfArrays images, const vector<int>& channels, InputArray mask, OutputArray hist,
const vector<int>& histSize, const vector<float>& ranges,bool accumulate=false );

--------------------------------------------------------------------------------------------------------------

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html

arrays – Source arrays. They all should have the same depth, CV_8U or CV_32F , and the same size. Each of them can have an arbitrary number of channels.
- 源输入（图像）数组，必须是相同深度的CV_8U或者CV_32F(即uchar或者float),相同大小，每一个可以是任意通道的;
[上面的例子1中每次计算一个单通道图像，所以直接对图像取地址赋给了该参数]

narrays – Number of source arrays.
- 源输入数组中的元素个数;
[例子1中只计算一幅图像的直方图，所以这个参数都是1]

channels – List of the dims channels used to compute the histogram. The first array channels are enumerated from 0 to arrays[0].channels()-1 ,   the second array channels are counted from arrays[0].channels() to arrays[0].channels() + arrays[1].channels()-1, and so on.
- 用来计算直方图的通道维数数组,第一个数组的通道由0到arrays[0].channels()-1列出，第二个数组的通道从arrays[0].channels()到arrays[0].channels()+arrays[1].channels()-1以此类推;
[例子1中为0,即第0个通道？？]

mask – Optional mask. If the matrix is not empty, it must be an 8-bit array of the same size as arrays[i].  The non-zero mask elements mark the array elements counted in the histogram.
-可选的掩膜，如果该矩阵不是空的，则必须是8位的并且与arrays[i]的大小相等，掩膜的非零值标记需要在直方图中统计的数组元素;
[例子1中为空的Mat()]

hist – Output histogram, which is a dense or sparse dims -dimensional array.
-输出直方图，是一个稠密或者稀疏的dims维的数组;
[例子1中为保存直方图的Mat]

dims – Histogram dimensionality that must be positive and not greater than CV_MAX_DIMS (equal to 32 in the current OpenCV version).
-直方图的维数，必须为正，并且不大于CV_MAX_DIMS(当前的OpenCV版本中为32，即最大可以统计32维的直方图);
[例子1中为1，因为统计的是每幅单通道图像的灰度直方图]

histSize – Array of histogram sizes in each dimension.
- 用于指出直方图数组每一维的大小的数组，即指出每一维的bin的个数的数组;
[因为例子1只有1维，所以例子1中直接对int取地址作为参数，即该维的bin的个数为256]

ranges – Array of the dims arrays of the histogram bin boundaries in each dimension. When the histogram is uniform ( uniform =true),   then for each dimension i it is enough to specify the lower (inclusive) boundary of the 0-th histogram bin and the upper(exclusive)  boundary for the last histogram bin histSize[i]-1. That is, in case of a uniform histogram each of ranges[i] is an array of 2 elements.   When the histogram is not uniform ( uniform=false ), then each of ranges[i] contains histSize[i]+1 elements:.  The array elements, that are not between  and  , are not counted in the histogram.
- 用于指出直方图每一维的每个bin的上下界范围数组的数组，当直方图是均匀的(uniform =true)时，对每一维i指定直方图的第0个bin的下界(包含即[)L0和最后一个即第histSize[i]-1个bin的上界(不包含的即))U_histSize[i]-1，也就是说对均匀直方图来说，每一个ranges[i]都是一个两个元素的数组【指出该维的上下界】。当直方图不是均匀的时，每一个ranges[i]数组都包含histSize[i]+1个元素:L0,U0=L1,U1=L1,...,U_histSize[i]-2 = L_histSize[i]-1,U_histSize[i]-1.不在L0到U_histSize[i]-1之间的数组元素将不会统计进直方图中;
[在例子1中采用的是均匀直方图，所以范围为0-255]

uniform – Flag indicates that whether the histogram is uniform or not (see above).
- 直方图是否均匀的标志;【指定直方图每个bin统计的是否是相同数量的灰度级】
[例子1中为true]

accumulate – Accumulation flag. If it is set, the histogram is not cleared in the beginning when it is allocated.
This feature enables you to compute a single histogram from several sets of arrays, or to update the histogram in time.
-累加标志；
[单幅图像不进行累计所以例子1中为false]

【channels参数，自己也不是很明确，等看看该函数的源码之后再说】。

• 本文已收录于以下专栏：

calcHist的使用

opencv提供了calcHist函数来计算图像直方图。          其中C++的函数原型如下：void calcHist(const Mat* arrays, int narrays, co...
• sydnash
• 2012年04月11日 20:21
• 23410

OpenCV深入学习(6)--直方图之calcHist使用（补）

• ljbsdu
• 2012年04月01日 21:00
• 14606

calcHist函数

1、calcHist函数 函数作用： calcHist函数来计算图像直方图 2、calcHist函数调用形式 C++: void calcHist(const Mat* images, int n...

calcHist

calcHist函数的channels参数和narrays以及dims共同来确定用于计算直方图的图像； 首先dims是最终的直方图维数，narrays指出了arrays数组中图像的个数，其中每一幅图...
• chezhai
• 2016年12月08日 16:55
• 389

opencv2 直方图之calchist函数使用

• skeeee
• 2013年05月27日 15:24
• 4397

关于calchist()中的channels参数的说明

OpenCV提供了calcHist函数来计算图像直方图。          其中C++的函数原型如下：void calcHist(const Mat* arrays, int narrays, co...
• xbcReal
• 2016年10月24日 22:00
• 430

OpenCV中的calcHist函数解释

calcHist Calculates a histogram of a set of arrays. 计算阵列的直方图。 C++: void calcHist(const Mat*images...
• jkhere
• 2013年03月15日 11:23
• 1947

学习OpenCV2 —— 直方图匹配

• GDFSG
• 2016年03月04日 01:36
• 1138

openCV calcHist函数的使用

﻿﻿ 本文转自：http://blog.csdn.net/sydnash/article/details/7451039    opencv提供了calcHist函数来计算图像直方图。     ...