• OpenCV图像处理学习十,图像的形态学操作——膨胀腐蚀


    一.形态学操作概念

    图像形态学操作是指基于形状的一系列图像处理操作的合集,主要是基于集合论基础上的形态学数学对图像进行处理。

    形态学有四个基本操作:腐蚀、膨胀、开操作、闭操作,膨胀与腐蚀是图像处理中最常用的形态学操作手段。

    二.形态学操作-膨胀

    跟卷积操作类似,假设有图像A和结构元素B,结构元素B在图像A上面移动,其中结构元素B定义其中心为锚点,计算B覆盖下A的最大像素值用来替换锚点的像素,其中B作为结构体可以是任意形状。

    膨胀的原理:

    膨胀或者腐蚀操作就是将图像(或图像的一部分区域,我们称之为图像A)与结构元素(我们称之为卷积核B)进行卷积。核可以是任何的形状和大小,拥有一个单独定义出来的参考点,我们称其为锚点(anchorpoin)。多数情况下,核是一个小的中间带有参考点和实心正方形或者圆盘,可以把核视为模板或者掩码。

    膨胀就是求局部最大值的操作,核B与图形卷积,即计算核B覆盖的区域的像素点的最大值,并把这个最大值赋值给参考点指定的像素。这样就会使图像中的高亮区域逐渐增长。

    膨胀和腐蚀操作的核心内容是结构元素。一般来说结构元素是由元素为1或者0的矩阵组成。结构元素为1的区域定义了图像的领域,领域内的像素在进行膨胀和腐蚀等形态学操作时要进行考虑。

    膨胀函数API接口:

    1. dst=cv2.dilate(
    2. InputArray src,
    3. OutputArray dst,
    4. InputArray kernel,
    5. Point anchor=Point(-1,-1),
    6. int iterations=1,
    7. int borderType=BORDER_CONSTANT,
    8. const Scalar& borderValue=morphologyDefaultBorderValue()
    9. );
    10. 参数详解:
    11. 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
    12. 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
    13. 第三个参数,InputArray类型的kernel,膨胀操作的核。若为NULL时,表示的是使用参考点位于中心3x3的核。
    14. 我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。
    15. 其中,getStructuringElement函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:
    16. 矩形: MORPH_RECT
    17. 交叉形: MORPH_CROSS
    18. 椭圆形: MORPH_ELLIPSE
    19. 而getStructuringElement函数的第二和第三个参数分别是内核的尺寸以及锚点的位置。
    20. 我们一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心。且需要注意,十字形的element形状唯一依赖于锚点的位置。而在其他情况下,锚点只是影响了形态学运算结果的偏移。
    21. getStructuringElement函数相关的调用示例代码如下:
    22. int g_nStructElementSize = 3; //结构元素(内核矩阵)的尺寸
    23. //获取自定义核
    24. Mat element = getStructuringElement(MORPH_RECT,
    25. Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),
    26. Point( g_nStructElementSize, g_nStructElementSize ));
    27. 第四个参数,Point类型的anchor,锚的位置,其有默认值(-1-1),表示锚位于中心。
    28. 第五个参数,int类型的iterations,迭代使用erode()函数的次数,默认值为1
    29. 第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
    30. 第七个参数,const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。
    31. 使用erode函数,一般我们只需要填前面的三个参数,后面的四个参数都有默认值。而且往往结合getStructuringElement一起使用。

    结构元素的API函数接口

    1. cv::Mat kernel = getStructuringElement(int shape,Size ksize,Point anchor);
    2. //返回值:返回指定形状和尺寸的结构元素
    3. //结构元素的定义:形状 (MORPH_RECT(矩形核)
    4. //MORPH_CROSS(十字交叉形核)
    5. //MORPH_ELLIPSE(椭圆形核));结构元素大小;锚点 默认是Point(-1, -1)意思就是中心像素,也可以自己指定
    6. //函数接口示例
    7. cv::Mat elementRect,elementCross,elementEllipse;
    8. elementRect = cv::getStructuringElement(cv::MORPH_RECT,cv::Size(3,3),cv::Point(-1,-1));
    9. elementCross =
    10. cv::getStructuringElement(cv::MORPH_CROSS,cv::Size(3,3),cv::Point(-1,-1));
    11. elementEllipse =
    12. cv::getStructuringElement(cv::MORPH_ELLIPSE,cv::Size(5,5),cv::Point(-1,-1));

    此外,我们也可以自定义结构元素,如下:
    使用Mat_模板类自定义5×5大小十字形、菱形、方形、x形结构元素:

    1. //自定义核(结构元素)
    2. cv::Mat_ cross(5,5);
    3. cv::Mat_ diamond(5,5);
    4. cv::Mat_ x(5,5);
    5. cv::Mat_ square(5,5);
    6. // Creating the cross-shaped structuring element
    7. cross <<
    8. 0, 0, 1, 0, 0,
    9. 0, 0, 1, 0, 0,
    10. 1, 1, 1, 1, 1,
    11. 0, 0, 1, 0, 0,
    12. 0, 0, 1, 0, 0;
    13. // Creating the diamond-shaped structuring element
    14. diamond <<
    15. 0, 0, 1, 0, 0,
    16. 0, 1, 1, 1, 0,
    17. 1, 1, 1, 1, 1,
    18. 0, 1, 1, 1, 0,
    19. 0, 0, 1, 0, 0;
    20. // Creating the x-shaped structuring element
    21. x <<
    22. 1, 0, 0, 0, 1,
    23. 0, 1, 0, 1, 0,
    24. 0, 0, 1, 0, 0,
    25. 0, 1, 0, 1, 0,
    26. 1, 0, 0, 0, 1;
    27. // Creating the square-shaped structuring element
    28. square <<
    29. 1, 1, 1, 1, 1,
    30. 1, 1, 1, 1, 1,
    31. 1, 1, 1, 1, 1,
    32. 1, 1, 1, 1, 1,
    33. 1, 1, 1, 1, 1;
    34. int xnr = x.rows;
    35. int xnl = x.cols;
    36. for(int j = 0;j
    37. {
    38. char *data = x.ptr<char>(j);
    39. for(int i = 0; i
    40. {
    41. int value = data[i];
    42. std::cout<" ";
    43. }
    44. std::cout<
    45. }

    =========================================================================

    三.形态学操作—腐蚀

    腐蚀就是清除掉图像的一些毛刺和细节,腐蚀一般可以用来消除噪点,分割出独立的图像元素等。其本质上也是一种空间滤波,设定一个掩模,掩模中心逐次滑过每一个像素点,当前像素点(即掩模中心所对应的位置)的值设为掩模覆盖区域中像素的最小值。

    腐蚀原理:

    膨胀或者腐蚀操作就是将图像(或图像的一部分区域,我们称之为图像A)与结构元素(我们称之为卷积核B)进行卷积。核可以是任何的形状和大小,拥有一个单独定义出来的参考点,我们称其为锚点(anchorpoin)。多数情况下,核是一个小的中间带有参考点和实心正方形或者圆盘,可以把核视为模板或者掩码。掩膜中心位置的像素点是否与周围领域的像素点颜色一样(即是否是白色点,即像素值是否为255),若一致,则保留,不一致则该点变为黑色(值即为0)。

    腐蚀函数API接口:

    1. dst=cv2.erode(
    2. InputArray src,
    3. OutputArray dst,
    4. InputArray kernel,
    5. Point anchor=Point(-1,-1),
    6. int iterations=1,
    7. int borderType=BORDER_CONSTANT,
    8. const Scalar& borderValue=morphologyDefaultBorderValue()
    9. );
    10. 参数说明:
    11. 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
    12. 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
    13. 第三个参数,InputArray类型的kernel,膨胀操作的核。若为NULL时,表示的是使用参考点位于中心3x3的核。
    14. 我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。
    15. 其中,getStructuringElement函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:
    16. 矩形: MORPH_RECT
    17. 交叉形: MORPH_CROSS
    18. 椭圆形: MORPH_ELLIPSE
    19. 而getStructuringElement函数的第二和第三个参数分别是内核的尺寸以及锚点的位置。
    20. 我们一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心。且需要注意,十字形的element形状唯一依赖于锚点的位置。而在其他情况下,锚点只是影响了形态学运算结果的偏移。
    21. getStructuringElement函数相关的调用示例代码如下:
    22. 调用这样之后,我们便可以在接下来调用erode或dilate函数时,第三个参数填保存了getStructuringElement返回值的Mat类型变量。对应于我们上面的示例,就是填element变量。
    23. 第四个参数,Point类型的anchor,锚的位置,其有默认值(-1-1),表示锚位于中心。
    24. 第五个参数,int类型的iterations,迭代使用erode()函数的次数,默认值为1
    25. 第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
    26. 第七个参数,const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。
    27. 使用erode函数,一般我们只需要填前面的三个参数,后面的四个参数都有默认值。而且往往结合getStructuringElement一起使用。

    腐蚀的具体操作是:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为1,则该像素为1,否则为0。

    膨胀的具体操作是:用一个结构元素(一般是3×3的大小)扫描图像中的每一个像素,用结构元素中的每一个像素与其覆盖的像素做“与”操作,如果都为0,则该像素为0,否则为1。

    =========================================================================

    代码实现:

    1. #include"stdafx.h"
    2. #include
    3. #include
    4. #include
    5. using namespace cv;
    6. using namespace std;
    7. int _tmain(int argc, _TCHAR* argv[])
    8. {
    9. Mat image1 = imread("F:/photo/qx.jpg", 1);
    10. namedWindow("input_picture1");
    11. imshow("input_picture1", image1);
    12. Mat image2;
    13. Mat image3;
    14. cvtColor(image1, image2, COLOR_RGB2GRAY);
    15. namedWindow("input_picture2");
    16. imshow("input_picture2", image2);
    17. threshold(image2, image3, 65, 255, THRESH_BINARY);
    18. namedWindow("input_picture3");
    19. imshow("input_picture3", image3);
    20. Mat eroded;
    21. erode(image3, eroded, Mat());
    22. namedWindow("erode");
    23. imshow("erode", eroded);
    24. Mat dilated;
    25. dilate(image3, dilated, Mat());
    26. namedWindow("dilate");
    27. imshow("dilate", dilated);
    28. waitKey(0);
    29. return 0;
    30. }

    图像处理效果:

    原图和灰度图

    灰度图和二值化图: 

     二值化图像腐蚀膨胀效果:

  • 相关阅读:
    掌握源码,轻松搭建:一站式建站系统源码 附完整搭建步骤与教程
    你知道防抖和节流与闭包的关系吗?
    Python:实现radix sort基数排序算法(附完整源码)
    Java常用工具环境安装手册(持续更新)
    解决“yarn : 无法加载文件 C:Progr Files\nodejs yarn.ps1,因为在此系统上禁止运行脚本的问题-使用命令更改计算机的执行策略
    联盟快应用-如何进行测试?
    积分商城可设置的四种兑换商品类型
    面试高频问题----2
    Nacos Docker部署步骤
    用户留存为何重要?
  • 原文地址:https://blog.csdn.net/weixin_44651073/article/details/126321876