2265 字
11 分钟
OpenCV:形态学操作

1. 基础概念#

形态学主要从图像内提取分量信息,该分量信息通常对于 表达和描绘图像的形状 具有重要意义,通常是图像理解时所使用的最本质的形状特征。

​ 形态学处理在视觉检测文字识别医学图像处理图像压缩编码等领域都有非常重要的应用。

形态学操作主要包含: 腐蚀膨胀开运算闭运算梯度运算顶帽运算黑帽运算 等操作。腐蚀操作和膨胀操作是形态学运算的基础,将腐蚀和膨胀操作进行结合,就可以实现其他不同形式的运算。

2. 腐蚀#

​ 腐蚀是形态学中的最基本操作,它能够将图像的边界点消除使图像沿着边界向内收缩,还可以将小于指定结构体元素的部分去除

​ 腐蚀用来收缩或者细化二值图像中的前景,借此实现去除噪声元素分割等功能。

2.1 原理#

​ 在腐蚀过程中,通常使用一个结构元来逐个像素地扫描要被腐蚀的图像,并根据结构元和被腐蚀图像的关系确定腐蚀结果

  • 如果结构元完全处于前景图像中,就将结构元中心点所对应的腐蚀结果图像中的像素点处理为 前景色
  • 如果结构元未完全处于前景图像中,就将结构元中心点对应的腐蚀结果图像中的像素点处理为 背景色

腐蚀示意图

2.2 使用方法#

  • 通过函数cv2.erode(),实现腐蚀操作
  • 函数原型dst = cv2.erode( src, kernel, anchor, iterations, borderType, borderValue )
  • 参数说明
    • dst腐蚀后输出的目标图像,与原始图像具有相同的大小和类型。
    • src要进行腐蚀的图像,图像的通道数可以是任意的,但图像的深度必须是CV_8UCV_16UCV_16SCV_32FCV_64F中的一种。
    • kernel腐蚀操作时所采用的结构元
    • anchor可选参数,结构元中锚点的位置,默认为(-1, -1),在核的中心位置。
    • iterations可选参数,腐蚀操作迭代的次数,默认为1,即只进行一次腐蚀操作。
    • borderType可选参数,边界样式,默认为BORDER_CONSTANT
    • borderValue可选参数,边界值, 一般采用默认值。

2.3 示例#

import cv2
import numpy as np
J = cv2.imread("J.png")
kernel = np.ones((5, 5), np.uint8)
J_erosion_1 = cv2.erode(J, kernel, iterations = 1)
kernel = np.ones((9, 9), np.uint8)
J_erosion_2 = cv2.erode(J, kernel, iterations = 1)
cv2.imwrite("J_erosion_1.png", J_erosion_1)
cv2.imwrite("J_erosion_2.png", J_erosion_2)
原图5x5的结构元,腐蚀1次9x9的结构元,腐蚀1次
J5x59x9

3. 膨胀#

膨胀操作是形态学中另外一种基本的操作。膨胀操作将当前对象接触到的背景点合并到当前对象内,从而实现将图像的边界点向外扩张如果图像内两个对象的距离较近,那么在膨胀的过程中,两个对象有可能会连通在一起。膨胀操作对填补图像分割后图像内所存在的空白相当有帮助。

3.1 原理#

​ 同腐蚀过程一样,在膨胀过程中,也是使用一个结构元(核函数)来逐个像素地扫描要被膨胀的图像,并根据结构元和待膨胀图像的关系来确定膨胀结果

  • 如果结构元中任意一点处于前景图像中,就膨胀结果图像中对应像素点处理为前景色
  • 如果结构元完全处于背景图像外,就膨胀结果图像中对应像素点处理为背景色

膨胀示意图

3.2 使用方法#

  • 通过函数cv2.dilate(),实现膨胀操作
  • 函数原型dst = cv2.dilate( src, kernel, anchor, iterations, borderType, borderValue )
  • 参数说明
    • dst膨胀后输出的目标图像,与原始图像具有相同的大小和类型。
    • src要进行膨胀的图像,图像的通道数可以是任意的,但图像的深度必须是CV_8UCV_16UCV_16SCV_32FCV_64F中的一种。
    • kernel腐蚀操作时所采用的结构元
    • anchor可选参数,结构元中锚点的位置,默认为(-1, -1),在核的中心位置。
    • iterations可选参数,膨胀操作迭代的次数,默认为1,即只进行一次膨胀操作。
    • borderType可选参数,边界样式,默认为BORDER_CONSTANT
    • borderValue可选参数,边界值, 一般采用默认值。

3.3 示例#

import cv2
import numpy as np
J = cv2.imread("J.png")
kernel = np.ones((5, 5), np.uint8)
J_dilate_1 = cv2.dilate(J, kernel, iterations = 1)
kernel = np.ones((9, 9), np.uint8)
J_dilate_2 = cv2.dilate(J, kernel, iterations = 1)
cv2.imwrite("J_dilation_1.png", J_dilate_1)
cv2.imwrite("J_dilation_2.png", J_dilate_2)
原图5x5的结构元,膨胀1次9x9的结构元,膨胀1次
J5x59x9

4. 形态学函数#

4.1 使用方法#

  • 通过函数cv2.morphologyEx(),可以实现形态学操作

  • 函数原型dst = cv2.morphologyEx( src, op, kernel, anchor, iterations, borderType, borderValue )

  • 参数说明

    • dst膨胀后输出的目标图像,与原始图像具有相同的大小和类型。

    • src要进行膨胀的图像,图像的通道数可以是任意的,但图像的深度必须是CV_8UCV_16UCV_16SCV_32FCV_64F中的一种。

    • op具体的形态学操作

      形态学操作

    • kernel腐蚀操作时所采用的结构元

    • anchor可选参数,结构元中锚点的位置,默认为(-1, -1),在核的中心位置。

    • iterations可选参数,膨胀操作迭代的次数,默认为1,即只进行一次膨胀操作。

    • borderType可选参数,边界样式,默认为BORDER_CONSTANT

    • borderValue可选参数,边界值, 一般采用默认值。

4.2 开运算:先腐蚀,再膨胀#

开运算进行的操作是先将图像腐蚀再对腐蚀的结果进行膨胀

开运算可以用于去噪去毛刺划分连接在一起的不同区域以计数等。

import cv2
import numpy as np
J = cv2.imread("J.png")
kernel = np.ones((5, 5), np.uint8)
J_open = cv2.morphologyEx(src=J, op=cv2.MORPH_OPEN, kernel=kernel)
box = cv2.imread("box.png")
kernel = np.ones((15, 15), np.uint8)
box_open = cv2.morphologyEx(src=box, op=cv2.MORPH_OPEN, kernel=kernel)
cv2.imwrite("J_open.png", J_open)
cv2.imwrite("box_open.png", box_open)
毛刺图开运算:去毛刺
JJ_open
粘连图开运算:划分区域
boxbox_open

4.3 闭运算:先膨胀,再腐蚀#

闭运算先膨胀、后腐蚀的运算。

闭运算有助于关闭前景物体内部的小孔去除物体上的小黑点,还可以将不同的前景图像进行连接

import cv2
import numpy as np
J_hole = cv2.imread("J_hole.png")
kernel = np.ones((9, 9), np.uint8)
J_hole_close = cv2.morphologyEx(src=J_hole, op=cv2.MORPH_CLOSE, kernel=kernel)
cv2.imwrite("J_hole_close.png", J_hole_close)
孔洞图闭运算:闭合孔洞
J_holeJ_hole_close

4.4 形态学梯度运算:膨胀 - 腐蚀#

形态学梯度运算是用图像的膨胀图像减腐蚀图像的操作。

形态学梯度运算可以获取原始图像中前景图像的边缘

import cv2
import numpy as np
J = cv2.imread("J_open.png")
kernel = np.ones((3, 3), np.uint8)
J_gradient = cv2.morphologyEx(src=J, op=cv2.MORPH_GRADIENT, kernel=kernel)
cv2.imwrite("J_gradient.png", J_gradient)
原图形态学梯度运算
J_openJ_gradient

4.5 顶帽运算:原图 - 开运算#

顶帽运算是用原始图像减去其开运算图像的操作。

顶帽运算能够获取图像的噪声信息,或者得到比原始图像的边缘更亮的边缘信息

import cv2
import numpy as np
J = cv2.imread("J.png")
kernel = np.ones((3, 3), np.uint8)
J_tophat = cv2.morphologyEx(src=J, op=cv2.MORPH_TOPHAT, kernel=kernel)
cv2.imwrite("J_tophat.png", J_tophat)
原图开运算顶帽运算
JJ_openJ_tophat

4.6 黑帽运算:闭运算 - 原图#

黑帽运算是用闭运算图像减去原始图像的操作。

黑帽运算能够获取图像内部的小孔前景色中的小黑点,或者得到比原始图像的边缘更暗的边缘部分

import cv2
import numpy as np
J_hole = cv2.imread("J_hole.png")
kernel = np.ones((3, 3), np.uint8)
J_blackhat = cv2.morphologyEx(src=J_hole, op=cv2.MORPH_BLACKHAT, kernel=kernel)
cv2.imwrite("J_blackhat.png", J_blackhat)
原图闭运算黑帽运算
J_holeJ_hole_closeJ_blackhat

5. 自定义结构元#

​ 在进行形态学操作时,必须使用一个特定的结构元,既可以自定义生成,也可以通过函数cv2.getStructuringElement()构造

5.1 使用方法#

  • 通过函数cv2.getStructuringElement()能够构造并返回一个用于形态学处理所使用的结构元素
  • 函数原型retval = cv2.getStructuringElement( shape, ksize, anchor)
  • 参数说明
    • shape:结构元的形状类型
      • cv2.MORPH_RECT矩形结构元素,所有元素值都是1
      • cv2.MORPH_CROSS十字形结构元素,对角线元素值为1
      • cv2.MORPH_ELLIPSE椭圆形结构元素。
    • ksize:结构元的大小
    • anchor:结构元中锚点的位置,默认为(-1, -1),在核的中心位置。

5.2 示例#

import cv2
kernel_rect = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
kernel_cross = cv2.getStructuringElement(cv2.MORPH_CROSS, (7, 7))
kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7))
print("kernel_rect = \n", kernel_rect)
print("kernel_cross = \n", kernel_cross)
print("kernel_ellipse = \n", kernel_ellipse)
kernel_rect =
[[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 1 1]
[1 1 1 1 1 1 1]
[1 1 1 1 1 1 1]
[1 1 1 1 1 1 1]]
kernel_cross =
[[0 0 0 1 0 0 0]
[0 0 0 1 0 0 0]
[0 0 0 1 0 0 0]
[1 1 1 1 1 1 1]
[0 0 0 1 0 0 0]
[0 0 0 1 0 0 0]
[0 0 0 1 0 0 0]]
kernel_ellipse =
[[0 0 0 1 0 0 0]
[0 1 1 1 1 1 0]
[1 1 1 1 1 1 1]
[1 1 1 1 1 1 1]
[1 1 1 1 1 1 1]
[0 1 1 1 1 1 0]
[0 0 0 1 0 0 0]]
封面
示例歌曲
示例艺术家
封面
示例歌曲
示例艺术家
0:00 / 0:00