OpenCV中的直方图计算函数calcHist函数可以计算给定的若干幅图像的指定的通道的统计直方图!
calcHist函数原型为
//!计算给定图像集合的联合密度直方图 (joint dense histogram)
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 );
该函数内部的实现方式是怎样的呢?
首先调用了函数 histPrepareImages(....)准备一些中间变量,
//该函数主要初始化了三个中间临时变量 ptrs,deltas,uniranges
static void histPrepareImages( const Mat* images, int nimages, const int* channels,
const Mat& mask, int dims, const int* histSize, const float** ranges, bool uniform,
vector<uchar*>& ptrs, vector<int>& deltas, Size& imsize, vector<double>& uniranges )
接着根据输入图像的位深度调用不同的函数实现
针对8位深度的图像,调用了函数calcHist_8u(.....)
static void
calcHist_8u( vector<uchar*>& _ptrs, const vector<int>& _deltas, Size imsize, Mat& hist, int dims, const float** _ranges, const double* _uniranges, bool uniform )
针对16位和32位深度图像,调用了模板类函数
template<typename T> static void
calcHist_( vector<uchar*>& _ptrs, const vector<int>& _deltas, Size imsize, Mat& hist, int dims, const float** _ranges, const double* _uniranges, bool uniform )
调用方式如下:
int depth = images[0].depth();//输入图像的深度
//根据输入图像的位深度调用不同的直方图计算函数
if( depth == CV_8U ) //8位深度
calcHist_8u(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
else if( depth == CV_16U )//16位深度
calcHist_<ushort>(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
else if( depth == CV_32F ) //32位深度
calcHist_<float>(ptrs, deltas, imsize, ihist, dims, ranges, _uniranges, uniform );
else
CV_Error(CV_StsUnsupportedFormat, "");
为了研究源码,我把位于...\OpenCV245\modules\imgproc\src\文件夹下的histogram.cpp文件下的相关函数加到自定义命名空间中,这么做就可以调试运行每一行代码啦
在命名空间MyHistFunc中定义了一系列与直方图的计算为主要目的之函数,所有在该Histogram.cpp文件中被定义为 static 类型的函数,在头文件Histogram.h中都没有进行声明,所以这些静态函数都只能在该文件中被该文件的定义在他之后的其他函数调用;而只有函数calcHist( const Mat* images, int nimages, const int* channels,InputArray _mask, OutputArray _hist, int dims, const int* histSize,const float** ranges, bool uniform, bool accumulate )在头文件中进行了声明,所以该函数是唯一暴露在外边,可以被其他文件中的函数(如Main()函数)调用的函数。 如果你想在别的文件的函数中调用该文件中的static类型的函数,那么只需要把该函数的声明复制到头文件Histogram.h中,就像calcHist(....)函数那样。
histogram.h 头文件的内容(这个头文件是在新建的工程中自己写的):
主函数的实现:(主程序中调用了命名空间MyHistFunc中的函数calcHist(....))
需要看客们注意的地方是:我并没有把TBB下的函数拷贝到自定义的命名空间钟来,因为那是并行运算的代码。
如下所示:
只要没有定义HAVE_TBB标志,自己的命名空间就可以正常运行了,否则会提示你上述类 calcHist1D_Invoker < T >没有定义喔#ifdef HAVE_TBBcalcHist1D_Invoker < T > body ( _ptrs , _deltas , hist , _uniranges , size [ 0 ], dims , imsize );parallel_for ( BlockedRange ( 0 , imsize . height ), body );return ;#endif