OpenCV二值图像分析之形态学应用技巧

  • 2020 年 2 月 21 日
  • 筆記

引言

前两天刚写了一篇二值图像分析之轮廓发现与轮廓属性分析的相关文章,得到大家比较好反馈,感谢大家支持,让我有勇气继续再写下去,二值图像分析还有一块核心技能就是图像形态学操作技巧,这里也打算根据我自己的项目经验,给大家吐槽总结一下,希望大家多提宝贵意见,不足之处多多补充!

形态学操作与相关函数

OpenCV中支持的图像形态学操作主要有膨胀、腐蚀、开操作、闭操作、顶帽操作、黑帽操作、形态学梯度操作,涉及的相关API函数主要有如下几个:

腐蚀操作函数:

void cv::erode(  InputArray      src,  OutputArray   dst,  InputArray      kernel,  Point       anchor = Point(-1,-1),  int   iterations = 1,  int   borderType = BORDER_CONSTANT,  const Scalar &        borderValue = morphologyDefaultBorderValue()  )

膨胀操作函数:

void cv::dilate(      InputArray      src,      OutputArray   dst,      InputArray      kernel,      Point       anchor = Point(-1,-1),      int   iterations = 1,      int   borderType = BORDER_CONSTANT,      const Scalar &        borderValue = morphologyDefaultBorderValue()  )

腐蚀跟膨胀两个函数的高度相似,唯一不同的函数运行输出结果不一样。参数解释如下:

  • src 输入图像、灰度或者彩色均可
  • dst 输出图像、跟输入图像格式与类型相同
  • kernel 结构元素、决定输出图像样式
  • anchor 锚定位置、是针对结构元素来说的
  • iterations 循环次数、意思是连续多次操作(腐蚀/膨胀)
  • borderType 边缘处理、边缘处理的方式,这个以前也详细的讲过,这里不废话了
  • borderValue 只有在选择DEFAULT_BORDER的时候才会用。

获取结构元素:

Mat cv::getStructuringElement(      int   shape,      Size ksize,      Point anchor = Point(-1,-1)  )

参数解释:

  • shape:是指结构元素的形状,常见的有矩形、圆形、十字交叉、线
  • ksize:是指结构元素的大小
  • anchor:是指结构元素锚定的位置、Point(-1,-1)表示默认锚定位置为结构元素中心

形态学操作函数:

void cv::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()  )

该函数通过其中操作(op)参数来实现OpenCV支持全部形态学操作、当然包括腐蚀与膨胀、所以可以忘记腐蚀跟膨胀单独的函数表达了。该函数与腐蚀/膨胀函数相比,多出唯一参数是op操作,当前支持的操作包括如下:

MORPH_ERODE  腐蚀  MORPH_DILATE  膨胀  MORPH_OPEN  开操作  MORPH_CLOSE  闭操作  MORPH_GRADIENT 形态学梯度  MORPH_TOPHAT 顶帽操作  MORPH_BLACKHAT 黑帽操作  MORPH_HITMISS 击中击不中

形态学应用场景

这里结合每个形态学操作,给出了每个操作的应用场景与效果演示。简单的腐蚀与膨胀操作,实现区域分离与合并

原图(图-1):

使用15×15的圆形结构元素膨胀之后:(图-2)

使用相同的结构元素,对图-1进行腐蚀之后:(图-3)

可见使用15×15圆形结构元素腐蚀之后,图中所有的对象已经被擦除了。

原图(图-4):

开操作

开操作可以去除小的干扰块,开操作结构元素:7×7矩形,开操作之后(图-5)

可见已经删除一些小的干扰块跟白色像素点了。

闭操作

闭操作可以填充空洞区域,比如图-4中白色矩形内部黑色部分小矩形,通过闭操作可以完成填充,使用11×11的矩形结构元素,操作之后(图-6):

可见图中黑色矩形区域已经填充完成。

有时候我只对这些很小区域感兴趣,特别是在工业检测中,很多都是微小的瑕疵或者斑点,常规方法很能提取到,这个时候我们通过下面两个形态学操作可以实现对这些小干扰块/瑕疵区域的提取,原图如下(图-7):

这个图是来自知识星球一位会员的提问,他想提取那个小白色斑点,并测量它的大小与面积,采用顶帽操作即可获取,顶帽操作的定义为原图 减去 开操作结果,只要给一个合适的结构元素,即可提取到斑点区域, 顶帽操作之后,会有一些边缘线,通过开操作删去,最终得到的结果如下:(图-8)

很完美的得到图像白色斑点区域了。

除了顶帽操作,另外还有一个黑帽操作,它的定义为闭操作的结果减去原图,对图-4实现黑帽操作就可以得到白色矩形中黑色小矩形块,结果如下:(图-9)

所以顶帽跟黑帽是非常有用的两个操作,特别是在二值图像分析中需要提取一些比较小Blob对象场景中。

形态学梯度

使用形态学梯度可以完整的提取一些对象边缘跟轮廓,在一些应用场景中非常适用。举例,原图如下:(图-10)

基于形态学梯度提取内外轮廓,得到的边缘图像如下:(图-11)

代码都很简单,基本都是API函数直接调用,这里就不贴出来献丑了,主要是告诉大家如何利用OpenCV提供函数灵活运用,每个函数都有着自己合适的应用场景,形态学的各种不同结构元素跟操作有时候会给你带来非常好的图像处理效果,直接可以服务后续的对象检测与测量、识别等环节。实现上述形态学处理的关键代码就三行,如下:

Mat src = imread("D:/images/morph.png");  se = getStructuringElement(MORPH_RECT, Size(7, 7), Point(-1, -1));  morphologyEx(src, dst, MORPH_OPEN, se);

主要靠这三行,解释一下!先要二值化、然后找到合适的结构元素,然后执行对应的形态学操作,代码中是开操作!请千万别注意一下!