案例内容

通过开运算,去除图像a中的噪声,再通过闭运算,填补图像b中的裂纹。

a.bmp
图像a

在这里插入图片描述

图像b

案例原理

腐蚀

腐蚀是基本的形态学操作,可以使图像向内缩小。在腐蚀过程中,会使用一个结构元逐个像素扫描图像,根据结构元与前景对象的位置关系,决定腐蚀结果图像中像素点的像素值。
在这里插入图片描述

腐蚀效果

上图中img为原始图像,白色部分为前景对象,主要内容为两个重叠的矩形,矩形边上的小突起表示噪声。图中a,b,c分别为使用边长为5、10、20的正方形结构元进行腐蚀的结果。

可以发现,随着结构元的增大,前景对象逐渐变小,两个矩形彼此分离,噪声也逐渐消失。由此可知,结构元越大,腐蚀的程度越高,前景对象就会越小,而通过特定的结构元进行的腐蚀效果,可以去除图像中的特定噪声,分割图像中的元素。

膨胀

膨胀与腐蚀相反,可以将图像向外扩大。在膨胀过程中,也会使用一个结构元逐个像素扫描图像,根据结构元与前景对象的位置关系,决定膨胀结果图像中像素点的像素值。

在这里插入图片描述

膨胀效果

上图中img为原始图像,白色部分为前景对象,主要内容为两个分离的矩形,矩形边上有凹陷。图中a,b,c分别为使用边长为5、10、20的正方形结构元进行膨胀的结果。

可以发现,随着结构元的增大,前景对象逐渐变大,两个矩形彼此靠近,最后合并,凹陷也逐渐消失。由此可知,结构元越大,膨胀的程度越高,前景对象就会越大,而通过特定的结构元进行的膨胀效果,可以填补图像的空缺,合并图像中的元素。

开运算与闭运算

腐蚀与膨胀是形态学运算的基础,将腐蚀与膨胀结合,可以实现开运算、闭运算、形态学梯度运算等多种运算,本例中使用的是开运算与闭运算。

开运算操作会先将图像进行腐蚀,再对腐蚀结果进行膨胀,即:
在这里插入图片描述

开运算效果

上图中img为原始图像,a为原始图像经边长为20的正方形结构元腐蚀后的结果图,b为腐蚀结果a经相同的正方形结构元膨胀后的效果图,c为原始图像经相同的正方形结构元进行开运算后的效果图。

可以发现,开运算的结果与腐蚀后膨胀的结果相同,与原始图像相比,都成功去除了原始图像上的小凸起,断开了两矩形之间的连线,并且没有使其余部分发生大的变化。由此可知,开运算可以平滑物体的轮廓,断开较窄的狭颈,消除细的突出物。

在这里插入图片描述

闭运算效果

上图中img为原始图像,a为原始图像经边长为20的正方形结构元膨胀后的结果图,b为膨胀结果a经相同的正方形结构元腐蚀后的效果图,c为原始图像经相同的正方形结构元进行闭运算后的效果图。

可以发现,闭运算的结果与膨胀后腐蚀的结果相同,与原始图像相比,都成功填补了原始图像上的沟壑与断裂,图像整体的大小基本不变。由此可知,开运算可以弥合较窄的间断和细长的沟壑,消除小的孔洞,填补轮廓线中的断裂。

其他形态学函数

除了腐蚀、膨胀、开运算、闭运算外,形态学函数还有形态学梯度运算、顶帽运算、黑帽运算等方法。

形态学梯度运算会将原始图像分别进行膨胀与腐蚀操作,再将膨胀图像减去腐蚀图像,示例如下图所示。
在这里插入图片描述

形态学梯度运算结果

上图中img为原始图像,a为原始图像经边长为10的正方形结构元膨胀后的结果图,b为原始图像经相同的正方形结构元腐蚀后的效果图,c为膨胀结果a减去腐蚀结果b后的效果图,d为原始图像经相同的正方形结构元进行形态学梯度运算后的效果图。

可以发现,形态学梯度运算的结果与膨胀图像减去腐蚀图像的结果相同,与原始图像相比,获得了图像边缘所在的区域。

顶帽运算会先对原始图像进行开运算操作,再将原始图像减去开运算图像,示例如下图所示。
在这里插入图片描述

顶帽运算结果

上图中img为原始图像,a为原始图像img经边长为5的正方形结构元开运算后的结果图,b为原始图像img减去开运算图像a后的效果图,c为原始图像经相同的正方形结构元进行顶帽运算后的效果图。

可以发现,顶帽运算的结果与原始图像减去开运算图像的效果相同,与原始图像相比,顶帽运算获得了图像中的凸起部分与细颈部分。

黑帽运算与顶帽运算类似,但黑帽运算会先对原始图像进行闭运算操作,再将闭运算图像减去原始图像,示例如下图所示。

在这里插入图片描述

黑帽运算结果

上图中img为原始图像,a为原始图像img经边长为5的正方形结构元闭运算后的结果图,b为闭运算图像a减去原始图像img后的效果图,c为原始图像经相同的正方形结构元进行黑帽运算后的效果图。

可以发现,黑帽运算的结果与闭运算图像减去原始图像的效果相同,与原始图像相比,黑帽运算获得了图像中的裂纹部分与窄缝部分。

重要代码

kernel = cv2.getStructuringElement(shape, ksize, anchor)
表示生成一个结构元,其中:

  • kernel为生成的结构元
  • shape为生成结构元的形状,其中:
    cv2.MORPH_RECT     表示矩形结构元
    cv2.MORPH_ELLIPSE   表示椭圆结构元
    cv2.MORPH_CROSS    表示十字型结构元
  • ksize为生成结构元的大小,形式为(a, b),a表示列数,b表示行数,通常情况下a与b相等
  • anchor为结构元的锚点位置,默认值为(-1, -1),表示中心

dst = cv2.morphologyEx(src, op, kernel, anchor, iterations)
表示对图像进行形态学运算,其中:

  • dst为运算结果图像
  • src为原始图像
  • op为运算模式,其中:
    cv2.MORPH_ERODE   表示腐蚀操作
    cv2.MORPH_DILATE    表示膨胀操作
    cv2.MORPH_OPEN     表示开运算
    cv2.MORPH_CLOSE    表示闭运算
    cv2.MORPH_GRADIENT  表示形态学梯度运算
    cv2.MORPH_TOPHAT    表示顶帽运算
    cv2.MORPH_BLACKHAT   表示黑帽运算
    本例使用cv2.MORPH_OPEN与cv2.MORPH_CLOSE,分别表示开运算与闭运算
  • kernel为指定的结构元,本例中为边长为20的正方形
  • anchor为结构元的锚点位置,本例使用默认值(-1, -1),即中心
  • iteration为迭代次数,表示形态学运算的次数,默认值为1

代码实现

首先,要导入库,获取两张原始图像,即:

import cv2
import numpy as np
imga = cv2.imread("a.bmp")
imgb = cv2.imread("b.bmp")

获取图像后,将图像转化为二值化图像,即:

graya = cv2.cvtColor(imga, cv2.COLOR_BGR2GRAY)
grayb = cv2.cvtColor(imgb, cv2.COLOR_BGR2GRAY)
reta, imga1 = cv2.threshold(graya, 127, 255, cv2.THRESH_BINARY)
retb, imgb1 = cv2.threshold(grayb, 127, 255, cv2.THRESH_BINARY)

在进行形态学运算之前,先生成结构元,此处使用边长为3的正方形作为结构元,即:

k = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))

先对图像a进行处理,要求去除图像a上的突起部分,需要对图像a使用开运算,即:

ra = cv2.morphologyEx(imga1, cv2.MORPH_OPEN, k)

再对图像b进行处理,要求填补图像b上的裂纹部分,需要对图像b使用闭运算。实际运行时,发现闭运算结果仍然存在小型裂纹,故将迭代次数上升至2,生成迭代一次和迭代两次的运算图像。

rb1 = cv2.morphologyEx(imgb1, cv2.MORPH_CLOSE, k)
rb2 = cv2.morphologyEx(imgb1, cv2.MORPH_CLOSE, k, iterations = 2)

最后进行结果展示:

cv2.imshow('imga', imga)
cv2.imshow('imgb', imgb)
cv2.imshow('ra', ra)
cv2.imshow('rb1', rb1)
cv2.imshow('rb2', rb2)
cv2.waitKey(0)
cv2.destroyAllWindows()

最终代码为:

#===导入库===
import cv2
import numpy as np

#===获取原始图像===
imga = cv2.imread("a.bmp")
imgb = cv2.imread("b.bmp")
#===将原始图像二值化===
graya = cv2.cvtColor(imga, cv2.COLOR_BGR2GRAY)
grayb = cv2.cvtColor(imgb, cv2.COLOR_BGR2GRAY)
reta, imga1 = cv2.threshold(graya, 127, 255, cv2.THRESH_BINARY)
retb, imgb1 = cv2.threshold(grayb, 127, 255, cv2.THRESH_BINARY)
#===生成结构元===
k = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
#===对a进行闭运算===
ra = cv2.morphologyEx(imga1, cv2.MORPH_OPEN, k)
#===对b进行闭运算===
rb1 = cv2.morphologyEx(imgb1, cv2.MORPH_CLOSE, k)
rb2 = cv2.morphologyEx(imgb1, cv2.MORPH_CLOSE, k, iterations = 2)
#===结果展示===
cv2.imshow('imga', imga)
cv2.imshow('imgb', imgb)
cv2.imshow('ra', ra)
cv2.imshow('rb1', rb1)
cv2.imshow('rb2', rb2)
cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果

运行结果

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐