《opencv学习笔记》-- 形态学滤波:形态学梯度、开运算、闭运算、顶帽、黑帽

形态学梯度

膨胀图与腐蚀图之差。

gradient(src, element) =  dilate(src, element) - erode(src, element)

形态学梯度可以用来保留物体的边缘轮廓。

二值图像进行这一操作可以将团块的边缘突出出来

可以使用减法函数(subtract())或者 morphologyEx函数进行形态学梯度操作。

减法函数:

void subtract( InputArray src1,
            InputArray src2,
            OutputArray dst,
            InputArray mask = noArray(),
            int dtype = -1);

参数1,InputArray类型,一般是cv::Mat,被减数;

参数2,InputArray类型,一般是cv::Mat,减数;

参数3,OutputArray类型,输出的目标图像,和原图像有一样的尺寸和类型;

参数4,掩码可选操作掩码;这是一个8位单通道数组,指定元素;要更改的输出数组;

参数5,数据类型输出阵列的可选深度;

dst = src1 - src2

morphologyEx函数:modules\imgproc\src\morph.cpp

void morphologyEx(InputArray src, OutputArray dst, int op,
                  InputArray kernel, Point anchor = Point(-1,-1), 
                  int iterations=1, int borderType = BORDER_CONSTANT,
                  const Scalar& borderValue = morphologyDefaultBorderValue() );

参数1,输入图像,填Mat类的对象。图像位深应该为:CV_8U, CV_16U,CV_16S, CV_32F               或CV_64F。

参数2,目标图像,需要和源图片有一样的尺寸和类型。

参数3,表示形态学运算的类型,可以是以下标识符:

                MORPH_OPEN          ---  开运算(Opening operation)

                MORPH_CLOSE        ---  闭运算(Closing operation)

                MORPH_GRADIENT  ---  形态学梯度(Morphological gradient)

                MORPH_TOPHAT      ---  顶帽(Top hat)

                MORPH_BLACKHAT  ---  黑帽(Black hat)

参数4,形态学运算的内核。若为NULL时,表示的是使用参考点位于中心3x3的核。

           一般使用函数 getStructuringElement配合这个参数的使用。

           getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)

参数5,锚的位置,默认值Point(-1,-1),表示锚位于中心。

参数6,迭代使用函数的次数,默认值为1。

参数7,用于推断图像外部像素的某种边界模式。默认值BORDER_ CONSTANT。

参数8,当边界为常数时的边界值,默认值morphologyDefaultBorderValue(),

            使用时,可以看官方文档createMorphologyFilter()函数。

源码:

void morphologyEx( InputArray _src, OutputArray _dst, int op,
                       InputArray _kernel, Point anchor, int iterations,
                       int borderType, const Scalar& borderValue )
{
    CV_INSTRUMENT_REGION();

    CV_Assert(!_src.empty());

    Mat kernel = _kernel.getMat();
    if (kernel.empty())
    {
        kernel = getStructuringElement(MORPH_RECT, Size(3,3), Point(1,1));
    }
#ifdef HAVE_OPENCL
    Size ksize = kernel.size();
    anchor = normalizeAnchor(anchor, ksize);

    CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 && _src.channels() <= 4 &&
        anchor.x == ksize.width >> 1 && anchor.y == ksize.height >> 1 &&
        borderType == cv::BORDER_CONSTANT && borderValue == morphologyDefaultBorderValue(),
        ocl_morphologyEx(_src, _dst, op, kernel, anchor, iterations, borderType, borderValue))
#endif

    Mat src = _src.getMat(), temp;
    _dst.create(src.size(), src.type());
    Mat dst = _dst.getMat();

#if !IPP_DISABLE_MORPH_ADV
    //CV_IPP_RUN_FAST(ipp_morphologyEx(op, src, dst, kernel, anchor, iterations, borderType, borderValue));
#endif

    switch( op )
    {
    case MORPH_ERODE:
        erode( src, dst, kernel, anchor, iterations, borderType, borderValue );
        break;
    case MORPH_DILATE:
        dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
        break;
    case MORPH_OPEN:
        erode( src, dst, kernel, anchor, iterations, borderType, borderValue );
        dilate( dst, dst, kernel, anchor, iterations, borderType, borderValue );
        break;
    case MORPH_CLOSE:
        dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
        erode( dst, dst, kernel, anchor, iterations, borderType, borderValue );
        break;
    case MORPH_GRADIENT:
        erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
        dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
        dst -= temp;
        break;
    case MORPH_TOPHAT:
        if( src.data != dst.data )
            temp = dst;
        erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
        dilate( temp, temp, kernel, anchor, iterations, borderType, borderValue );
        dst = src - temp;
        break;
    case MORPH_BLACKHAT:
        if( src.data != dst.data )
            temp = dst;
        dilate( src, temp, kernel, anchor, iterations, borderType, borderValue );
        erode( temp, temp, kernel, anchor, iterations, borderType, borderValue );
        dst = temp - src;
        break;
    case MORPH_HITMISS:
        CV_Assert(src.type() == CV_8UC1);
        if(countNonZero(kernel) <=0)
        {
            src.copyTo(dst);
            break;
        }
        {
            Mat k1, k2, e1, e2;
            k1 = (kernel == 1);
            k2 = (kernel == -1);

            if (countNonZero(k1) <= 0)
                e1 = Mat(src.size(), src.type(), Scalar(255));
            else
                erode(src, e1, k1, anchor, iterations, borderType, borderValue);

            if (countNonZero(k2) <= 0)
                e2 = Mat(src.size(), src.type(), Scalar(255));
            else
            {
                Mat src_complement;
                bitwise_not(src, src_complement);
                erode(src_complement, e2, k2, anchor, iterations, borderType, borderValue);
            }
            dst = e1 & e2;
        }
        break;
    default:
        CV_Error( CV_StsBadArg, "unknown morphological operation" );
    }
}

}

开运算

开运算是先腐蚀后膨胀的过程。dst = open(src, element) = dilate(erode(src, element));

可以用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。结果是放大了裂缝或者局部低亮度的区域。

闭运算

闭运算是先膨胀后腐蚀的过程。dst = close(src, element) = erode(dilate(src, element));

闭运算能够排除小型黑洞(黑色区域)

顶帽

用来分离比邻近点亮一些的斑块。

原图像与“开运算“的结果图之差。dst = tophat(src, element) = src - open(src, element)

效果图突出了比原图轮廓周围的区域更明亮的区域

应用场景:

当一幅图像具有大幅的背景的时候,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取。

黑帽

“闭运算”的结果图与原图像之差。dst = blackhat(src,  element) = close(src,  element) - src

效果图突出了比原图轮廓周围的区域更暗的区域,且这一操作和选择的核的大小相关

黑帽运算用来分离比邻近点暗一些的斑块

你可能感兴趣的:(opencv,opencv)