OpenCV 直方图计算函数 calcHist源码深度剖析

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 头文件的内容(这个头文件是在新建的工程中自己写的):


histogram.cpp 直方图函数实现文件的内容(这个头文件是在OpenCV的原文件上改动了命名空间的名字写成的):


主函数的实现:(主程序中调用了命名空间MyHistFunc中的函数calcHist(....)


需要看客们注意的地方是:我并没有把TBB下的函数拷贝到自定义的命名空间钟来,因为那是并行运算的代码。

如下所示:

  
  
  
  
#ifdef HAVE_TBB
calcHist1D_Invoker < T > body ( _ptrs , _deltas , hist , _uniranges , size [ 0 ], dims , imsize );
parallel_for ( BlockedRange ( 0 , imsize . height ), body );
return ;
#endif
只要没有定义HAVE_TBB标志,自己的命名空间就可以正常运行了,否则会提示你上述类 calcHist1D_Invoker < T >没有定义喔





你可能感兴趣的:(opencv,直方图,calcHist)