Python 图像处理第二十八章|OpenCV 形态学操作进阶:腐蚀、膨胀、开运算、闭运算、梯度、顶帽黑帽

上一章我们学习了仿射与透视变换,完成了文档倾斜矫正。在 HSV 颜色掩码、二值图、轮廓检测的流程里,经常会出现细碎噪点、小空洞、边缘毛刺,直接拿去找轮廓很容易检出大量无效轮廓。形态学操作就是专门针对二值图像做形状修正的预处理工具。

前置说明:形态学一般作用于二值图(黑白图),白色为前景目标,黑色为背景;也可以作用于灰度图。核心都是基于卷积核(结构元 kernel)滑动扫描图像。

一、基础:腐蚀 erode 与膨胀 dilate

腐蚀和膨胀是所有形态学运算的基石,其余运算都是这两个的组合。

结构元 kernel:一个矩形、椭圆或十字形矩阵,我们可以用 cv2.getStructuringElement() 创建。

python 复制代码
# 生成结构元,ksize 是核大小,越大效果越强
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

1. 腐蚀 cv2.erode

腐蚀:吃掉前景白色区域的边缘,白色区域缩小。

作用:消除细小白色噪点、断开两个挨得很近的目标、磨平毛刺。

原理:核覆盖区域只要有一个像素是黑色,锚点位置就变黑。

python 复制代码
import cv2
import numpy as np

img = cv2.imread(r"D:\PYTHON\binary_mask.jpg")

if img is None:
    print("图片读取失败!")
    exit()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#5×5 矩形核
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
erode_img = cv2.erode(gray, kernel, iterations=1)

cv2.imshow("原图二值掩码", gray)
cv2.imshow("腐蚀结果", erode_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

2. 膨胀 cv2.dilate

膨胀:扩张前景白色区域,白色区域变大,向外"长胖"。

作用:填补目标内部小孔洞、连接距离很近的断裂线条、把分开的碎片合并。

原理:核覆盖区域只要有一个像素是白色,锚点位置就变白。

python 复制代码
import cv2
import numpy as np

img = cv2.imread(r"D:\PYTHON\binary_mask.jpg")

if img is None:
    print("图片读取失败!")
    exit()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
dilate_img = cv2.dilate(gray, kernel, iterations=1)

cv2.imshow("原图二值掩码", gray)
cv2.imshow("膨胀结果", dilate_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

参数 iterations:迭代次数,相当于重复执行该操作,次数越大效果越强。

二、组合运算:开运算、闭运算(最常用在掩码预处理)

OpenCV 提供 cv2.morphologyEx() 统一执行复合形态学操作,不用手动连续调用 erode、dilate。

1. 开运算 MORPH_OPEN

流程:先腐蚀,后膨胀。

核心用途:去掉前景外面细小的白色噪点,目标主体大小基本不变。

适合场景:HSV 颜色掩码里散落的小白噪点、孤立碎斑。

python 复制代码
import cv2
import numpy as np
img = cv2.imread(r"D:\PYTHON\mask_noise.jpg")

if img is None:
    print("图片读取失败!")
    exit()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
open_img = cv2.morphologyEx(gray, cv2.MORPH_OPEN, kernel)

cv2.imshow("带噪掩码", gray)
cv2.imshow("开运算(去外部小白噪点)", open_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

2. 闭运算 MORPH_CLOSE

流程:先膨胀,后腐蚀。

核心用途:填充前景目标内部的黑色小洞、缝隙,目标外轮廓基本不变。

适合场景:掩码目标里面有孔洞、文字笔画断裂、色块内部镂空。

python 复制代码
import cv2
import numpy as np
img = cv2.imread(r"D:\PYTHON\mask_hole.jpg")

if img is None:
    print("图片读取失败!")
    exit()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
close_img = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, kernel)

cv2.imshow("带孔洞掩码", gray)
cv2.imshow("闭运算(填充内部孔洞)", close_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

实操搭配口诀:外噪点开运算,内孔洞闭运算,HSV 掩码预处理经常开运算 + 闭运算连用。

三、进阶形态学:梯度、顶帽、黑帽

1. 形态学梯度 MORPH_GRADIENT

梯度 = 膨胀图 − 腐蚀图。

作用:提取物体轮廓边缘,得到目标的描边。

python 复制代码
gradient_img = cv2.morphologyEx(gray, cv2.MORPH_GRADIENT, kernel)

2. 顶帽(礼帽)MORPH_TOPHAT

顶帽 = 原图 − 开运算图。

作用:提取比核尺寸更小的亮区域,用来提取暗背景上细小亮纹理、微弱亮线条。

3. 黑帽 MORPH_BLACKHAT

黑帽 = 闭运算图 − 原图。

作用:提取比核尺寸更小的暗区域,提取亮目标内部细小暗缝隙、黑点。

四、六种形态学操作完整对比代码

下面把六种操作放在一起运行,方便直观对比效果差异。

python 复制代码
import cv2
import numpy as np
img = cv2.imread(r"D:\PYTHON\binary.jpg")

if img is None:
    print("图片读取失败!")
    exit()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
erode = cv2.erode(gray, kernel)
dilate = cv2.dilate(gray, kernel)

open_op = cv2.morphologyEx(gray, cv2.MORPH_OPEN, kernel)
close_op = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, kernel)
gradient = cv2.morphologyEx(gray, cv2.MORPH_GRADIENT, kernel)
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, kernel)
blackhat = cv2.morphologyEx(gray, cv2.MORPH_BLACKHAT, kernel)

cv2.imshow("erode 腐蚀", erode)
cv2.imshow("dilate 膨胀", dilate)
cv2.imshow("open 开运算", open_op)
cv2.imshow("close 闭运算", close_op)
cv2.imshow("gradient 梯度", gradient)
cv2.imshow("tophat 顶帽", tophat)
cv2.imshow("blackhat 黑帽", blackhat)
cv2.waitKey(0)
cv2.destroyAllWindows()

把同一张二值图依次跑完这六种操作,效果差异其实非常直观:腐蚀 让白色前景整体收缩一圈,细小噪点直接消失;膨胀 让白色前景向外扩张,小孔洞和断裂缝隙被填上;开运算 先腐蚀后膨胀,只去掉前景外部的零散小白噪点,主体大小基本不变;闭运算 先膨胀后腐蚀,只填补前景内部的黑色小洞,外轮廓基本不变;形态学梯度 输出的是膨胀图与腐蚀图之差,得到的是目标的一圈描边;顶帽 输出原图与开运算图之差,突出比核更小的亮区域;黑帽输出闭运算图与原图之差,突出比核更小的暗区域。

建议读者准备一张同时包含外部小噪点、内部小孔洞、细线条和边缘毛刺的二值图,用同一份代码依次运行六种操作,把七张窗口并排观察。这样比分别用不同图片测试更容易看出每种操作到底改变了什么,也更容易理解"开运算去外噪、闭运算填内洞"这类口诀背后的实际画面。

结构元尺寸是影响效果强弱的关键变量,建议固定同一张图,把 ksize 从 3×3 逐步调到 15×15,重点观察以下几点:

  • 3×3:效果最轻微,只对单个像素级的噪点和毛刺起作用,目标主体形状几乎不变,适合作为保底参数。
  • 5×5:日常掩码预处理的常用值,能清掉大部分细小噪点和小孔洞,同时不明显破坏目标轮廓。
  • 7×7 到 9×9:去噪和填洞能力明显增强,但腐蚀会让细笔画、细线条变细甚至断开,膨胀会让相邻目标粘连成一片。
  • 11×11 到 15×15:效果最强,小目标可能被整体腐蚀掉,大目标边缘也会明显变形;此时梯度描边会变粗,顶帽和黑帽提取出的区域也会明显减少。
  • 形状差异:矩形核在水平和垂直方向作用均匀,椭圆核边缘过渡更平滑,十字核只沿水平和垂直方向作用,处理方向性纹理时要优先考虑非正方形核。

一句话总结调参思路:先用小核确认效果方向,再逐步加大核尺寸观察目标是否被破坏,找到"噪点去干净、主体还完整"的那个临界尺寸,通常就是这张图最合适的结构元大小。

五、六种操作速查表

操作 OpenCV 常量 等价组合 主要作用
腐蚀 cv2.erode --- 收缩前景,去小噪点
膨胀 cv2.dilate --- 扩张前景,填小孔洞
开运算 cv2.MORPH_OPEN 先腐蚀后膨胀 去外部噪点,分离目标
闭运算 cv2.MORPH_CLOSE 先膨胀后腐蚀 填内部孔洞,连接断裂
形态学梯度 cv2.MORPH_GRADIENT 膨胀 − 腐蚀 提取轮廓边缘
顶帽 cv2.MORPH_TOPHAT 原图 − 开运算 提取亮小区域
黑帽 cv2.MORPH_BLACKHAT 闭运算 − 原图 提取暗小区域

六、综合实战:车牌区域粗定位

下面用一个完整示例演示形态学操作在车牌粗定位中的应用:先灰度化、边缘检测,再用闭运算连接字符,最后用开运算去噪。

python 复制代码
import cv2
import numpy as np

img = cv2.imread("car.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#1. 高斯模糊去噪
blur = cv2.GaussianBlur(gray, (5, 5), 0)

#2. Sobel 水平边缘
sobel_x = cv2.Sobel(blur, cv2.CV_16S, 1, 0, ksize=3)
abs_x = cv2.convertScaleAbs(sobel_x)

#3. 二值化
_, binary = cv2.threshold(abs_x, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)

#4. 闭运算连接字符
kernel_close = cv2.getStructuringElement(cv2.MORPH_RECT, (17, 5))
closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel_close)

#5. 开运算去除小噪点
kernel_open = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
opened = cv2.morphologyEx(closed, cv2.MORPH_OPEN, kernel_open)

#6. 查找轮廓
contours, _ = cv2.findContours(opened, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
    x, y, w, h = cv2.boundingRect(cnt)
    ratio = w / float(h)
    area = cv2.contourArea(cnt)

    # 车牌大致比例 2.5 ~ 5.5,面积过滤
    if 2.5 < ratio < 5.5 and area > 1000:
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

这个例子中,闭运算的横向结构元素(17×5)专门用于把横向排列的字符连成一块,开运算则负责清理残留噪点。结构元素的形状和尺寸选择,往往比操作本身更关键。

七、性能与调参建议

  • 优先使用 cv2.morphologyEx:它内部对开闭运算做了优化,比手动先腐蚀再膨胀更快。
  • 结构元素尽量小:3×3 或 5×5 通常足够,过大容易破坏目标形状。
  • 迭代次数替代大核 :需要更强效果时,可增加 iterations,但要注意计算量。
  • 方向性结构元素:处理横向或纵向纹理时,使用非正方形核(如 1×15、15×1)效果更好。
  • 彩色图像先转灰度:形态学操作通常作用于单通道图像,彩色图需先转换或分通道处理。

八、本章小结

本章系统梳理了 OpenCV 中六种核心形态学操作:腐蚀、膨胀、开运算、闭运算、形态学梯度、顶帽与黑帽。它们本质上都是结构元素与图像局部区域的集合运算,理解"先腐蚀后膨胀""先膨胀后腐蚀"的组合逻辑,就能灵活应对去噪、填洞、连断、提边、提取亮暗小目标等常见需求。

下一章将进入图像轮廓检测与特征分析,继续把形态学处理后的结果转化为可量化的几何信息。

相关推荐
美狐美颜SDK开放平台2 小时前
视频美颜SDK如何实现动态贴纸跟随?人脸追踪技术解析
android·人工智能·计算机视觉·音视频·直播美颜sdk
鬓戈2 小时前
手机拍屏幕行为模型二次训练方案
人工智能
拜小白3 小时前
【论文解读】PanoRoom:从球面到3D布局
深度学习·计算机视觉·全景图
BD_Marathon3 小时前
【Python】标准多态和鸭子多态
python
木头科技3 小时前
【AI 工程化第十六篇】Spring AI 多模态 RAG 实战:图片、扫描件、表格与图文证据链
java·人工智能·spring
龙石数据3 小时前
龙石 AI 智能体开发平台入选2026全球数据管理峰会数据治理创新实践案例
大数据·人工智能
拜小白3 小时前
【论文解读】(JLDNet) Joint 3D Layout and Depth:一张全景图同时算出房间骨架和像素深度
深度学习·计算机视觉·全景图
ZDGJ60993 小时前
个人参与国际期货交易有哪些优势
人工智能
用户8356290780513 小时前
Python 操作 Excel:创建数组公式与 R1C1 公式
后端·python