第 9 章 形态学图像处理
学习目标:掌握基于集合论的形状分析工具——腐蚀、膨胀、开、闭、顶帽、黑帽、击中-未击中、骨架化、距离变换,理解它们如何解决实际的”形状问题”。 形态学(Morphology)= 形状的学问,由法国学派(Matheron, Serra)在矿物分析中诞生,1960-80 年代发展为独立分支。
9.1 集合论基础
9.1.1 为什么用集合?
二值图像 = 一个平面上的点集: [ A = {(x, y) : f(x, y) = 1} ]
- 前景 = 集合内点(1)
- 背景 = 集合补(0)
形态学 = 用集合运算操作形状。
9.1.2 基本集合运算
| 运算 | 符号 | 定义 |
|---|---|---|
| 并 | (A \cup B) | (x \in A \text{ or } x \in B) |
| 交 | (A \cap B) | (x \in A \text{ and } x \in B) |
| 补 | (A^c) | (x \notin A) |
| 差 | (A - B) | (A \cap B^c) |
| 平移 | ((A)_z) | ({a + z : a \in A}) |
| 反射 | (\hat{B}) | ({-b : b \in B}) |
9.1.3 结构元 (Structuring Element, SE)
核心概念。SE 是一个小”探针”,用来”扫描”图像做形状分析。
常见 SE:
方形 3×3: 十字 3×3: 线段 5×1:┌─┬─┬─┐ ┌─┬─┬─┐│■│■│■│ │ │■│ │ ■■■■■├─┼─┼─┤ ├─┼─┼─┤│■│■│■│ │■│■│■│├─┼─┼─┤ ├─┼─┼─┤│■│■│■│ │ │■│ │└─┴─┴─┘ └─┴─┴─┘
圆盘 5×5:┌─┬─┬─┬─┬─┐│ │■│■│■│ ││■│■│■│■│■││■│■│■│■│■││■│■│■│■│■││ │■│■│■│ │└─┴─┴─┴─┴─┘SE 的原点(origin,通常是中心)决定平移位置。
import cv2se_rect = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))se_ellipse= cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))se_cross = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))9.2 腐蚀与膨胀(两大基础运算)
9.2.1 腐蚀 (Erosion)
定义 9.1: [ A \ominus B = {z : (B)_z \subseteq A} ]
直觉:SE (B) 在图像 (A) 内”完全装得下”的所有中心位置。
A (前景): B (3×3 方块): A⊖B: █████████ █████ █████████ ■■■ █████ █████████ ■★■ █████ ← 边界向内缩一圈 █████████ ■■■ █████████效果:
- 前景变小 / 边界向内收缩
- 小物体(比 B 还小)被完全消除
- 连在一起的物体可能分开
- 窄连接处被切断
eroded = cv2.erode(binary, kernel, iterations=1)9.2.2 膨胀 (Dilation)
定义 9.2: [ A \oplus B = {z : (\hat{B})_z \cap A \ne \emptyset} ]
直觉:SE 反射后,与 (A) 有任何重叠的所有中心位置。
等价:(A \oplus B = \bigcup_{a \in A} (B)_a)(把 B 贴在 A 的每个点上,取并)
A: A⊕B: █████ █████████ █████ → █████████ █████ █████████ ← 向外膨胀一圈效果:
- 前景变大 / 边界向外扩展
- 填充小孔、裂缝
- 连接邻近的物体(注意:可能过度连接)
dilated = cv2.dilate(binary, kernel, iterations=1)9.2.3 对偶性
腐蚀和膨胀是对偶的(De Morgan 律的形态学版本):
[ (A \ominus B)^c = A^c \oplus \hat{B} ]
意义:对前景腐蚀 = 对背景膨胀(反之亦然)。
9.2.4 性质
- 平移不变:((A)_z \ominus B = (A \ominus B)_z)
- 增函数:(A \subseteq B \Rightarrow A \ominus C \subseteq B \ominus C)
- 结合性:(A \oplus (B \oplus C) = (A \oplus B) \oplus C)(级联 SE 等价于大 SE)
实用性质:
- 两个 3×3 膨胀 = 一次 5×5 膨胀
- N 次 3×3 = 一次 ((2N+1) \times (2N+1))
- 大 SE 可拆为小 SE 级联 → 加速(FPGA/嵌入式常用)
9.2.5 灰度图像的腐蚀/膨胀
对灰度图扩展: [ (A \ominus B)(x) = \min_{s \in B} {A(x + s)} ] [ (A \oplus B)(x) = \max_{s \in B} {A(x + s)} ]
即局部最小 / 最大滤波。
9.3 开运算与闭运算
9.3.1 开运算 (Opening)
[ A \circ B = (A \ominus B) \oplus B ]
流程:先腐蚀,再膨胀。
直觉:让 SE 在 (A) 内部”滚动”,能滚到的地方 = (A \circ B)。
A (有小点 + 细连): A ⊖ B: A ⊖ B ⊕ B: ██ ██ · ██ ██ ██ ██ ██████· → ████ → ██████ ██ ██· ██ ██ ██ ██ ↑ 小点消失 细连接断开后不恢复效果:
- 去除小物体(比 SE 小的)
- 断开细连接
- 平滑轮廓(凸出物被磨平)
- 物体大小基本不变(主体被保留)
9.3.2 闭运算 (Closing)
[ A \bullet B = (A \oplus B) \ominus B ]
流程:先膨胀,再腐蚀。
直觉:让 SE 在 (A) 的外部滚动,填不进去的地方 = (A \bullet B)。
效果:
- 填充小孔(比 SE 小的)
- 连接近邻物体
- 平滑轮廓(凹陷处被填)
9.3.3 开 vs 闭:对偶
[ (A \circ B)^c = A^c \bullet \hat{B} ]
开对前景 = 闭对背景。
9.3.4 幂等性
[ (A \circ B) \circ B = A \circ B ] [ (A \bullet B) \bullet B = A \bullet B ]
再做一次开 / 闭,结果不变。这是其他组合没有的性质。
9.3.5 典型应用
指纹去毛刺:
原图:指纹 + 细小噪点→ 开运算去噪点连通断裂字符:
OCR 中字符扫描残缺→ 闭运算补全车牌预处理:
去除小噪声(开)→ 合并小字符间的间隙(闭)opened = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)closed = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)9.4 击中-未击中变换 HMT
9.4.1 动机
想检测图像中特定形状的出现位置(如十字形、拐角)。
9.4.2 定义
用两个 SE:(B_1)(前景模板)、(B_2)(背景模板),通常 (B_1 \cap B_2 = \emptyset)。
[ A \otimes B = (A \ominus B_1) \cap (A^c \ominus B_2) ]
直觉:寻找满足
- “(B_1) 在 (A) 内”(前景匹配)
- “(B_2) 在 (A) 外”(背景匹配)
的所有位置。
9.4.3 应用:角点检测
想找”左上角”(前景在右下、背景在左上):
B_1: B_2:│ · · ·│ │■ ■ ·││· ■ ■│ │■ · ·││· ■ ■│ │· · ·│击中位置 = 所有左上角点。
9.4.4 细化、增厚(基于 HMT)
细化 (Thinning): [ A \oslash B = A - (A \otimes B) ]
反复用不同方向的 (B),逐步去除前景边界上”非结构性”的点。
增厚反向。
9.5 基本形态学算法
9.5.1 边界提取
[ \partial A = A - (A \ominus B) ]
前景 - 腐蚀后前景 = 边界。3×3 SE 给出 1 像素厚边界。
9.5.2 区域填充(孔洞填充)
目的:二值图中某物体内有小黑洞,想填实。
算法:
X_0 = 孔洞内某点X_k = (X_{k-1} ⊕ B) ∩ A^c (膨胀 + 只在背景内增长)重复直到 X_k = X_{k-1}填充结果 = X_k ∪ AOpenCV:
# 洞填充:先求背景的 flood fill 然后取反h, w = binary.shapemask = np.zeros((h+2, w+2), np.uint8)cv2.floodFill(binary.copy(), mask, (0, 0), 255)filled = binary | cv2.bitwise_not(binary) # 简化示意9.5.3 连通分量提取
4-连通 vs 8-连通:
4-连通: 只考虑上下左右 8-连通: 加上对角 · ■ · ■ ■ ■ ■ ★ ■ ■ ★ ■ · ■ · ■ ■ ■算法(两遍扫描):
第一遍:逐像素扫描 若当前前景: 看上/左邻居的标签 最小的标签赋给当前 若两邻居标签不同,记录"等价"第二遍:根据等价合并标签OpenCV:
num_labels, labels = cv2.connectedComponents(binary, connectivity=8)num, labels, stats, centroids = cv2.connectedComponentsWithStats(binary)# stats[i] = [x, y, w, h, area]用途:目标计数(细胞、米粒)、去小物体(面积阈值)。
9.5.4 凸包
定义:包含前景的最小凸集。
形态学算法(Gonzalez):用 4 个 HMT 模板反复增厚直到收敛。
实用:OpenCV 的 cv2.convexHull 基于 Graham 扫描或 Sklansky 算法,比形态学方法快。
9.5.5 细化(骨架化前奏)
目标:把宽条缩成 1 像素宽的”骨架”。
HMT 细化(Guo-Hall / Zhang-Suen):反复用 8 个方向 HMT 去除边界像素,保持连通。
9.6 骨架化 (Skeletonization)
9.6.1 骨架的直觉:最大内切圆心轨迹
定义 9.3(Blum 中轴):前景内所有点 (p),存在至少两个最近的背景点,则 (p) 在骨架上。
等价直觉:想象同时从前景所有边界点向内”烧”,相遇的地方就是骨架。
矩形: 骨架:█████████ · · · · · · · · ·█████████ · · · ━━━━━ · · ·█████████ → · · · · · · · · ·█████████ · · · · · · · · ·9.6.2 形态学定义
[ S(A) = \bigcup_{k=0}^{K} S_k(A) ] [ S_k(A) = (A \ominus kB) - [(A \ominus kB) \circ B] ]
- (kB) 表示 SE (B) 的 (k) 次膨胀
- ((A \ominus kB)):腐蚀 (k) 次
- 再减去对它开运算的结果
性质:
- 骨架是前景的细骨架表示
- 可以从 (S) 重建 (A)(用最大内切圆):(A = \bigcup_{k} (S_k \oplus k B))
9.6.3 快速骨架化(Zhang-Suen 1984)
算法:
对每个前景像素 p,检查 8 邻居 (p1..p8):条件 1: 2 ≤ N(p) ≤ 6 (N = 前景邻居数)条件 2: S(p) = 1 (0→1 跃迁次数)条件 3: p1·p3·p5 = 0 (子迭代 1) 或 p1·p3·p7 = 0 (子迭代 2)条件 4: p3·p5·p7 = 0 (子迭代 1) 或 p1·p5·p7 = 0 (子迭代 2)
若四条件都满足 → 标记删除两轮子迭代交替执行,直到无变化效果:保证连通、1 像素宽、中心化。
应用:
- OCR 字符预处理
- 指纹脊线提取
- 血管追踪
- 手写识别
from skimage.morphology import skeletonizeskel = skeletonize(binary > 0)9.7 距离变换
9.7.1 定义
定义 9.4:对二值图像 (A),距离变换 (D) 满足: [ D(x) = \min_{y \in A^c} \text{dist}(x, y) ]
每个前景像素到最近背景的距离。
二值图: 距离变换 (D8, 8-连通):0 0 0 0 0 0 0 0 0 00 1 1 1 0 0 1 1 1 00 1 1 1 0 0 1 2 1 0 ← 中心离背景 2 步0 1 1 1 0 0 1 1 1 00 0 0 0 0 0 0 0 0 09.7.2 距离度量
| 度量 | 公式 | 备注 |
|---|---|---|
| D4 (曼哈顿) | (|dx| + |dy|) | 菱形扩展 |
| D8 (切比雪夫) | (\max(|dx|, |dy|)) | 正方形扩展 |
| 欧氏 | (\sqrt{dx^2 + dy^2}) | 各向同性 |
| 倒角 | 整数近似欧氏(3-4、5-7-11) | 速度+质量折衷 |
9.7.3 计算算法
串行两遍扫描(Rosenfeld)
前向扫描 (从左上到右下): D(x, y) = min( D(x, y) 原值, D(x-1, y) + 1, D(x, y-1) + 1, D(x-1, y-1) + sqrt(2), D(x+1, y-1) + sqrt(2) )
反向扫描 (从右下到左上): 类似,考虑反方向邻居复杂度 (O(N)),线性时间。
Felzenszwalb-Huttenlocher 2004:严格欧氏 (O(N))
基于抛物线下包络,现代标准。
dist = cv2.distanceTransform(binary, cv2.DIST_L2, 5)9.7.4 应用
骨架化
距离变换后,局部极大值位置 ≈ 骨架(每个极大值是一个最大内切圆心)。
分水岭分割(第 10 章)
以距离变换为”地形高度”,距离大的点作为 marker → 分水岭分割粘连物体。
形状分析
- 形状内切圆半径 = 最大距离值
- 形状厚度分布直方图
9.8 顶帽与黑帽变换
9.8.1 顶帽 (Top-Hat)
[ \text{TH}(A) = A - (A \circ B) ]
直觉:原图 - 开运算。
- 开运算去除了 比 SE 小的前景细节
- 相减得到的就是那些细节
提取:比 SE 小、亮度高(在暗背景上)的结构。
9.8.2 黑帽 (Bottom-Hat / Black-Hat)
[ \text{BH}(A) = (A \bullet B) - A ]
直觉:闭运算 - 原图。
- 闭运算填充了 比 SE 小的暗细节 / 孔
- 相减得到那些细节
提取:比 SE 小、亮度低(暗细节)的结构。
9.8.3 应用:非均匀光照校正
经典场景:打印物体 + 不均匀光照 → OCR 困难。
做法(灰度形态学):
se = cv2.getStructuringElement(cv2.MORPH_RECT, (51, 51)) # 大 SEbackground = cv2.morphologyEx(gray, cv2.MORPH_OPEN, se)corrected = cv2.subtract(gray, background) # = top-hat# 现在可以清晰二值化_, binary = cv2.threshold(corrected, 0, 255, cv2.THRESH_OTSU)原理:
- 大 SE 的开运算 ≈ 光照背景(因为它”滚”过细节,保留粗尺度趋势)
- 原图 - 背景 = 前景(与光照无关)
这是形态学在文档处理的最经典应用。
9.9 灰度形态学与重建
9.9.1 灰度 SE
灰度形态学中 SE 也是灰度(可有高度)。基本运算扩展为极值运算(9.2.5)。
9.9.2 形态学重建
标记图 (F) + 掩膜 (G): [ R_G(F) = \lim_{n \to \infty} (F \oplus B) \wedge G ] (反复膨胀 F,但每次都用 G 截断,直到收敛)
用途:
- 断开粘连的细胞:以距离变换局部极大为标记,重建
- 提取特定形状的对象:标出想要的位置,重建即可
- 顶帽重建(Opening by Reconstruction):比普通开运算更好地保留原形状
9.10 实战:形态学处理的设计思路
9.10.1 常见问题清单
| 问题 | 用什么 |
|---|---|
| 去小噪点 | 开运算 |
| 补小孔 | 闭运算 |
| 连接字符 | 闭运算(水平 SE) |
| 断开粘连 | 开运算(圆盘 SE) |
| 提取粗尺度背景 | 大 SE 的开运算 |
| 校正不均匀光照 | 顶帽变换 |
| 提取边界 | (A - (A \ominus B)) |
| 骨架 | Zhang-Suen / 距离变换 |
| 最大内切圆 | 距离变换的极大 |
| 形状匹配 | HMT |
| 连通分量计数 | connectedComponents |
9.10.2 SE 形状的选择
| SE | 保留什么 |
|---|---|
| 圆盘 | 各向同性(无方向偏好) |
| 水平线 | 水平结构(线条、文字行) |
| 垂直线 | 垂直结构 |
| 方形 | 简单 + 快(仅轻微方向偏向) |
| 十字 | 简单且稍少像素 |
经验:形状分析用圆盘;方向敏感检测用线段;通用场合用方形(最快)。
9.10.3 SE 大小
SE 大小 = “要去除 / 保留的尺度”。
- 去比 10 像素小的噪点 → 11×11 或更小
- 连接间距 < 5 的字符 → 5×1 水平 SE 闭运算
- 校正 100 像素尺度的光照 → 101×101 开运算
9.11 本章要点与面试考点
✅ 必须掌握
- 腐蚀、膨胀的集合定义与直觉
- 开 / 闭运算的公式、幂等性、去小物体/补小孔
- 腐蚀与膨胀的对偶性
- 击中-未击中变换
- 边界提取、孔洞填充、连通分量
- 骨架化的三种思路(形态学、HMT、距离变换)
- 顶帽/黑帽及其在光照校正的应用
- 灰度形态学 = 极值滤波
💡 高频面试题
Q1. 开运算和闭运算分别能解决什么问题?
答:
- 开 (Open) = 先腐蚀后膨胀 → 去除比 SE 小的前景(小噪点、细连接)
- 闭 (Close) = 先膨胀后腐蚀 → 填充比 SE 小的孔、连接近邻物体
- 两者都能平滑轮廓,但开磨凸出,闭填凹陷
Q2. 为什么顶帽变换能提取非均匀光照下的细节?
答:用大 SE 的开运算对灰度图处理,结果近似光照背景(大尺度缓变)。原图减去它 = 前景细节(高频信息),与光照无关。这就是”TopHat = 原图 - 开运算”。
Q3. 灰度形态学的腐蚀等价于什么滤波?
答:局部最小滤波。灰度腐蚀 ((A \ominus B)(x) = \min_{s \in B} A(x + s)),即邻域最小值。膨胀为最大值滤波。开运算 = min 后 max(低通+保边)。
Q4. 骨架化的几种方法有什么区别?
答:
- 形态学骨架((S = \bigcup S_k)):严格、可重建原形,但骨架可能不连通
- HMT 细化(Zhang-Suen):保证连通、1 像素宽,但对噪声敏感
- 距离变换极大值:简单、快,但极大值可能不连续
工业上常用 Zhang-Suen(连通性好)。
Q5. 连通分量的 4-连通和 8-连通有何区别?
答:4-连通只考虑上下左右 4 邻居(产生菱形邻域),8-连通包括对角 8 邻居(方形邻域)。拓扑悖论:前景和背景若都用 4(或都用 8),可能出现连通性矛盾。标准做法:前景 8-连通 + 背景 4-连通。
Q6. 腐蚀和膨胀的对偶性有何工程意义?
答:((A \ominus B)^c = A^c \oplus \hat{B}) 意味着:对前景做腐蚀 = 对背景做膨胀。实现时只需一个操作,另一个由取反得到。也解释了开/闭的对偶:开 ↔ 闭。
Q7. 击中-未击中与模板匹配的区别?
答:HMT 用两个 SE 分别匹配前景与背景模板,严格形状检测(二值);模板匹配(如 SAD/NCC)基于灰度相关,连续灰度图。HMT 对少量噪声脆弱;匹配对光照和噪声鲁棒但慢。
Q8. 为什么形态学操作能级联加速?
答:结合律 ((A \oplus B) \oplus C = A \oplus (B \oplus C))。一个大 SE 可分解为小 SE 的级联(如 9×9 = 3×3 + 3×3 + 3×3),每次只做 3×3 卷积,总复杂度 (O(9N)) << (O(81N))。圆盘 SE 的近似分解也常用。
9.12 延伸阅读
- Matheron, Random Sets and Integral Geometry(形态学创始文献)
- Serra, Image Analysis and Mathematical Morphology(奠基教材)
- Soille, Morphological Image Analysis: Principles and Applications(工程手册)
- Zhang & Suen, “A Fast Parallel Algorithm for Thinning Digital Patterns”, 1984
- Felzenszwalb & Huttenlocher, “Distance Transforms of Sampled Functions”, 2012
- scikit-image morphology:https://scikit-image.org/docs/stable/api/skimage.morphology.html
下一章:我们把”形态学”拓展到”语义”——如何让算法自动理解”哪些像素属于同一个物体”?这就是图像分割。
如果這篇文章對你有幫助,歡迎分享給更多人!
部分資訊可能已經過時





















