形态学处理最基本的操作是腐蚀和膨胀,所以研究一下opencv的这两个基本操作,路径:D:\OpenCV\opencv\sources\modules\imgproc\src\morph.cpp中,由于腐蚀和膨胀的基本程序流程一样,在这里着重看一下cv::erode()函数
void cv::erode( InputArray src, OutputArray dst, InputArray kernel,
Point anchor, int iterations,
int borderType, const Scalar& borderValue )
{
//调用opencv的函数morphOp并设置参数为MORPH_ERODE
morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue ); //见补充一
}
//===================补充一=================//
static void morphOp( int op, InputArray _src, OutputArray _dst,
InputArray _kernel,
Point anchor, int iterations,
int borderType, const Scalar& borderValue )
{
Mat kernel = _kernel.getMat(); //转化为Mat类型的结构元(核)
Size ksize = kernel.data ? kernel.size() : Size(3,3); //获取结构元的大小(默认3X3)
anchor = normalizeAnchor(anchor, ksize); //归一化结构元内核
CV_Assert( anchor.inside(Rect(0, 0, ksize.width, ksize.height)) );
#if defined (HAVE_IPP) && (IPP_VERSION_MAJOR >= 7)
if( IPPMorphOp(op, _src, _dst, kernel, anchor, iterations, borderType, borderValue) )
return;
#endif
Mat src = _src.getMat();
_dst.create( src.size(), src.type() );
Mat dst = _dst.getMat();
if( iterations == 0 || kernel.rows*kernel.cols == 1 )
{
src.copyTo(dst);
return;
}
if( !kernel.data )
{
//当结构元没有数据时,生成矩形的结构元,大小为3X3,中点为(1,1)
kernel = getStructuringElement(MORPH_RECT, Size(1+iterations*2,1+iterations*2));
anchor = Point(iterations, iterations);
iterations = 1;
}
else if( iterations > 1 && countNonZero(kernel) == kernel.rows*kernel.cols )
{
anchor = Point(anchor.x*iterations, anchor.y*iterations);
kernel = getStructuringElement(MORPH_RECT,
Size(ksize.width + (iterations-1)*(ksize.width-1),
ksize.height + (iterations-1)*(ksize.height-1)),
anchor);
iterations = 1;
}
int nStripes = 1;
#if defined HAVE_TEGRA_OPTIMIZATION
if (src.data != dst.data && iterations == 1 && //NOTE: threads are not used for inplace processing
(borderType & BORDER_ISOLATED) == 0 && //TODO: check border types
src.rows >= 64 ) //NOTE: just heuristics
nStripes = 4;
#endif
parallel_for_(Range(0, nStripes),
MorphologyRunner(src, dst, nStripes, iterations, op, kernel, anchor, borderType, borderType, borderValue)); //见补充二,Range(0, nStripes)运算符重载如下:
//Ptr<FilterEngine> f = createMorphologyFilter(op, src.type(),
// kernel, anchor, borderType, borderType, borderValue );
//f->apply( src, dst );
//for( int i = 1; i < iterations; i++ )
// f->apply( dst, dst );
}
//======================见补充二======================//
class MorphologyRunner : public ParallelLoopBody
{
public:
//构造函数
MorphologyRunner(Mat _src, Mat _dst, int _nStripes, int _iterations,
int _op, Mat _kernel, Point _anchor,
int _rowBorderType, int _columnBorderType, const Scalar& _borderValue) :
borderValue(_borderValue)
{
src = _src;
dst = _dst;
nStripes = _nStripes;
iterations = _iterations;
op = _op;
kernel = _kernel;
anchor = _anchor;
rowBorderType = _rowBorderType;
columnBorderType = _columnBorderType;
}
void operator () ( const Range& range ) const
{
int row0 = min(cvRound(range.start * src.rows / nStripes), src.rows);
int row1 = min(cvRound(range.end * src.rows / nStripes), src.rows);
/*if(0)
printf("Size = (%d, %d), range[%d,%d), row0 = %d, row1 = %d\n",
src.rows, src.cols, range.start, range.end, row0, row1);*/
Mat srcStripe = src.rowRange(row0, row1);
Mat dstStripe = dst.rowRange(row0, row1);
Ptr<FilterEngine> f = createMorphologyFilter(op, src.type(), kernel, anchor,
rowBorderType, columnBorderType, borderValue ); //调用滤波器引擎
f->apply( srcStripe, dstStripe );
for( int i = 1; i < iterations; i++ )
f->apply( dstStripe, dstStripe );
}
private:
Mat src;
Mat dst;
int nStripes;
int iterations;
int op;
Mat kernel;
Point anchor;
int rowBorderType;
int columnBorderType;
Scalar borderValue;
};