【OpenCV 4开发详解】图像腐蚀

小白学视觉”,选择“星标”公众号

重磅干货,第一时间送达

经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。

图像的腐蚀过程与图像的卷积操作类似,都需要模板矩阵来控制运算的结果,在图像的腐蚀和膨胀中这个模板矩阵被称为结构元素。与图像卷积相同,结构元素可以任意指定图像的中心点,并且结构元素的尺寸和具体内容都可以根据需求自己定义。定义结构元素之后,将结构元素的中心点依次放到图像中每一个非0元素处,如果此时结构元素内所有的元素所覆盖的图像像素值均不为0,则保留结构元素中心点对应的图像像素,否则将删除结构元素中心点对应的像素。图像的腐蚀过程示意图如图6-12所示,图6-12中左侧为待腐蚀的原图像,中间为结构元素,首先将结构元素的中心与原图像中的A像素重合,此时结构元素中心点的左侧和上方元素所覆盖的图像像素值均为0,因此需要将原图像中的A像素删除;当把结构元素的中心点与B像素重合时,此时结构元素中所有的元素所覆盖的图像像素值均为1,因此保留原图像中的B像素。将结构元素中心点依次与原图像中的每个像素重合,判断每一个像素点是否保留或者删除,最终原图像腐蚀的结果如图6-12中右侧图像所示。

图6-12 图像腐蚀结果示意图

图像腐蚀可以用“”表示,其数学表示形式如式(6.4)所示,通过公式可以发现,其实对图像A的腐蚀运算就是寻找图像中能够将结构元素B全部包含的像素点。

图像腐蚀过程中使用的结构元素可以根据需求自己生成,但是为了研究人员的使用方便,OpenCV 4提供了getStructuringElement()函数用于生成常用的矩形结构元素、十字结构元素和椭圆结构元素。该函数的函数原型在代码清单6-10中给出。

代码清单6-10 getStructuringElement()函数原型1.Mat cv::getStructuringElement(int shape,2.                              Size  ksize,3. Point anchor = Point(-1,-1) 4.                              )
  • shape:结构元素的种类,可以选择的参数及含义在表6-5中给出。
  • ksize:结构元素的尺寸大小
  • anchor:中心点的位置,默认参数为结构元素的几何中心点。

该函数用于生成图像形态学操作中常用的矩形结构元素、十字结构元素和椭圆结构元素。函数第一个参数为生成结构元素的种类,可以选择的参数及含义在表6-5给出,函数第二个参数是结构元素的尺寸大小,能够影响到图像腐蚀的效果,一般情况下,结构元素的种类相同时,结构元素的尺寸越大腐蚀效果越明显。函数的最后一个参数是结构元素的中心点,只有十字结构元素的中心点位置会影响图像腐蚀后的轮廓形状,其他种类的结构元素的中心点位置只影响形态学操作结果的平移量。

表6-5 getStructuringElement()函数结构元素形状可选择参数

标志参数 简记 作用
MORPH_RECT 0 矩形结构元素,所有元素都为1
MORPH_CROSS 1 十字结构元素,中间的列和行元素为1
MORPH_ELLIPSE 2 椭圆结构元素,矩形的椭圆内接元素为1

OpenCV 4提供了用于图像腐蚀的erode()函数,该函数的函数原型在代码清单6-11中给出。

代码清单6-11 erode()图像腐蚀1.void cv::erode(InputArray  src,2.               OutputArray  dst,3. InputArray kernel,4. Point anchor = Point(-1,-1),5. int iterations = 1,6. int borderType = BORDER_CONSTANT,7. const Scalar & borderValue = morphologyDefaultBorderValue() 8. )
  • src:输入的待腐蚀图像,图像的通道数可以是任意的,但是图像的数据类型必须是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一。
  • dst:腐蚀后的输出图像,与输入图像src具有相同的尺寸和数据类型。
  • kernel:用于腐蚀操作的结构元素,可以自己定义,也可以用getStructuringElement()函数生成。
  • anchor:中心点在结构元素中的位置,默认参数为结构元素的几何中心点
  • iterations:腐蚀的次数,默认值为1。
  • borderType:像素外推法选择标志,取值范围在表3-5中给出。默认参数为BORDER_DEFAULT,表示不包含边界值倒序填充。
  • borderValue:使用边界不变外推法时的边界值。

该函数根据结构元素对输入图像进行腐蚀,在腐蚀多通道图像时每个通道独立进行腐蚀运算。函数的第一个参数为待腐蚀的图像,图像通道数可以是任意的,但是图像的数据类型必须是CV_8U,CV_16U,CV_16S,CV_32F或CV_64F之一。函数第二个参数为腐蚀后的输出图像,与输入图像具有相同的尺寸和数据类型。函数第三个和第四个参数都是与结构元素相关的参数,第三个参数为结构元素,第四个参数为结构元素的中心位置,第四个参数的默认值为Point(-1,-1),表示结构元素的几何中心处为结构元素的中心点。函数第五个参数是使用结构元素腐蚀的次数,腐蚀次数越多效果越明显,参数默认值为1,表示只腐蚀1次。函数第六个参数是图像像素外推法的选择标志,第七个参数为使用边界不变外推法时的边界值,这两个参数对图像中主要部分的腐蚀操作没有影响,因此在多数情况下使用默认值即可。

需要注意的是该函数的腐蚀过程只针对图像中的非0像素,因此如果图像是以0像素为背景,那么腐蚀操作后会看到图像中的内容变得更瘦更小;如果图像是以255像素为背景,那么腐蚀操作后会看到图像中的内容变得更粗更大。

为了更加了解图像腐蚀的效果以及erode()函数的使用方法,在代码清单6-12中给出了对图6-12中的原图像进行腐蚀的示例程序,程序运行结果如图6-13所示。在程序中分别利用矩形结构元素和十字结构元素对像素值为0做背景的图像和像素值为255做背景的图像进行腐蚀,结果在图6-14、图6-15给出。最后利用图像腐蚀操作对代码清单6-6中二值化后的图像进行滤波,之后统计连通域个数,实现对原图像中的米粒进行计数,程序运行结果在图6-16给出。通过结果可以发现,腐蚀操作可以去除由噪声引起的较小的连通域,得到了正确的米粒数。

代码清单6-12 myErode.cpp图像腐蚀1.#include <opencv2\opencv.hpp>2.#include <iostream>3.#include <vector>4.5.using namespace cv;6.using namespace std;7.//绘制包含区域函数8.void drawState(Mat &img, int number, Mat centroids, Mat stats, String str) {9. RNG rng(10086);10 vector<Vec3b> colors;11. for (int i = 0; i < number; i++)12. {13. //使用均匀分布的随机数确定颜色14. Vec3b vec3 = Vec3b(rng.uniform(0,256),rng.uniform(0,256),rng.uniform(0,256));15. colors.push_back(vec3);16. }17.18. for (int i = 1; i < number; i++)19. {20. // 中心位置21. int center_x = centroids.at<double>(i, 0);22. int center_y = centroids.at<double>(i, 1);23. //矩形边框24. int x = stats.at<int>(i, CC_STAT_LEFT);25. int y = stats.at<int>(i, CC_STAT_TOP);26. int w = stats.at<int>(i, CC_STAT_WIDTH);27. int h = stats.at<int>(i, CC_STAT_HEIGHT);28.29. // 中心位置绘制30. circle(img, Point(center_x, center_y), 2, Scalar(0, 255, 0), 2, 8, 0);31. // 外接矩形32. Rect rect(x, y, w, h);33. rectangle(img, rect, colors[i], 1, 8, 0);34. putText(img, format("%d", i), Point(center_x, center_y),35. FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);36. }37. imshow(str, img);38.}39.40.int main()41.{42. //生成用于腐蚀的原图像43. Mat src = (Mat_<uchar>(6, 6) << 0, 0, 0, 0, 255, 0,44. 0, 255, 255, 255, 255, 255,45. 0, 255, 255, 255, 255, 0,46. 0, 255, 255, 255, 255, 0,47. 0, 255, 255, 255, 255, 0,48. 0, 0, 0, 0, 0, 0);49. Mat struct1, struct2;50. struct1 = getStructuringElement(0, Size(3, 3));  //矩形结构元素51. struct2 = getStructuringElement(1, Size(3, 3));  //十字结构元素52.53. Mat erodeSrc;  //存放腐蚀后的图像54. erode(src, erodeSrc, struct2);55. namedWindow("src", WINDOW_GUI_NORMAL);56. namedWindow("erodeSrc", WINDOW_GUI_NORMAL);57. imshow("src", src);58. imshow("erodeSrc", erodeSrc);59.60.  Mat LearnCV_black = imread("LearnCV_black.png", IMREAD_ANYCOLOR);61. Mat LearnCV_write = imread("LearnCV_write.png", IMREAD_ANYCOLOR);62. Mat erode_black1, erode_black2, erode_write1, erode_write2;63. //黑背景图像腐蚀64. erode(LearnCV_black, erode_black1, struct1);65. erode(LearnCV_black, erode_black2, struct2);66. imshow("LearnCV_black", LearnCV_black);67. imshow("erode_black1", erode_black1);68. imshow("erode_black2", erode_black2);69.70. //白背景腐蚀71. erode(LearnCV_write, erode_write1, struct1);72. erode(LearnCV_write, erode_write2, struct2);73. imshow("LearnCV_write", LearnCV_write);74. imshow("erode_write1", erode_write1);75. imshow("erode_write2", erode_write2);76.77. //验证腐蚀对小连通域的去除78. Mat img = imread("rice.png");79. Mat img2;80. copyTo(img, img2, img);  //克隆一个单独的图像,用于后期图像绘制81. Mat rice, riceBW;82.83. //将图像转成二值图像,用于统计连通域84. cvtColor(img, rice, COLOR_BGR2GRAY);85. threshold(rice, riceBW, 50, 255, THRESH_BINARY);86.87. Mat out, stats, centroids;88. //统计图像中连通域的个数89. int number = connectedComponentsWithStats(riceBW, out, stats,centroids,8,CV_16U);90. drawState(img, number, centroids, stats, "未腐蚀时统计连通域");  //绘制图像91.92. erode(riceBW, riceBW, struct1);  //对图像进行腐蚀93. number = connectedComponentsWithStats(riceBW, out, stats, centroids, 8, CV_16U);94. drawState(img2, number, centroids, stats, "腐蚀后统计连通域");  //绘制图像95.96. waitKey(0);97. return 0;98.}

图6-13 用十字结构元素腐蚀示例

图6-14 myErode.cpp程序中黑背景图像腐蚀结果

图6-15 myErode.cpp程序中白背景图像腐蚀结果

图6-16 myErode.cpp程序中对米粒图像腐蚀后统计连通域结果

(0)

相关推荐

  • Python进阶——OpenCV之GUI

    文章目录 图像处理(Getting Started with Images) 读取图像 显示图像 保存图像 使用Matplotlib 视频处理(Getting Started with Videos) ...

  • python+opencv图像处理(十)

    图像旋转 本篇主要利用opencv的转换函数warpAffine实现图像的平移和旋转. 1.图像旋转 图像旋转即是根据某个中心点进行旋转. 要进行旋转,要找到中心点,要知道旋转角度,opencv提供了 ...

  • python+opencv图像处理(十一)

    图像镜像 图像的镜像指的是将图像以某条线为中心进行镜像对换. 图像的镜像根据翻转的方向可分为水平镜像翻转.垂直镜像翻转和对角镜像翻转3种. 水平镜像翻转指的是将图像以y轴为中心进行左右镜像对换. 垂直 ...

  • [OpenCV]经典霍夫变换原理

    本文主要讲述的是霍夫变换的一些内容,并加入一些在生活中的应用,希望能对读者对于霍夫变换的内容有所了解. 首先我先说的是,霍夫变换是一个特征提取技术.其可用于隔离图像中特定形状的特征的技术,应用在图像分 ...

  • 【OpenCV 4开发详解】图像连通域分析

    小白学视觉",选择"星标"公众号 重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<OpenCV 4开发详解>.为 ...

  • 【OpenCV 4开发详解】直方图应用

    直方图不仅能够表示图像像素的统计特性,应用统计的直方图结果也可以增强图像的对比度,在图像中寻找相似区域等.本节中将重点介绍如果通过调整直方图分布提高图像的对比度.利用直方图反向投影寻找相同区域以及将图 ...

  • 【OpenCV 4开发详解】形态学应用

    重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<OpenCV 4开发详解>.为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通 ...

  • 知荐 | 基于视觉系统的ADAS横向开发详解

    自动驾驶2级以上包含了对横向控制的不同算法策略,包含对中控制.纠偏控制及预警控制,涉及不同范围的功能,如车道保持辅助LKA/紧急车道保持ELK.交通拥堵辅助/高速集成式巡航TJAICA.车道偏离预警L ...

  • iMX8MQ MCUXpresso SDK开发详解

    飞凌iMX8MQ 平台内部有一个Cortex M4内核,支持使用MCUXpresso SDK进行开发. MCUXpresso SDK是微控制器软件支持的集合,它包含外围驱动程序,RPMSG多核通信,以 ...

  • 【精品博文】《FPGA设计技巧与案例开发详解》初探(二)之工程文件管理

    对于彬哥书中所提到的工程文件管理,由于只给了一个框架,简要介绍了各个文件夹的作用,进而有许多初学者不知道具体怎么操作,会在群里问这类问题.下面,我将详细介绍一下如何构建彬哥的工程目录. 首先,我还是简 ...

  • 【精品博文】《FPGA设计技巧与案例开发详解(第二版)》上线

    呕心沥血几春秋,携友再创第二版,<FPGA设计技巧与案例开发详解>,在去年经历了<FPGA设计技巧与案例开发详解>第一版的各种风风雨雨后,我们响应广大网友与高校学生的号召,精心 ...

  • BMP图像数据格式详解

    一.简介 BMP(Bitmap-File)图形文件是Windows采用的图形文件格式,在Windows环境下运行的所有图象处理软件都支持BMP图象文件格式.Windows系统内部各图像绘制操作都是以B ...