图像去噪——非局部均值去噪(NLM)cv2.fastNlMeansDenoisingColored()函数使用及调用Trackbar滑动条调整最佳去噪值(附Python代码)

在这里插入图片描述

💪 专业从事且热爱图像处理,图像处理专栏更新如下👇:
📝《图像去噪》
📝《超分辨率重建》
📝《语义分割》
📝《风格迁移》
📝《目标检测》
📝《图像增强》
📝《模型优化》
📝《模型实战部署》
📝《图像配准融合》
📝《数据集》
📝《高效助手》
📝《C++》
📝《Qt》


在这里插入图片描述

痛点:在深度学习训练前准备样本时,有些数据集本身就含有微弱的噪声,假设做超分辨率重建,这些噪声如果直接传入网络一起训练,网络在训练过程中会逐步提取特征,其中就包含了噪声特征,最终超分模型会将噪声当作细节特征放大显示出来,影响最终的超分效果。

解决办法:为了解决噪声对超分的影响,在正式训练之前需要将训练样本中的噪声去除,去除图像噪声有诸多方法,两大类为深度学习方法和传统算法,深度学习去噪方法可以看我图像去噪专栏。本教程主要讲解一种传统的去噪方法,既能保留图像边缘和细节,又能有效去除噪声。

一、非局部均值去噪

1.1 NLM原理

非局部均值去噪的核心思想是基于图像中相似的局部区域来消除噪声。与简单的像素邻域滤波不同,它在图像中搜索具有相似模式的区域进行加权平均,从而消除噪声。算法会对每个像素点的局部邻域进行比对,并找到与该像素具有相似强度值的像素区域,然后对这些相似区域加权平均,替换噪声点。

1.2 NLM优势

非局部均值法相比传统的滤波算法(如高斯滤波、中值滤波和双边滤波)有几个显著的优势:

边缘保护更好:非局部均值去噪方法能够有效地保留图像中的细节和边缘,而高斯滤波等方法会模糊边缘。双边滤波尽管也保留了边缘,但效果不如非局部均值好。

细节保留更强:非局部均值通过分析更大范围的相似像素进行加权平均,因此在处理具有低噪声的图像时能更好地保留图像细节,而不会像中值滤波那样过度平滑。

适合处理复杂噪声:它在去除低频噪声(如自然噪声)方面表现优秀,而高斯滤波和中值滤波更适合处理高频噪声。

颜色处理能力强:fastNlMeansDenoisingColored() 不仅处理亮度通道,还分别处理颜色通道,因此对彩色图像的去噪效果较好。而高斯滤波和中值滤波直接作用于整个像素(包括颜色),容易导致颜色失真。

非局部特性:该方法不是仅限于局部区域,它在较大的搜索窗口内寻找相似的区域进行去噪,这与高斯和中值滤波的局部邻域处理有很大的区别

1.3 传统滤波算法比较

NLM是一种非常强大的去噪方法,尤其适合在细节和边缘保留要求较高的场景中使用。与传统的高斯滤波、中值滤波、双边滤波相比,它能够更好地去除噪声,同时保护图像的边缘和细节。缺点是处理速度较慢,特别是在较大的搜索窗口和模板窗口下,会消耗更多的计算资源。

下面列举了非局部均值滤波与高斯率、中值滤波、双边滤波在处理图像噪声方法的对比。

在这里插入图片描述

二、非局部均值去噪函数

OpenCV中提供了多个关于NML函数,见下:

cv2.fastNlMeansDenoising() - 处理单个灰度图像
cv2.fastNlMeansDenoisingColored() - 处理彩色图像。
cv2.fastNlMeansDenoisingMulti() - 用于在短时间内捕获的图像序列(灰度图像)
cv2.fastNlMeansDenoisingColoredMulti() - 同上,用于彩色图像。

本教程以cv2.fastNlMeansDenoisingColored() 函数为例讲解,其它函数的使用和参数类似。

2.1 函数解析

函数名:

cv2.fastNlMeansDenoisingColored(src, dst=None, h=10, hColor=10, templateWindowSize=7, searchWindowSize=21)

参数说明

src:输入的彩色噪声图像。
dst:输出的去噪图像。如果不指定,函数会返回去噪后的图像。
h:控制亮度通道的去噪强度(通常是灰度信息)。值越大,去噪效果越强,但可能会模糊细节。典型值在 3-10 之间。最小值为 0 时,表示不去噪。
hColor:控制颜色通道的去噪强度。与 h 类似,值越大,颜色去噪越强。较大的值可能会导致颜色失真或模糊。典型值也在 3-10 之间。
templateWindowSize:用于计算相似性的模板窗口大小。必须是奇数,通常为 7,可以取值范围为 3-21。此窗口用于分析局部区域的相似性。
searchWindowSize:用于寻找相似像素的搜索窗口大小。必须是奇数,默认值为 21。这个窗口越大,算法会比较更多的像素,从而得到更精确的去噪结果,但处理速度也会变慢。

2.2 版本补充

补:我自己使用的OpenCV版本是4.8.1.78,上面函数中的第四个参数命名为:hColor,在老版本的OpenCV中,第四个参数名为:hForColorComponents

在这里插入图片描述

三、实例应用代码

3.1 单帧图像处理

处理单帧图像的代码见下:

import cv2
import os

# 读取彩色图像
fold_path= 'Images/Visible_noise_img/SIGMA_SRGB_3_6.png'
img = cv2.imread(fold_path)

value = 2

# 使用 fastNlMeansDenoisingColored 进行去噪
denoised_img = cv2.fastNlMeansDenoisingColored(src = img,dst = None,h = value,hColor=value,templateWindowSize=7,searchWindowSize=21)

# 获取图片的名称
filename = os.path.basename(fold_path)
cv2.imwrite("Result/Visible_denoise_img/"+filename,denoised_img)

# 显示原图和去噪后的图像
cv2.imshow('Original', img)
cv2.imshow('Denoised', denoised_img)

cv2.waitKey(0)
cv2.destroyAllWindows()

3.2 批量图像处理

使用NLM方法批量去噪的代码见下:

import cv2
import os

# 设置输入图像文件夹路径和输出文件夹路径
input_folder = r'F:\Code\Python\U20241014_add_20240903'  # 替换为你的输入文件夹路径
output_folder = r'F:\Code\Python\HR_fastNlMeansDenoisingColored_2'  # 替换为你的输出文件夹路径

# 如果输出文件夹不存在,创建它
if not os.path.exists(output_folder):
    os.makedirs(output_folder)

# 遍历文件夹中的所有图像文件
for filename in os.listdir(input_folder):
    # 构造完整的文件路径
    img_path = os.path.join(input_folder, filename)

    # 检查文件是否为图像格式(可以根据需要扩展)
    if filename.endswith(('.png', '.jpg', '.jpeg', '.bmp', '.tiff')):
        # 读取图像
        img = cv2.imread(img_path)

        if img is not None:
            # 对图像进行非局部均值去噪
            denoised_img = cv2.fastNlMeansDenoisingColored(img, None, 2, 2, 7, 21)

            # 构造输出路径
            output_path = os.path.join(output_folder, filename)

            # 保存处理后的图像
            cv2.imwrite(output_path, denoised_img)

            print(f"已处理并保存图像: {filename}")
        else:
            print(f"无法读取图像: {filename}")

3.3 添加Trackbar滑动条

不同强度的噪声,使用cv2.fastNlMeansDenoisingColored()函数需要的参数不一样,为了更方便的快速确定参数用于去除图像噪声,在单帧图像处理基础上添加了Trackbar滑动条,拖动滑块以便找到最合适的参数值。具体代码见下:

import cv2
import time

# 读取彩色图像
img = cv2.imread("Images/Visible_noise_img/SIGMA_SRGB_3_6.png")

# 定义value的初始值
value = 1

# 定义一个回调函数,当Trackbar的值变化时调用
def on_trackbar(val):
    global img
    # 更新value值
    value = val
    start_time = time.time()
    # 重新调用fastNlMeanDenoisingColored去噪处理
    denoised_img = cv2.fastNlMeansDenoisingColored(src=img,dst=None,h=value,hColor=value, templateWindowSize=7, searchWindowSize=21)
    end_time = time.time()

    processing_time = (end_time -start_time) * 1000
    print(f'processing_time:{processing_time:.2f}ms')

    #显示去噪后的图像
    cv2.imshow("Denoised",denoised_img)

# 创建显示窗口
cv2.namedWindow("Denoised")

# 创建一个Trackbar滑动条,范围为1到50(根据自己需求调整值)
cv2.createTrackbar('value',"Denoised",value,50,on_trackbar)

# 首次显示图像,初始化为初始的value值
denoised_img = cv2.fastNlMeansDenoisingColored(src=img,dst=None,h=value,hColor=value, templateWindowSize=7, searchWindowSize=21)
cv2.imshow("Denoised",denoised_img)
cv2.imshow("Original",img)

# 等待按键退出
cv2.waitKey(0)
cv2.destroyAllWindows()

运行上面代码的输出见下,下面图片中耗时单位是错的,不是秒,是毫秒才对。

在这里插入图片描述

具体调整合适参数的过程见下面视频:

图像去噪

四、效果展示

下面对比图中,左侧为含噪图,右侧为NLM去噪结果图。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

五、总结

以上就是非局部均值去噪的详细使用方法,学者在使用NLM方法时先用3.3部分代码确定好参数值,再用3.2部分代码批量对图像进行去噪。

感谢您阅读到最后!😊总结不易,多多支持呀🌹 点赞👍收藏⭐评论✍️,您的三连是我持续更新的动力💖

关注公众号「视觉研坊」,获取干货教程、实战案例、技术解答、行业资讯!

以下是使用贝叶斯优化的时序信号快速非局部均值Python代码: ```python import numpy as np from scipy.signal import fftconvolve from skopt import gp_minimize def non_local_means_denoise(signal, kernel_size, h, sigma): """ 使用贝叶斯优化的时序信号快速非局部均值 参数: signal: ndarray,待的信号 kernel_size: int,滤波器的大小 h: float,平滑参数 sigma: float,声标准差 返回: ndarray,后的信号 """ # 构造滑动窗口,用于计算局部均 window = np.ones(kernel_size) / kernel_size def objective(x): """ 目标函数,计算该参数下的误差 参数: x: tuple,(h, sigma) 返回: float,误差 """ # 计算平滑参数和声标准差 h, sigma = x # 计算非局部均值 mean = fftconvolve(signal, window, mode='same') diff = signal - mean weights = np.exp(-diff ** 2 / (2 * sigma ** 2)) weights /= np.sum(weights, axis=0) denoised_signal = np.sum(weights * signal, axis=0) # 计算误差 mse = np.mean((denoised_signal - signal) ** 2) return mse # 使用贝叶斯优化寻找最优参数 result = gp_minimize( objective, [(0.001, 0.1), (0.001, 0.1)], n_random_starts=5, n_calls=20, verbose=False ) # 使用最优参数进行 h, sigma = result.x mean = fftconvolve(signal, window, mode='same') diff = signal - mean weights = np.exp(-diff ** 2 / (2 * sigma ** 2)) weights /= np.sum(weights, axis=0) denoised_signal = np.sum(weights * signal, axis=0) return denoised_signal ``` 使用示例: ```python import matplotlib.pyplot as plt # 构造带声的信号 t = np.linspace(0, 1, 200) signal = np.sin(2 * np.pi * t) + 0.1 * np.random.randn(200) # denoised_signal = non_local_means_denoise(signal, 10, 0.05, 0.1) # 绘制原始信号和后的信号 plt.plot(t, signal, label='原始信号') plt.plot(t, denoised_signal, label='后的信号') plt.legend() plt.show() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

视觉研坊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值