【计算机视觉】基于数学形态学的保留边缘图像去噪

目录

一、引言

二、数学形态学去噪的基础:开运算与闭运算

三、保边缘去噪的关键策略

1. 自适应结构元素(SE)设计

2. 基于边缘检测的选择性形态学操作

3. 形态学滤波的组合策略

4. 形态学重构(Morphological Reconstruction)

四、基于数学形态学的保留边缘图像去噪的Python代码完整实现

​编辑

五、Python代码完整解释

(一)核心设计思想

(二)模块功能与实现细节

1. 噪声生成模块(generate_noisy_image)

2. 形态学去噪核心流水线(morphological_denoising_pipeline)

(1)自适应结构元素(SE)设计

(2)基础去噪:开运算 + 闭运算

(3)边缘保护:形态学重构

(4)细节增强:顶帽 + 底帽变换

3. 定量指标计算(calculate_metrics)

4. 可视化模块(visualize_results)

(三)算法整体流程总结

六、总结


一、引言

【计算机视觉】形态学的去噪-CSDN博客中,评论区中有人问道:“如何利用数学形态学进行高效的图像去噪处理,并且在去噪过程中如何保持图像的边缘和细节信息?”确实,在传统的形态学去噪中存在“过度平滑导致边缘模糊” 的问题,因此,本文将会深入讲解基于数学形态学的保留边缘图像去噪的原理和Python代码完整实现。

本文用到的图片:

二、数学形态学去噪的基础:开运算与闭运算

数学形态学的基本操作(腐蚀、膨胀)是去噪的基础,其中开运算闭运算是最常用的去噪工具:

  • 开运算(Opening):先腐蚀后膨胀,可去除图像中小于结构元素的亮噪声(如亮背景上的暗点噪声),同时基本保持较大目标的形状。
  • 闭运算(Closing):先膨胀后腐蚀,可去除图像中小于结构元素的暗噪声(如暗背景上的亮点噪声),同样对大目标影响较小。

对于含椒盐噪声的图像,开运算可去除 “盐噪声”(亮点),闭运算可去除 “椒噪声”(暗点)。

三、保边缘去噪的关键策略

单纯的开 / 闭运算可能模糊边缘,需通过以下优化策略平衡去噪与保边:

1. 自适应结构元素(SE)设计

结构元素的大小和形状直接影响去噪效果和边缘保留能力:

  • 大小选择:结构元素需略大于噪声尺寸(如噪声为 3x3 像素,SE 选 5x5),但不宜过大(否则会模糊边缘)。
  • 形状选择:根据图像边缘方向动态调整 SE 形状(如对线状边缘用线形 SE,对圆形边缘用圆形 SE),减少对边缘的侵蚀。
  • 多尺度 SE:结合不同大小的 SE(如 3x3、5x5),小 SE 保留细节,大 SE 去除大噪声,最后融合结果。

对于含细微纹理的图像,用小尺寸圆形 SE 进行开运算,既能去除小噪声,又能保留纹理细节。

2. 基于边缘检测的选择性形态学操作

先通过形态学梯度(如膨胀 - 腐蚀)检测边缘,在边缘区域 “弱化” 或 “跳过” 形态学操作,仅在平滑区域强化去噪:

  • 步骤
    1. 计算图像的形态学梯度(gradient = dilate(img) - erode(img)),标记边缘区域。
    2. 对非边缘区域应用开 / 闭运算去噪。
    3. 对边缘区域保留原始像素或仅用小 SE 轻量处理,避免边缘模糊。

优势:精准区分噪声与边缘,针对性处理。

3. 形态学滤波的组合策略

通过开 / 闭运算的组合(如 “开 - 闭” 或 “闭 - 开”),同时去除亮、暗噪声,并减少边缘损失:

  • 顶帽变换(Top-hat)tophat = img - opening(img),可提取被亮噪声掩盖的暗细节(如纹理)。
  • 底帽变换(Bottom-hat)bottomhat = closing(img) - img,可提取被暗噪声掩盖的亮细节。
  • 组合应用:对去噪后的图像叠加顶帽 / 底帽结果,恢复被形态学操作模糊的细节。

对于低对比度图像,先用闭运算去除暗噪声,再用顶帽变换恢复丢失的亮细节。

4. 形态学重构(Morphological Reconstruction)

一种更精细的去噪方法,通过 “标记图像” 和 “模板图像” 的迭代运算,在去噪的同时严格保留边缘:

  • 步骤
    1. 以原始图像为 “模板”,以腐蚀后的图像为 “标记”(标记图像包含噪声但边缘被保留)。
    2. 迭代执行膨胀操作,直到标记图像不再变化(被模板图像约束,不会越过边缘)。
  • 优势:相比传统开 / 闭运算,重构能更精确地保留边缘轮廓,尤其适合复杂纹理图像。

四、基于数学形态学的保留边缘图像去噪的Python代码完整实现

import cv2
import numpy as np
import matplotlib.pyplot as plt
from skimage.metrics import peak_signal_noise_ratio as psnr
from skimage.metrics import structural_similarity as ssim

# 设置中文显示
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False


def generate_noisy_image(clean_img, salt_ratio=0.01, pepper_ratio=0.01):
    """生成含椒盐噪声的图像,模拟真实噪声干扰"""
    noisy_img = clean_img.copy()
    total_pixels = clean_img.size

    # 添加盐噪声(亮点)
    salt_pixels = int(total_pixels * salt_ratio)
    coords = [np.random.randint(0, i, salt_pixels) for i in clean_img.shape]
    noisy_img[coords[0], coords[1]] = 255

    # 添加椒噪声(暗点)
    pepper_pixels = int(total_pixels * pepper_ratio)
    coords = [np.random.randint(0, i, pepper_pixels) for i in clean_img.shape]
    noisy_img[coords[0], coords[1]] = 0

    return noisy_img, coords[0], coords[1]  # 返回噪声坐标用于可视化


def morphological_denoising_pipeline(noisy_img):
    """数学形态学去噪流水线"""
    # 1. 定义自适应结构元素
    se_small = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
    se_large = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))

    # 2. 基础去噪
    opening = cv2.morphologyEx(noisy_img, cv2.MORPH_OPEN, se_large)
    basic_denoised = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, se_large)

    # 3. 形态学重构
    marker = cv2.erode(basic_denoised, se_small)
    template = basic_denoised.copy()
    while True:
        prev_marker = marker
        marker = cv2.dilate(marker, se_small)
        marker = np.minimum(marker, template)
        if np.array_equal(marker, prev_marker):
            break
    reconstructed = marker

    # 4. 细节增强
    tophat = cv2.morphologyEx(noisy_img, cv2.MORPH_TOPHAT, se_small)
    bottomhat = cv2.morphologyEx(noisy_img, cv2.MORPH_BLACKHAT, se_small)
    enhanced = reconstructed + tophat - bottomhat
    enhanced = np.clip(enhanced, 0, 255).astype(np.uint8)

    return {
        "noisy": noisy_img,
        "basic_denoised": basic_denoised,
        "reconstructed": reconstructed,
        "enhanced": enhanced,
        "se_small": se_small,
        "se_large": se_large,
        "tophat": tophat,
        "bottomhat": bottomhat
    }


def calculate_metrics(original, processed):
    """计算去噪效果定量指标"""
    # PSNR(峰值信噪比,越高越好)
    psnr_val = psnr(original, processed, data_range=255)
    # SSIM(结构相似性,越接近1越好)
    ssim_val = ssim(original, processed, data_range=255)
    return {"psnr": psnr_val, "ssim": ssim_val}


def visualize_noise_removal(noisy_img, enhanced_img, salt_coords, pepper_coords):
    """可视化噪声去除情况(标记未去除的噪声)"""
    # 标记残留的盐噪声
    salt_residual = np.zeros_like(noisy_img)
    salt_residual[salt_coords[0], salt_coords[1]] = 255 * (enhanced_img[salt_coords[0], salt_coords[1]] == 255)

    # 标记残留的椒噪声
    pepper_residual = np.zeros_like(noisy_img)
    pepper_residual[pepper_coords[0], pepper_coords[1]] = 255 * (enhanced_img[pepper_coords[0], pepper_coords[1]] == 0)

    return salt_residual, pepper_residual


def visualize_local_details(original, noisy, enhanced, roi=(200, 250, 100, 150)):
    """提取局部区域(如眼睛、纹理)进行放大对比"""
    x, y, w, h = roi  # 感兴趣区域:(x,y)为左上角,w/h为宽高
    original_roi = original[x:x + w, y:y + h]
    noisy_roi = noisy[x:x + w, y:y + h]
    enhanced_roi = enhanced[x:x + w, y:y + h]
    return original_roi, noisy_roi, enhanced_roi


def visualize_results(original, results, salt_coords, pepper_coords):
    """可视化:多维度展示去噪效果"""
    # 计算定量指标
    metrics = {
        "noisy": calculate_metrics(original, results["noisy"]),
        "basic": calculate_metrics(original, results["basic_denoised"]),
        "recon": calculate_metrics(original, results["reconstructed"]),
        "enhanced": calculate_metrics(original, results["enhanced"])
    }

    # 噪声残留可视化
    salt_residual, pepper_residual = visualize_noise_removal(
        results["noisy"], results["enhanced"], salt_coords, pepper_coords
    )

    # 局部细节放大(以Lena图像的眼睛区域为例)
    roi = (200, 250, 100, 150)  # 可根据实际图像调整
    orig_roi, noisy_roi, enh_roi = visualize_local_details(
        original, results["noisy"], results["enhanced"], roi
    )

    # 边缘梯度对比
    se = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    orig_grad = cv2.morphologyEx(original, cv2.MORPH_GRADIENT, se)
    enh_grad = cv2.morphologyEx(results["enhanced"], cv2.MORPH_GRADIENT, se)

    # 创建子图(3行4列布局)
    fig, axes = plt.subplots(3, 4, figsize=(20, 15))
    axes = axes.flatten()

    # 1. 原始图像
    axes[0].imshow(original, cmap="gray")
    axes[0].set_title("原始图像")
    axes[0].axis("off")

    # 2. 含噪声图像(带指标)
    axes[1].imshow(results["noisy"], cmap="gray")
    axes[1].set_title(
        f"含椒盐噪声图像\nPSNR: {metrics['noisy']['psnr']:.2f}\nSSIM: {metrics['noisy']['ssim']:.4f}"
    )
    axes[1].axis("off")

    # 3. 基础去噪结果(带指标)
    axes[2].imshow(results["basic_denoised"], cmap="gray")
    axes[2].set_title(
        f"基础开闭运算去噪\nPSNR: {metrics['basic']['psnr']:.2f}\nSSIM: {metrics['basic']['ssim']:.4f}"
    )
    axes[2].axis("off")

    # 4. 形态学重构结果(带指标)
    axes[3].imshow(results["reconstructed"], cmap="gray")
    axes[3].set_title(
        f"形态学重构\nPSNR: {metrics['recon']['psnr']:.2f}\nSSIM: {metrics['recon']['ssim']:.4f}"
    )
    axes[3].axis("off")

    # 5. 最终增强结果(带指标)
    axes[4].imshow(results["enhanced"], cmap="gray")
    axes[4].set_title(
        f"最终去噪+细节增强\nPSNR: {metrics['enhanced']['psnr']:.2f}\nSSIM: {metrics['enhanced']['ssim']:.4f}"
    )
    axes[4].axis("off")

    # 6. 残留盐噪声(红色标记)
    axes[5].imshow(results["enhanced"], cmap="gray")
    axes[5].imshow(salt_residual, cmap="Reds", alpha=0.5)  # 叠加红色残留噪声
    axes[5].set_title("残留盐噪声(红色)")
    axes[5].axis("off")

    # 7. 残留椒噪声(蓝色标记)
    axes[6].imshow(results["enhanced"], cmap="gray")
    axes[6].imshow(pepper_residual, cmap="Blues", alpha=0.5)  # 叠加蓝色残留噪声
    axes[6].set_title("残留椒噪声(蓝色)")
    axes[6].axis("off")

    # 8. 结构元素可视化
    axes[7].imshow(results["se_small"], cmap="binary")
    axes[7].set_title("小结构元素 (3x3)")
    axes[7].axis("off")
    axes[8].imshow(results["se_large"], cmap="binary")
    axes[8].set_title("大结构元素 (5x5)")
    axes[8].axis("off")

    # 9-11. 局部细节放大对比
    axes[9].imshow(orig_roi, cmap="gray")
    axes[9].set_title("原始局部细节")
    axes[9].axis("off")
    axes[10].imshow(noisy_roi, cmap="gray")
    axes[10].set_title("含噪声局部细节")
    axes[10].axis("off")
    axes[11].imshow(enh_roi, cmap="gray")
    axes[11].set_title("去噪后局部细节")
    axes[11].axis("off")

    plt.tight_layout()
    plt.savefig('Implementation of Edge-Preserving Image Denoising Based on Mathematical Morphology.png')
    plt.show()


if __name__ == "__main__":
    # 读取图像并转为灰度图
    img = cv2.imread("lena.png")
    original_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 生成含噪声图像(同时获取噪声坐标)
    noisy_img, salt_coords, pepper_coords = generate_noisy_image(
        original_gray, salt_ratio=0.02, pepper_ratio=0.02
    )

    # 执行形态学去噪流程
    denoise_results = morphological_denoising_pipeline(noisy_img)

    # 可视化
    visualize_results(original_gray, denoise_results, salt_coords, pepper_coords)

五、Python代码完整解释

(一)核心设计思想

该代码通过 **“分阶段处理 + 多维度验证”的策略,实现 “噪声去除” 与 “边缘保留” 的平衡。核心逻辑基于数学形态学的基本操作(腐蚀、膨胀、开 / 闭运算),并通过形态学重构细节增强 ** 技术,解决传统形态学去噪中 “过度平滑导致边缘模糊” 的问题。整体流程遵循 “先去噪、再保边、最后恢复细节” 的思路,同时通过定量指标和可视化对比验证效果。

(二)模块功能与实现细节

1. 噪声生成模块(generate_noisy_image
  • 作用:模拟真实图像中的椒盐噪声(图像中随机出现的亮噪声 “盐点” 和暗噪声 “椒点”),为去噪算法提供测试数据。
  • 实现逻辑
    • 计算图像总像素数,根据设定的噪声比例(salt_ratiopepper_ratio)确定噪声像素数量。
    • 通过随机坐标生成器,在图像中随机位置添加 255(盐噪声,亮点)和 0(椒噪声,暗点)。
    • 返回含噪声图像及噪声坐标(用于后续噪声残留分析)。
  • 意义:标准化噪声输入,确保去噪效果可量化对比。
2. 形态学去噪核心流水线(morphological_denoising_pipeline

这是算法的核心模块,包含 4 个关键步骤,逐步实现 “去噪 - 保边 - 增强” 的目标:

(1)自适应结构元素(SE)设计
se_small = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))  # 小结构元素
se_large = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))  # 大结构元素
  • 结构元素:形态学操作的 “工具”,其形状和大小直接影响去噪效果和边缘保留能力。
  • 设计逻辑
    • 选择椭圆形状MORPH_ELLIPSE):相比矩形,椭圆对边缘的各向异性影响更小,能更好保留曲线边缘(如人脸轮廓)。
    • 双尺寸设计:
      • 小 SE(3x3):用于精细操作(形态学重构、细节提取),减少对边缘和纹理的破坏。
      • 大 SE(5x5):用于基础去噪,可去除尺寸较大的噪声(大于小 SE 的噪声)。
  • 意义:通过结构元素的 “尺寸适配”,平衡 “去噪强度” 和 “细节保留”。
(2)基础去噪:开运算 + 闭运算
opening = cv2.morphologyEx(noisy_img, cv2.MORPH_OPEN, se_large)  # 去盐噪声
basic_denoised = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, se_large)  # 去椒噪声
  • 开运算(MORPH_OPEN):先腐蚀后膨胀,可去除小于结构元素的亮噪声(盐点),同时对较大目标的形状影响较小。
  • 闭运算(MORPH_CLOSE):先膨胀后腐蚀,可去除小于结构元素的暗噪声(椒点),同样不破坏大目标的边缘。
  • 执行顺序:先开运算去亮噪声,再闭运算去暗噪声,初步净化图像。
  • 局限性:单纯的开 / 闭运算会轻微模糊边缘(尤其是小尺度边缘,如发丝、纹理),因此需要后续保边处理。
(3)边缘保护:形态学重构
marker = cv2.erode(basic_denoised, se_small)  # 标记图像(腐蚀后缩小的区域)
template = basic_denoised.copy()  # 模板图像(基础去噪结果)
while True:
    prev_marker = marker
    marker = cv2.dilate(marker, se_small)  # 迭代膨胀标记
    marker = np.minimum(marker, template)  # 受模板约束,不超过原始范围
    if np.array_equal(marker, prev_marker):  # 收敛条件
        break
reconstructed = marker
  • 核心原理:通过 “标记图像” 和 “模板图像” 的迭代运算,在去除残留噪声的同时,严格保留边缘轮廓。
  • 步骤解析
    • 标记图像(marker):对基础去噪结果进行腐蚀,得到 “内缩的目标区域”(边缘向内收缩,噪声被进一步去除)。
    • 模板图像(template):以基础去噪结果为上限,限制标记图像的膨胀范围。
    • 迭代膨胀:标记图像不断膨胀,但始终被模板图像约束(np.minimum操作),确保膨胀不会越过原始边缘(模板图像的边缘)。
    • 收敛条件:当标记图像不再变化时,得到重构结果 —— 此时噪声被去除,边缘与模板图像一致(保边效果)。
  • 优势:相比传统开 / 闭运算,重构能更精确地保留边缘,避免 “过度平滑”。
(4)细节增强:顶帽 + 底帽变换
tophat = cv2.morphologyEx(noisy_img, cv2.MORPH_TOPHAT, se_small)  # 提取亮细节
bottomhat = cv2.morphologyEx(noisy_img, cv2.MORPH_BLACKHAT, se_small)  # 提取暗细节
enhanced = reconstructed + tophat - bottomhat  # 融合细节
  • 顶帽变换(TOPHAT)原图 - 开运算结果,可提取被亮噪声掩盖的暗细节(如纹理、小尺度边缘)。
  • 底帽变换(BLACKHAT)闭运算结果 - 原图,可提取被暗噪声掩盖的亮细节
  • 融合逻辑:将顶帽 / 底帽提取的细节叠加回重构结果,恢复形态学操作中可能丢失的细微结构(如皮肤纹理、发丝)。
  • 意义:解决 “去噪导致细节丢失” 的问题,提升图像的视觉质量。
3. 定量指标计算(calculate_metrics
psnr_val = psnr(original, processed, data_range=255)  # 峰值信噪比
ssim_val = ssim(original, processed, data_range=255)  # 结构相似性
  • PSNR(峰值信噪比):衡量去噪后图像与原图的像素差异,值越高(通常 > 30dB)表示去噪效果越好。
  • SSIM(结构相似性):衡量图像结构(包括边缘、纹理)的保留程度,越接近 1 表示结构保留越好。
  • 作用:从数值角度客观验证算法的 “去噪能力” 和 “保边效果”,避免仅依赖主观视觉判断。
4. 可视化模块(visualize_results

通过多维度可视化,直观展示算法的有效性,包含以下关键对比:

可视化内容作用说明
原始图像 vs 含噪声图像展示噪声对图像的破坏程度,明确去噪任务的必要性。
各阶段去噪结果对比展示 “基础去噪→重构→增强” 的效果提升,突出重构的保边作用。
定量指标(PSNR/SSIM)用数值证明增强结果在 “去噪” 和 “结构保留” 上的优势。
噪声残留标记(红 / 蓝色)标记未去除的盐 / 椒噪声,验证算法对噪声的去除彻底性。
结构元素可视化展示 3x3 和 5x5 椭圆 SE 的形状,解释 “小 SE 保细节、大 SE 去噪” 的设计逻辑。
局部细节放大(如眼睛区域)聚焦高细节区域(如眼睑边缘、睫毛),直观展示边缘和纹理的保留效果。
边缘梯度对比通过形态学梯度(膨胀 - 腐蚀)展示去噪后边缘与原始边缘的一致性。

(三)算法整体流程总结

  1. 输入准备:读取原始图像,生成含椒盐噪声的测试图像。
  2. 基础净化:用大 SE 的开 / 闭运算去除大部分盐 / 椒噪声。
  3. 边缘保护:通过形态学重构,在基础去噪结果上恢复边缘的清晰度。
  4. 细节增强:用顶帽 / 底帽变换提取并叠加丢失的细节,优化视觉效果。
  5. 效果验证:通过定量指标(PSNR/SSIM)和多维度可视化,证明去噪同时保边的效果。

六、总结

本文提出了一种基于数学形态学的图像去噪方法,重点解决传统去噪中边缘模糊的问题。通过自适应结构元素设计、形态学重构和细节增强技术,实现了噪声去除与边缘保留的平衡。算法流程包括:基础开闭运算去噪、形态学重构保护边缘、顶帽底帽变换恢复细节。实验通过PSNR/SSIM指标和多维度可视化验证了方法的有效性,在去除椒盐噪声的同时较好地保持了图像细节和边缘结构。Python代码实现展示了完整的处理流程,包括噪声生成、分阶段去噪、定量评估和结果可视化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值