参考书目:《OpenCV计算机视觉基础教程》–夏帮贵。
代码编写:Jupyter Notebook。
# 形态变换:用于二值图像的形状操作,形态变换实现原理基于数字形态学;
# 数字形态学(形态学):主要是从图像内部提取信息来描述图像形态;
# 数字形态学广泛应用于视觉检测、文字识别、医学图像处理、图像压缩编码等领域;
# 形态变换主要包括:腐蚀、膨胀、高级形态操作;
# 1.形态操作内核
# 形态操作会使用一个内核遍历图像,根据内核和图像的位置关系决定内核中心对应的图像像素点的输出结果;
# 语法格式:retval = cv2.getStructuringElement(shape, ksize)
# 参数说明:
# a.shape:内核形状,包括:cv2.MORPH_RECT(矩形)、cv2.MORPH_CROSS(十字形)、cv2.MORPH_ELLIPSE(椭圆形);
# b.ksize:内核大小;
import cv2 as cv
import numpy as np
rect_kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
cross_kernel = cv.getStructuringElement(cv.MORPH_CROSS, (5, 5))
ellipse_kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5))
print("矩形内核:")
print(rect_kernel)
print("-----------------------")
print("十字形内核:")
print(cross_kernel)
print("-----------------------")
print("椭圆形内核:")
print(ellipse_kernel)
print("-----------------------")
kernel1 = np.ones((5, 5), np.uint8)
kernel2 = np.array([[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0]])
kernel3 = np.array([[0, 0, 1, 0, 0],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[1, 1, 1, 1, 1],
[0, 0, 1, 0, 0]])
print("自定义内核1:")
print(kernel1)
print("-----------------------")
print("自定义内核2:")
print(kernel2)
print("-----------------------")
print("自定义内核3:")
print(kernel3)
# 结果输出:
矩形内核:
[[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]]
-----------------------
十字形内核:
[[0 0 1 0 0]
[0 0 1 0 0]
[1 1 1 1 1]
[0 0 1 0 0]
[0 0 1 0 0]]
-----------------------
椭圆形内核:
[[0 0 1 0 0]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[0 0 1 0 0]]
-----------------------
自定义内核1:
[[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]]
-----------------------
自定义内核2:
[[0 0 1 0 0]
[0 0 1 0 0]
[1 1 1 1 1]
[0 0 1 0 0]
[0 0 1 0 0]]
-----------------------
自定义内核3:
[[0 0 1 0 0]
[1 1 1 1 1]
[1 1 1 1 1]
[1 1 1 1 1]
[0 0 1 0 0]]
腐蚀原理
- 在下图中,0表示背景,1表示前景;
- 蓝色方块表示3×3矩形内核;
- 执行腐蚀操作时,依次将内核中心对准每个单元格,根据内核和前景的未知关系决定当前单元格的值;
- 当内核部分或全部处于前景之外,内核中心对应单元格的值设置为0;
- 当内核完全处于前景内部时,内核中心对应单元格的值才设置为1;
- 通过腐蚀操作,图像的边界被侵蚀,白色区域缩小;
# 2.腐蚀
# 语法格式:dst = cv2.erode(src, kernel[, anchor[, iterations[, borderType[, borderValue]]]])
# 参数说明:
# a.dst:处理后的图像;
# b.src:处理前的图像;
# c.kernel:内核;
# d.anchor:锚点,默认值:(-1, -1),表示锚点为内核中心;
# e.iterations:腐蚀操作的迭代次数;
# f.borderType:边界类型,默认值:BORDER_CONSTANT;
# g.borderValue:边界值,一般自动确定;
import cv2 as cv
import numpy as np
img1 = cv.imread("fuxi.jpg")
kernel1 = np.ones((3, 3), np.uint8)
kernel2 = np.ones((5, 5), np.uint8)
img2 = cv.erode(img1, kernel1, iterations = 2)
img3 = cv.erode(img1, kernel2, iterations = 2)
cv.imshow("fuxi", img1)
cv.imshow("fuxi_kernel1", img2)
cv.imshow("fuxi_kernel2", img3)
cv.waitKey(0)
膨胀原理
- 膨胀对图像边界进行扩张;
- 执行遍历操作时,只有内核完全处于前景外部时,内核中心对应像素点的值才设置为0,否则设置为1;
- 如下图,0表示背景,1表示前景,蓝色方块表示大小为3×3的矩形内核;
- 只有在内核完全处于前景外部时,内核中心对应单元格的值才设置为0;
- 内核部分在前景内,内核中心对应单元格的值设置为1;
# 3.膨胀
# 语法格式:dst = cv2.dilate(src, kernel[, anchor[, iterations[, borderType[, borderValue]]]])
# 参数说明:
# a.dst:处理后的图像;
# b.src:处理前的图像;
# c.kernel:内核;
# d.anchor:锚点,默认值:(-1, -1),表示锚点为内核中心;
# e.iterations:腐蚀操作的迭代次数;
# f.borderType:边界类型,默认值:BORDER_CONSTANT;
# g.borderValue:边界值,一般自动确定;
import cv2 as cv
import numpy as np
img1 = cv.imread("fuxitext.jpg")
kernel1 = np.ones((3, 3), np.uint8)
kernel2 = np.ones((5, 5), np.uint8)
kernel3 = np.ones((7, 7), np.uint8)
img2 = cv.dilate(img1, kernel1, iterations = 2)
img3 = cv.dilate(img1, kernel2, iterations = 2)
img4 = cv.dilate(img1, kernel3, iterations = 2)
cv.imshow("fuxitext", img1)
cv.imshow("fuxitext_kernel1", img2)
cv.imshow("fuxitext_kernel2", img3)
cv.imshow("fuxitext_kernel3", img4)
cv.waitKey(0)
# 4.高级形态操作
# 高级形态操作基于腐蚀和膨胀操作,包括:开运算、闭运算、形态学梯度运算、黑帽运算、礼帽运算;
# 语法格式:dst = cv2.morphologyEx(src, op, kernel[, anchor[, iteration[, borderType[, borderValue]]]])
# 参数说明:
# a.dst:处理后的图像;
# b.src:处理前的图像;
# c.op:形态操作类型;cv2.MORPH_ERODE:腐蚀操作;cv2.MORPH_DILATE:膨胀操作;
# e.kernel:内核;
# f.anchor:锚点,默认值:(-1, -1),表示锚点为内核中心;
# g.iterations:腐蚀操作的迭代次数;
# h.borderType:边界类型,默认值:BORDER_CONSTANT;
# i.borderValue:边界值,一般自动确定;
# 4.1 开运算:先对图像执行腐蚀操作,再对腐蚀结果执行膨胀操作;
import cv2 as cv
import numpy as np
img1 = cv.imread("fuxi.jpg")
kernel = np.ones((3, 3), np.uint8)
op = cv.MORPH_OPEN
img2 = cv.morphologyEx(img1, op, kernel, iterations = 5)
cv.imshow("fuxi", img1)
cv.imshow("fuxi_OPEN", img2)
cv.waitKey(0)
# 4.2 闭运算:先对图像执行膨胀操作,再对图像执行腐蚀操作;
import cv2 as cv
import numpy as np
img1 = cv.imread("fuxitext.jpg")
kernel = np.ones((5, 5), np.uint8)
op = cv.MORPH_CLOSE
img2 = cv.morphologyEx(img1, op, kernel, iterations = 3)
cv.imshow("fuxitext", img1)
cv.imshow("fuxitext_CLOSE", img2)
cv.waitKey(0)
# 4.3 形态学梯度运算:用图像的膨胀操作结果减去腐蚀操作结果;
import cv2 as cv
import numpy as np
img1 = cv.imread("fuxitext.jpg")
kernel = np.ones((3, 3), np.uint8)
op = cv.MORPH_GRADIENT
img2 = cv.morphologyEx(img1, op, kernel, iterations = 1)
cv.imshow("fuxitext", img1)
cv.imshow("fuxitext_GRADIENT", img2)
cv.waitKey(0)
# 4.4 黑帽运算:用图像的闭运算结果减去原图像;
import cv2 as cv
import numpy as np
img1 = cv.imread("fuxitext.jpg")
kernel = np.ones((5, 5), np.uint8)
op = cv.MORPH_BLACKHAT
#img2 = cv.morphologyEx(img1, op, kernel, iterations = 27) # 测试iterations = 27时的效果
img2 = cv.morphologyEx(img1, op, kernel, iterations = 9)
cv.imshow("fuxitext", img1)
cv.imshow("fuxitext_BLACKHAT", img2)
cv.waitKey(0)
# 4.5 礼帽运算:用原图像减去图像的开运算结果;
import cv2 as cv
import numpy as np
img1 = cv.imread("fuxitext.jpg")
kernel = np.ones((7, 7), np.uint8)
op = cv.MORPH_TOPHAT
img2 = cv.morphologyEx(img1, op, kernel, iterations = 1)
cv.imshow("fuxitext", img1)
cv.imshow("fuxitext_TOPHAT", img2)
cv.waitKey(0)