提示:文章参考了网络上其他作者的文章,以及相关书籍,如有侵权,请联系作者。


前言

       图像的形态学处理是对图像的局部像素进行处理,用于从图像中提取有意义的局部图像细节。通过改变局部区域的像素形态,以对目标进行增强,或者为后续进行图像分割、特征提取、边缘检测等操作做准备。
       图像的形态学处理包含如下内容。
在这里插入图片描述
       在开始之前,我们先了解一下:结构元素:StructElement。结构元素在算子参数中的名称为StructElement,在腐蚀与膨胀操作中都需要用到。结构元素是类似于“滤波核”的元素,或者说类似于一个“小窗”,在原图上进行“滑动”,这就是结构元素,可以指定其形状和大小。结构元素一般由0和1的二值像素组成。结构元素的原点相当于“小窗”的中心,其尺寸由具体的腐蚀或膨胀算子指定,结构元素的尺寸也决定着腐蚀或者膨胀的程度。结构元素越大,被腐蚀消失或者被膨胀增加的区域也会越大。
       结构元素的形状可以根据操作的需求进行创建,可以是圆形、矩形、椭圆形,甚至是指定的多边形等。可以通过gen_circle、gen_rectanglel、gen_ellipse、gen_region_polygon等算子创建需要的形状并指定尺寸。


一、腐蚀和膨胀

       在经阈值处理提取出目标区域的二值图像之后,区域边缘可能并不理想,这时可以使用腐蚀或使膨胀操作对区域进行“收缩”或“扩张”。

1.腐蚀

       腐蚀操作是对所选区域进行“收缩”的一种操作,可以用于消除边缘和杂点。腐蚀区域的大小与结构元素的大小和形状相关。其原理是使用一个自定义的结构元素,如矩形、圆形等,在二值图像上进行类似于“滤波”的滑动操作,然后将二值图像对应的像素点与结构元素的像素进行对比,得到的交集(进行“与”操作)即为腐蚀后的图像像素。左图为二值化后的图像,右图为使用中间的结构元素对图像进行腐蚀,得到的结果为“收缩”了一圈的图像。
在这里插入图片描述
       经过腐蚀操作,图像区域的边缘可能会变得平滑,区域的像素将会减少,相连的部分可能会断开。即使如此,各部分仍然属于同一个区域。
       Halcon中有许多与腐蚀操作相关的算子,比较常用的有erosion_circle 算子和erosion rectangle1算子,它们分别使用圆形与矩形结构元素对输入区域进行腐蚀操作。这里以erosion_circle算子为例进行说明。erosion_circle算子的原型如下:

    erosion_circle(Region : RegionErosion : Radius :)

       其中各参数的含义如下。
       1)、参数1:Region为输入图像中的区域,该区域往往是由上一环节的某种分割操作得到的输出结果,如阈值处理提取的区域等。
       2)、参数2:RegionErosion为输出的腐蚀后的区域。
       3)、参数3:Radius为圆形结构元素的半径。其具体值取与想要被去除的杂点的大小有关。因为小于这个圆形结构元素的点都会被移除,而该圆形的直径一般是一个奇数,如3、5、7、9等,所以该半径取值一般会取1.5、2.5、3.5、4.5······默认值是3.5。
       注意:圆形的直径取奇数是因为圆形是对称图形,这样做是为了使圆形的中心点坐标为整数。
       下面以一个简单的例子来说明腐蚀操作。下图左图即原始图像,为一幅背景较为复杂的图像。目标是提取较大的面积芯片区域。因此,可以先将图像转化为单通道灰度图像,并使用阈值进行简单的灰度分割。阈值分割图像如中图所示。在满足条件的区域使用erosion_circle 算子移除杂点,erosion_circle算子的输入区域为中图的红色部分,腐蚀的结果如下图右图所示。
在这里插入图片描述
       上图腐蚀操作的代码如下:

read_image(Image, 'board_erosion')
rgb1_to_gray(Image, GrayImage)
threshold(GrayImage, Region, 100, 255)
erosion_circle(Region, RegionErosion, 7.5)
erosion_circle(RegionErosion, RegionErosion2, 6.5)
dev_clear_window()
dev_display(RegionErosion2)

       因为经阈值处理后,图像中会包含背景中的许多杂点和非关键区域,所以这里通过腐蚀操作移除杂点,并且在腐蚀的结果上进行重复腐蚀,以达到理想的结果。腐蚀操作很容易让图像中出现“空洞”,因此可以使用膨胀或者闭运算进行后续处理。
       上文提到的erosion_circle算子是使用圆形结构元素进行腐蚀操作,还可以选择其他形状的结构元素,如erosion_rectangle1 算子是使用矩形结构元素进行腐蚀,用法与erosion_circle 算子类似;也可以使用自定义的结构元素或者其他方式。Halcon中与腐蚀有关的其他算子如下。
       1)、erosion1:用一个自定义的结构元素对输入区域进行腐蚀操作。这个自定义的结构元素需要预先创建,可能是圆形、矩形、多边形,甚至是点,等等。
       2)、erosion2:使用一个参考点对输入区域进行腐蚀操作。这个算子中的结构元素有一个参考点,这个点与erosion1中的点不同,它可以是指定的任意一点。
       3)、erosion_golay:使用的结构元素来自格雷字母表,通过定义结构元素对输入区域进行腐蚀操作。
       4)、erosion_seq:与erosion_golay类似,使用格雷字母表中的元素对输入区域进行连续的腐蚀操作。

2.膨胀

       与腐蚀相反,膨胀是对选区进行“扩大”的一种操作。其原理是使用一个自定义的结构元素,在待处理的二值图像上进行类似于“滤波”的滑动操作,然后将二值图像对应的像素点与结构元素的像素进行对比,得到的并集(进行“或”操作)为膨胀后的图像像素。下面左图为二值化之后的图像,使用一个圆形结构元素对图像进行膨胀操作,如中图所示,得到的结果为“膨胀”了一圈的图像,如右图所示。
在这里插入图片描述
       经过膨胀操作,图像区域的边缘可能会变得平滑,区域的像素将会增加,不相连的部分可能会连接起来,这些都与腐蚀操作正好相反。即使如此,原本不相连的区域仍然属于各自的区域,不会因为像素重叠就发生合并。
       注意:膨胀后发生重叠的区域可以用opening_seq算子分离开来。
       Halcon中有许多与膨胀操作相关的算子,比较常用的有dilation_circle算子和dilation_rectangle1算子,它们分别使用圆形与矩形结构元素对输入区域进行膨胀操作。这里以dilation_circle算子为例进行说明。dilation_circle 算子的原型如下:

    dilation circle(Region : RegionDilation : Radius :)

       其中各参数的含义如下。
       1)、参数1:Region为输入的区域。
       2)、参数2:RegionDilation为输出的膨胀后的区域。
       3)、参数3:Radius为圆形结构元素的半径,该半径的大小决定了膨胀的程度。其具体取值与待填补的空洞大小有关。该半径默认值依然是3.5。
       下面以一个简单的例子来说明膨胀操作。下面中图中的红色部分即输入区域,也就是上文中的膨胀操作提取出的区域。下面左图为一幅背景较为复杂的图像,目标是提取芯片区域,因此可以先将图像转化为单通道灰度图像,并使用阈值进行简单的灰度分割。阈值分割图像如中图所示,可见该区域有许多因为过度腐蚀而产生的“空洞”。接下来在该区域使用dilation_circle算子填补满足尺寸条件的小洞,得到的膨胀效果如右图所示。
在这里插入图片描述
       上图针对腐蚀后的区域进行膨胀操作的代码如下:

read_image(Image, 'board_erosion&dilation')
rgb1_to_gray(Image, GrayImage)
threshold(GrayImage, Region, 100, 255)
gen_image_proto(GrayImage, ImageCleared, 0)
erosion_circle(Region, RegionErosion, 7.5)
erosion_circle(RegionErosion, RegionErosion2, 6.5)
erosion_circle(RegionErosion2, RegionErosion3, 5.5)
*膨胀操作
dilation_circle(RegionErosion3, RegionDilation, 23.5)
dev_clear_window()
dev_display(RegionDilation)

       在最后一行使用膨胀算子,其中膨胀算子中的圆形结构元素半径可根据空洞的大小和需要的填补效果进行调节。
       经过阈值处理或腐蚀操作后,图像中包含了许多小空隙,为了使提取出的区域尽量完整,这里通过膨胀操作来填补空隙。根据膨胀的实际效果,可能还需要进行平滑边缘等处理,可以选择使用闭运算进行后续处理。
       除了上文提到的 dilation_circle 和 dilation_rectangle1 算子外,在Halcon中还可以使用其他方式进行膨胀操作。与膨胀有关的其他算子如下。
       1)、dilation1:用一个自定义的结构元素对输入区域进行膨胀操作。结构元素需要预先创建好,这个自定义的结构元素可能是圆形、矩形、多边形,甚至是点,等等。
       2)、dilation2:使用一个参考点对输入区域进行膨胀操作。这个算子中的结构元素有一个参考点,这个点与dilation1中的点不同,这个参考点可以是指定的任意一点。
       3)、dilation_golay:使用的结构元素来自格雷字母表,通过定义结构元素对输入区域进行膨胀操作。
       4)、dilation_seq:与dilation_golay类似,使用格雷字母表中的元素对输入区域进行连续的膨胀操作。

二、开运算和闭运算

       腐蚀与膨胀是形态学运算的基础,在实际检测的过程中,常常需要组合运用腐蚀与膨胀对图像进行处理。开运算与闭运算组合使用这两种操作,在保留图像主体部分的同时,处理图像中出现的各种杂点、空洞、小的间隙、毛糙的边缘等。合理地运用开运算与闭运算,能简化操作步骤,有效地优化目标区域,使提取出的范围更为理想。

1.开运算

       开运算的计算步骤是先腐蚀,后膨胀。通过腐蚀运算能去除小的非关键区域,也可以把离得很近的元素分隔开,再通过膨胀填补过度腐蚀留下的空隙。因此,通过开运算能去除一些孤立的、细小的点,平滑毛糙的边缘线,同时原区域面积也不会有明显的改变,类似于一种“去毛刺”的效果。
       在Halcon中打开开运算示例程序,目录如下。
在这里插入图片描述
       下面左图为原图,右图为提取出来的目标区域。
在这里插入图片描述
       代码如下:

* ball.hdev: Inspection of Ball Bonding
* 
dev_update_window ('off')
dev_close_window ()
dev_open_window (0, 0, 728, 512, 'black', WindowID)
read_image (Bond, 'die/die_03')
dev_display (Bond)
set_display_font (WindowID, 14, 'mono', 'true', 'false')
disp_continue_message (WindowID, 'black', 'true')
stop ()
threshold (Bond, Bright, 100, 255)
shape_trans (Bright, Die, 'rectangle2')
dev_set_color ('green')
dev_set_line_width (3)
dev_set_draw ('margin')
dev_display (Die)
disp_continue_message (WindowID, 'black', 'true')
stop ()
reduce_domain (Bond, Die, DieGrey)
threshold (DieGrey, Wires, 0, 50)
fill_up_shape (Wires, WiresFilled, 'area', 1, 100)
dev_display (Bond)
dev_set_draw ('fill')
dev_set_color ('red')
dev_display (WiresFilled)
disp_continue_message (WindowID, 'black', 'true')
stop ()
opening_circle (WiresFilled, Balls, 15.5)
dev_set_color ('green')
dev_display (Balls)
disp_continue_message (WindowID, 'black', 'true')
stop ()
connection (Balls, SingleBalls)
select_shape (SingleBalls, IntermediateBalls, 'circularity', 'and', 0.85, 1.0)
sort_region (IntermediateBalls, FinalBalls, 'first_point', 'true', 'column')
dev_display (Bond)
dev_set_colored (12)
dev_display (FinalBalls)
disp_continue_message (WindowID, 'black', 'true')
stop ()
smallest_circle (FinalBalls, Row, Column, Radius)
NumBalls := |Radius|
Diameter := 2 * Radius
meanDiameter := mean(Diameter)
minDiameter := min(Diameter)
dev_display (Bond)
disp_circle (WindowID, Row, Column, Radius)
dev_set_color ('white')
disp_message (WindowID, 'D: ' + Diameter$'.4', 'image', Row - 2 * Radius, Column, 'white', 'false')
dev_update_window ('on')

       下面左图为经过threshold算子分割后的图像,可以看到有很多杂点,边缘也不平滑。为了保留主体部分、同时平滑选区的边缘,这里使用opening_circle 算子。处理后如右图所示,杂点大部分都已消失,毛糙的边缘也有所平滑,前景目标更清晰。
在这里插入图片描述
       其中关于灰度阈值的选择,可以通过将鼠标指针悬停在关键像素上,查看其灰度值进行估算。注意,这里的图像都是暗背景、亮目标。如果是亮背景、暗目标,可以用invert_image进行颜色反转。
       如果圆形结构元素半径过大,可能导致图像内部出现大的空洞;如果圆形结构元素半径过小,能会使杂点消除得不完全,因此可以根据实际需要不断调整该参数。
       opening 算子的原型如下:

opening(Region, StructElement : RegionOpening::)

       其中各参数的含义如下。
       1)、参数1:Region为输入的图像区域。
       2)、参数2:StructElement为输入的结构元素,该结构元素应提前指定。
       3)、参数3:RegionOpening为输出的经开运算处理后的区域。
       开运算的效果与腐蚀类似,其本质也是一种腐蚀操作。经开运算处理后,图像上的大面积的区域依然能基本保持完整,而面积小的区域,如点或短线将被移除。
       除了上文中的opening算子以外,Halcon中与开运算有关的算子如下。
       1)、opening_circle:使用圆形结构元素对区域进行开运算处理。
       2)、opening_rectangle1:使用矩形结构元素对区域进行开运算处理。
       3)、opening_golay:使用格雷字母表中的元素对区域进行开运算处理。
       4)、opening_seq:分隔重叠的区域。该算子一般是erosion1、connection和dilation1算子的连续使用。如果重叠的区域小于结构元素,相交的两个区域将被分隔开来。

2.闭运算

       闭运算的计算步骤与开运算正好相反,为先膨胀,后腐蚀。这两步操作能将看起来很接近的元素,如区域内部的空洞或外部孤立的点连接成一体,区域的外观和面积也不会有明显的改变。通俗地说,就是类似于“填空隙”的效果。与单独的膨胀操作不同的是,闭运算在填空隙的同时,不会使图像边缘轮廓加粗。
       下面中图的红色部分为经阈值处理后提取的区域,三角形区域有小的空洞,四边形区域有部分缺失。经过closing算子处理后,小的空洞和缺失的部分得到了填充,形状变得完整。下面右图是闭运算后的效果。
在这里插入图片描述
       上图的闭运算处理代码如下:

read_image(Image, 'shapes_closing')
*将图像进行通道分解,分别转换为3个通道的RGB图像
decompose3(Image, Red, Green, Blue)
*使用颜色转换将RGB的3个通道图像转换为HSV通道图像
trans_from_rgb(Red, Green, Blue, Hue, Saturation, Intensity, 'hsv')
*对饱和度通道的图像进行阈值处理
threshold(Saturation, Regions, 180, 255)
*创建圆形结构元素,用于闭运算
gen_circle(StructElement, 10, 10, 10)
*对图像中较亮的区域进行闭运算处理,填补各自轮廓中的小空隙
closing(Regions, StructElement, Large)
dev_clear_window()
dev_display(Large)

       之所以选择对饱和度通道的图像进行阈值处理,是因为这个通道的图像符合暗背景、亮目标。经过闭运算后,区域内的小缝隙被填补,选区变得封闭。
       上文中使用了closing 算子进行闭运算处理。该算子的原型如下:

    closing(Region, StructElement :RegionClosing : : )

       其中各参数的含义如下。
       1)、参数1:Region为输入的图像区域。
       2)、参数2:StructElement为输入的结构元素,如圆形、矩形等。
       3)、参数3:RegionClosing为输出的经闭运算处理后的区域。
       闭运算也是一种扩张的操作。经闭运算处理后,图像上的大面积的区域依然能基本维持原状,而面积小的区域之间的空隙和区域内部的小孔将被封闭。
       注意:该算子本质虽然是扩张,但并不会将不同的区域合并,区域之间仍保持相对独立。
       除了上文中的closing算子以外,Halcon中与闭运算有关的算子如下。
       1)、closing_circle:使用圆形结构元素对区域进行闭运算处理。
       2)、closing_golay:使用格雷字母表中的元素对区域进行闭运算处理。
       3)、closing_rectangle1:使用矩形结构元素对区域进行闭运算处理。
       总体来说,开运算适合去除图上的杂点和噪声等非关键的元素。而闭运算则相反,它是用于填补区域中的小空隙。开运算和闭运算都不会改变主体部分的形态。

三、顶帽运算和底帽运算

       在实际检测过程中,有时需要利用开运算或者闭运算操作的结果。顶帽运算与底帽运算就是在开运算与闭运算的基础上,来处理图像中出现的各种杂点、空洞、小的间隙、毛糙的边缘等。合理地运用顶帽运算与底帽运算,能简化操作步骤,更能有效地优化目标区域,使提取出的范围更为理想。

1.顶帽运算

       顶帽运算的原理是用原始的二值图像减去开运算的图像。开运算的目的是“移除”某些局部像素,如去毛边、断开相邻的边缘等。而顶帽运算正是用来提取这些被移除的部分。下面右图为从二值图像中提取出的亮的区域,可见有一些杂点和毛边。
在这里插入图片描述
       上面中图中的红色部分为经过开运算处理后的效果,杂点消失,毛糙的边缘也有所平滑。与之对比的是右图,即不使用开运算,而使用顶帽运算的结果,得到的是开运算中被移除的边缘和杂点。上图顶帽运算处理代码如下:

read_image (Image,' data/board')
rgbl_to_gray(Image, GrayImage)
gen rectanglel (Rectangle, 259, 87, 957, 909)
reduce_domain (GrayImage, Rectangle, ImageReduced)
threshold (ImageReduced,Light,85,255)
gen_circle(StructElement,6,6,7)
*清理显示窗口,以便显示结果
dev_clear_window ()
*进行顶帽运算,得到开运算中被移除的局部像素并高亮显示
top_hat (Light, StructElement, RegionTopHat)
dev_clear window ()
dev_display (RegionTopHat)

       由此可见,顶帽运算返回的像素部分是尺寸比结构元素小的,并且比较亮的、在开运算中被移除的局部小区域。

2.底帽运算

       底帽运算的原理是用原始的二值图像减去闭运算的图像。闭运算的目的是对某些局部区域进行“填补”,如填空洞、使分离的边缘相连接等。而底帽运算正是用来提取这些用于填补的区域的。下面的图(c)为从二值图像中提取出的亮的区域,可见有一些空隙和不完整边缘。通过闭运算能对这些小的空隙进行填补,效果如图(b)所示。这里使用底帽运算,刚好将闭运算填补的部分提取出来,如图(d)所示。在这里插入图片描述
       上面的底帽运算处理代码如下:

read_image (Image, 'data/shapes')
decompose3 (Image, Red, Green, Blue)
trans_from_rgb (Red, Green, Blue, Hue, Saturation, Intensity, 'hsv' )
threshold (Saturation, Regions, 180, 255)
gen_circle(StructElement,10,10,10)
*清理显示窗口,以便显示结果
dev clear window ()
*清理显示窗口,以便显示结果
bottom_hat (Regions, StructElement, RegionBottomHat)
dev_clear_window ()
dev_display(RegionBottomHat)

       由此可见,底帽运算返回的像素部分是尺寸比结构元素小的,并且比较暗的、闭运算中用于填补孔隙的局部小区域。


总结

       形态学处理是图像处理的常用方法和手段,学者要掌握好基础概念和使用场合。

参考文献

1、Halcon机器视觉算法原理与编程实战/杨青编著.北京大学出版社

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐