4. 形态学操作去除噪声并增强缺陷

任务目标

本案例使用OpenCV对含噪声的工业零件表面图像执行形态学处理:先通过开运算去除背景椒盐噪声,再通过闭运算填补缺陷内部细小空洞,最终使划痕、凹坑等缺陷在二值图像中呈现为连续、完整的连通区域,便于后续缺陷检测与特征提取。

环境依赖

需要 Python 3.8+、OpenCV(pip install opencv-python)、NumPy。图像读取使用灰度模式。

关键完整代码

import cv2
import numpy as np

def enhance_defects(image_path, kernel_size=5):
    """
    形态学去噪并增强缺陷
    流程: 灰度化 -> 自适应阈值二值化 -> 开运算(去椒盐噪声) -> 闭运算(填补缺陷空洞)
    返回: 增强后的二值图像(缺陷为白色前景)
    """
    # 1. 读取灰度图
    img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    if img is None:
        raise ValueError(f"无法读取图像: {image_path}")

    # 2. 自适应阈值二值化(反色: 缺陷区域变为白色)
    #    适用于光照不均的工业表面
    binary = cv2.adaptiveThreshold(
        img, 255,
        cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
        cv2.THRESH_BINARY_INV,
        blockSize=11, C=2
    )

    # 3. 定义结构元(矩形核)
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_size, kernel_size))

    # 4. 开运算: 先腐蚀后膨胀, 去除孤立噪点(椒盐噪声)
    opened = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)

    # 5. 闭运算: 先膨胀后腐蚀, 填补缺陷内部细小空洞/断裂
    closed = cv2.morphologyEx(opened, cv2.MORPH_CLOSE, kernel)

    return closed

def count_defects(binary_img, min_area=30):
    """
    统计缺陷连通域数量(验证增强效果)
    返回: (缺陷数量, 带轮廓标注的彩色图)
    """
    contours, _ = cv2.findContours(
        binary_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
    )
    valid = [c for c in contours if cv2.contourArea(c) >= min_area]

    # 生成标注图(便于可视化验证)
    vis = cv2.cvtColor(binary_img, cv2.COLOR_GRAY2BGR)
    cv2.drawContours(vis, valid, -1, (0, 0, 255), 2)

    return len(valid), vis

if __name__ == "__main__":
    # 使用示例(请替换为实际图像路径)
    INPUT_PATH = "surface_defect.png"

    # 执行形态学增强
    enhanced = enhance_defects(INPUT_PATH, kernel_size=5)

    # 统计增强前后的缺陷连通域数量
    raw_binary = cv2.adaptiveThreshold(
        cv2.imread(INPUT_PATH, cv2.IMREAD_GRAYSCALE), 255,
        cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2
    )
    before_cnt, _ = count_defects(raw_binary)
    after_cnt, vis_result = count_defects(enhanced)

    print(f"增强前缺陷连通域数量: {before_cnt}")
    print(f"增强后缺陷连通域数量: {after_cnt}")

    # 保存结果
    cv2.imwrite("enhanced_result.png", enhanced)
    cv2.imwrite("defect_contours.png", vis_result)
    print("结果已保存: enhanced_result.png, defect_contours.png")

运行与验证

  1. 准备一张含划痕或凹坑的工业零件灰度图(或使用相机拍摄后转灰度),保存为 surface_defect.png。
  2. 运行脚本:python morphology_enhance.py。
  3. 观察输出:enhanced_result.png 中缺陷区域应为白色连续块,背景噪声明显减少;defect_contours.png 中红色轮廓应完整包围缺陷。

通过判定标准

  • 增强后图像中孤立噪点(单像素或小团白点)数量显著少于增强前。
  • 同一缺陷在增强前若断裂为多个小连通域,增强后应合并为更少的连通域(after_cnt 小于 before_cnt),且每个连通域面积大于设定的 min_area(30像素)。
  • 若原始图像缺陷本身完整且无噪声,则增强前后连通域数量应保持一致(或仅因去噪而减少),不会出现缺陷消失的情况。

常见问题

  • 核尺寸选择:kernel_size=5 适用于常见工业图像(分辨率约500×500)。若噪声颗粒较大,可增大到7或9;若缺陷细节细小,则保持3~5,避免过度腐蚀导致缺陷消失。
  • 阈值方法:光照均匀时可将 adaptiveThreshold 替换为全局 cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU),效果更简洁。
  • 验证逻辑:count_defects 中的 min_area 用于过滤残留小噪点,若增强后仍存在大量面积小于该值的连通域,说明开运算核尺寸偏小,需调大。