形态学操作
形态学,即数学形态学,是图像处理过程中一个非常重要的研究方向。形态学主要从图像内提取分量信息,该分量信息通常对于表达形态学操作主要包含:腐蚀、膨胀、开运算、闭运算、形态学梯度运算、礼帽运算、黑帽运算等。
1、腐蚀操作
腐蚀能够消除图像的边界点,使得图像沿着边界向内收敛,也可以将小于指定结构元素的部分去除。借此可以实现去除噪声、元素分割等功能。
在OpenCV中,使用函数cv2.erode()实现腐蚀操作,其语法格式为:
dst = cv2.erode(src, kernel, iterations)
参数说明:
dst是腐蚀后所输出的目标图像,该图像和原始图像具有同样的类型和大小。
scr是需要进行腐蚀的原始图像,图像的通道数可以是任意的。
kernel卷积核,代表腐蚀操作时所采用的结构类型(即腐蚀笔形)。
iterations是腐蚀操作迭代的次数,该值默认为1,即只进行一次腐蚀操作。
腐蚀综合案例如下。
# 形态学——腐蚀操作
import cv2
import numpy
zs_img = cv2.imread("E:/tmp/img/name.png")
ls_img = cv2.imread("E:/tmp/img/LiSi.png")
# 将图片按比例缩小
zs_img2 = cv2.resize(zs_img, (0, 0), fx=0.5, fy=0.5)
ls_img2 = cv2.resize(ls_img, (0, 0), fx=0.5, fy=0.5)
# 显现原始图像
cv2.imshow("ZS Aboriginal", zs_img2)
cv2.imshow("LS Aboriginal", ls_img2)
# 设置核,即画笔形状,shape为画笔尺寸,dtype设置数据类型,默认为numpy.float64。
kernel = numpy.ones(shape=(3, 3), dtype=numpy.uint8)
# 1、对张三图片进行腐蚀
# 对指定的图像对象进行腐蚀,kernel使用的画笔,iterations腐蚀的深度
zs_erosion = cv2.erode(zs_img2, kernel=kernel, iterations=1)
# 2、对李四图片进行腐蚀
ls_erosion = cv2.erode(ls_img2, kernel=kernel, iterations=1)
# 显示腐蚀后的效果
cv2.imshow("zs_erosion", zs_erosion)
cv2.imshow("ls_erosion", ls_erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果。
图1.1 腐蚀效果
根据上述运行结果可知道,腐蚀是由深颜色向浅色腐蚀,即向浅色中侵吞1画笔的尺寸,如果设置iterations=n参数,表示向浅色侵吞n个画笔尺寸。
2、膨胀操作
膨胀操作和腐蚀操作的作用是完全相反的,膨胀操作能对图像的边界进行扩张。膨胀操作对于填补图像分割后图像内所存在的空白有帮助。
在OpenCV中,使用函数cv2.dilate()实现膨胀操作,其语法格式为:
dst = cv2.dilate(src, kernel, iterations)
参数说明:
dst是膨胀后所输出目标图像,该图像和原始图像具有同样的类型和大小。
src是需要进行膨胀的原始图像,图像的通道数可以是任意的。
kernel卷积核,代表膨胀操作时所采用的结构类型。
iterations是膨胀操作迭代的次数,该值默认为1,即只进行一次膨胀操作。
膨胀案例。
import cv2
import numpy
# 读取图像
zs = cv2.imread("E:/tmp/img/ZhangSan.png")
ls = cv2.imread("E:/tmp/img/LiSi.png")
# 缩小两张图像尺寸
zs_img = cv2.resize(zs, (0, 0), fx=0.5, fy=0.5)
ls_img = cv2.resize(ls, (0, 0), fx=0.5, fy=0.5)
# 设置膨胀画笔尺寸
kernel = numpy.ones((3, 3), numpy.uint8)
# 1、对zs图像进行膨胀
zs_dilate = cv2.dilate(src=zs_img, kernel=kernel, iterations=2)
# 2、对ls图像进行膨胀
ls_dilate = cv2.dilate(src=ls_img, kernel=kernel, iterations=2)
# 效果呈现
# 原始图像
cv2.imshow("zs_img", zs_img)
cv2.imshow("ls_img", ls_img)
# 膨胀后的图像
cv2.imshow("zs_dilate", zs_dilate)
cv2.imshow("ls_dilate", ls_dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果。
图2.1 膨胀运行结果
根据图2.1结果可知,膨胀是由浅色向深色腐蚀,即向深色中侵吞1个画笔的尺寸,如果设置iterations=n参数,表示向深色侵吞n个画笔尺寸。
腐蚀与膨胀综合案例:
实现去ZhangSan.png图像中的“飞边”,并保持文字真实大小。
import cv2
import numpy
# 读取图像
zs = cv2.imread("E:/tmp/img/ZhangSan.png")
# 缩小两张图像尺寸
zs_img = cv2.resize(zs, (0, 0), fx=0.5, fy=0.5)
# 1、设置画笔尺寸
kernel = numpy.ones((3, 3), numpy.uint8)
# 2、对ZhangSan.png图像进行腐蚀,去除“飞边”。
zs_erode = cv2.erode(src=zs_img, kernel=kernel, iterations=1)
# 3、腐蚀后有效字体会缩小,再使用膨胀将有效字体扩大
zs_dilate = cv2.dilate(src=zs_erode, kernel=kernel, iterations=1)
# 验证效果
cv2.imshow("zs_img", zs_img)
cv2.imshow("zs_erode", zs_erode)
cv2.imshow("zs_dilate", zs_dilate)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果如图2.2。
国2.2 腐蚀和膨胀综合应用
3、通用形态学函数
腐蚀操作和膨胀操作是形态学运算的基础,将腐蚀和膨胀操作进行组合,就可以实现开运算、闭运算、形态学梯度运算、顶帽运算、黑帽运算等多种不同形式的运算。
OpenCV提供了函数cv2.morphologyEx来实现上述形态学运算,其常见语法结构如下:
dst = cv2.morphologyEx(src, op, [,kernel] [,iterations])
其中:mor ph log
dst代表经过形态学处理后所输出的目标图像,该图像和原始图像具有同样的类型和大小。
src代表需要进行形态学操作的原始图像。
op代表操作类型,如下表3.1所示。各种形态学运算的操作规则均是将腐蚀膨胀操作进行组合而得到的。
kernel卷积核,代表膨胀操作时所采用的结构类型。
iterations是膨胀操作迭代的次数,该值默认为1,即只进行一次膨胀操作。
表3.1
类型 说明 意义 操作
cv2.MORPH_ERODE 腐蚀 腐蚀 erode()
cv2.MORPH_DILATE 膨胀 膨胀 dilate()
cv2.MORPH_OPEN 开运算 先腐蚀后膨胀 dilate(erode())
cv2.MORPH_CLOSE 闭运算 先膨胀后腐蚀 erode(dilate())
cv2.MORPH_GRADIENT 形态学梯度运算 膨胀图减去腐蚀图 dilate()-erode()
cv2.MORPH_TOPHAT 顶帽运算 原始图像减开运算所得图像 src-open()
cv2.MORPH_BLACKHAT 黑帽 闭运算所得图像减原始图像 close()-src
3.1 开运算
开运算进行的操作是先对图像腐蚀,再对腐蚀后的对象进行膨胀,开运算可以用于去噪等。语法格式就是在通用形态学函数的基础上,将参数op设置为cv2.MORPH_OPEN即可。
示例代码如下所示。
# 开运算
import cv2
import numpy
# 读取图像
zs = cv2.imread("E:/tmp/img/ZhangSan.png")
# 缩小两张图像尺寸
zs_img = cv2.resize(zs, (0, 0), fx=0.5, fy=0.5)
# 1、设置画笔尺寸
kernel = numpy.ones((3, 3), numpy.uint8)
# 2、开运算
open = cv2.morphologyEx(src=zs_img, op=cv2.MORPH_OPEN, kernel=kernel)
# 显示结果
cv2.imshow("zs_img", zs_img) # 原始图
cv2.imshow("open", open) # 开运算
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果。
图3.1 开运算运行结果
3.2 闭运算
闭运算是先进行膨胀操作,然后再对膨胀后的图像进行腐蚀操作。闭运算有利于关闭前景物体内部的小孔,或去除物体上的小黑包,还可以将不同的前景图像进行连接。
闭运算示例代码如下所示。
# 闭运算
import cv2
import numpy
# 读取图像
zs = cv2.imread("E:/tmp/img/LiSi.png")
# 缩小两张图像尺寸
zs_img = cv2.resize(zs, (0, 0), fx=0.5, fy=0.5)
# 1、设置画笔尺寸
kernel = numpy.ones((3, 3), numpy.uint8)
# 2、闭运算
close = cv2.morphologyEx(src=zs_img, op=cv2.MORPH_CLOSE, kernel=kernel, iterations=2)
# 显示结果
cv2.imshow("zs_img", zs_img) # 原始图
cv2.imshow("close", close) # 闭运算
cv2.waitKey(0)
cv2.destroyAllWindows()
闭运算运行结果。
图3.2 闭运算运行结果
3.3 梯度运算
形态学梯度运算是用图像的膨胀图像减去腐蚀图像的操作,该操作可以获取原始图像中前景图像的边缘。
梯度运算示例代码。
import cv2
import numpy
# 读取图像
zs = cv2.imread("E:/tmp/img/ZhangSan.png")
# 缩小两张图像尺寸
zs_img = cv2.resize(zs, (0, 0), fx=0.5, fy=0.5)
# 1、设置画笔尺寸
kernel = numpy.ones((3, 3), numpy.uint8)
# 2、梯度运算
gradient = cv2.morphologyEx(src=zs_img, op=cv2.MORPH_GRADIENT, kernel=kernel)
# 显示结果
cv2.imshow("zs_img", zs_img) # 原始图
cv2.imshow("gradient", gradient) # 梯度运算
cv2.waitKey(0)
cv2.destroyAllWindows()
梯度运算运行结果。
图3.3 梯度运算
3.4 礼帽运算(顶帽运算)和黑帽运算
礼帽运算是用原始图像减去该图像开运算后的图像。礼帽运算能够获取图像的噪声信息,还可以得到比原始图像的边缘更亮的边缘信息。
黑帽运算是用闭运算后的图像减去原始图像。黑帽运算能够获取图像内部的小孔,或前景中的小黑点,或者得到比原始图像的边缘更暗的边缘部分。
顶帽黑帽综合案例。
import cv2
import numpy
# 读取图像
zs = cv2.imread("E:/tmp/img/ZhangSan.png")
# 缩小两张图像尺寸
zs_img = cv2.resize(zs, (0, 0), fx=0.5, fy=0.5)
# 1、设置画笔尺寸
kernel = numpy.ones((3, 3), numpy.uint8)
# 2.1 顶帽运算
top_hat = cv2.morphologyEx(src=zs_img, op=cv2.MORPH_TOPHAT, kernel=kernel)
# 2.2 黑帽运算
black_hat = cv2.morphologyEx(src=zs_img, op=cv2.MORPH_BLACKHAT, kernel=kernel)
# 显示结果
cv2.imshow("zs_img", zs_img) # 原始图
cv2.imshow("top_hat", top_hat) # 顶帽运算
cv2.imshow("black_hat", black_hat) # 黑帽运算
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果。
图3.4 顶帽和黑帽运行结果