机器视觉与深度学习(OpenCV-Python)案例代码4.1:图像预处理中的形态学运算
案例内容
通过开运算,去除图像a中的噪声,再通过闭运算,填补图像b中的裂纹。

图像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()
运行结果

更多推荐


所有评论(0)