当前位置: 首页 > news >正文

【OpenCV图像处理】图像去噪:cv.fastNlMeansDenoising()

文章目录

  • 一、图像去噪(Image Denoising)
    • (1)基本原理 —— 基于非局部均值(Non-Local Means, NLM)滤波算法
    • (2)算法步骤
    • (3)优缺点
  • 二、函数详解
  • 三、项目实战
    • 实战1:cv.fastNlMeansDenoising() —— 单张灰度图像去噪
    • 实战2:cv.fastNlMeansDenoisingColored() —— 单张彩色图像去噪
    • 实战3:cv.fastNlMeansDenoisingMulti() —— 多帧灰度图像去噪(增强单帧效果)
    • 实战4:cv.fastNlMeansDenoisingColoredMulti() —— 多帧彩色图像去噪(增强单帧效果)
    • 实战5:手搓代码(不加速版本)

一、图像去噪(Image Denoising)

(1)基本原理 —— 基于非局部均值(Non-Local Means, NLM)滤波算法

cv2.fastNlMeansDenoising() 是一种基于非局部均值去噪(Non-Local Means, NLM)的方法,旨在去除图像中的噪声。其核心思想是在图像的局部区域内,通过计算相似性并加权平均周围像素的值来减少噪声,同时保持图像的细节和边缘。

理解区别

  • 传统的均值滤波:是一种局部滤波方法,通过计算当前像素及其邻域像素(如3x3、5x5等)的加权平均值来平滑图像。所有邻域像素的贡献通常被认为是相同的(等权重),且由于只依赖局部区域,导致了图像在去噪时可能会出现模糊,尤其是在图像边缘部分。
  • 非局部均值滤波(NLM):是一种全局搜索滤波方法,计算每个像素与其他区域(除了当前像素所在区域之外的所有其他区域)的相似度,并使用这些相似区域的加权平均值来替换原有像素值。

(2)算法步骤

  • (1)确定目标像素和邻域:选择需要去噪的目标像素 I(x, y),并为每个目标像素定义一个搜索窗口。这个窗口决定了算法在图像中搜索与当前像素相似的区域。搜索窗口通常包括目标像素周围的一定数量的像素。
  • (2)计算像素块的相似性:计算目标像素的周围区域(通常是一个小块区域)与搜索窗口内所有其他区域的相似度。相似度度量通常基于欧几里得距离(或其他距离度量,如曼哈顿距离)来计算。假设目标像素周围有一个 m×m 的区域,算法将把每个像素周围的 m×m 区域视为一个小块,并计算当前像素的邻域与其他所有小块的差异。通常,使用以下的相似性度量公式:
    sim(I1,I2)=exp⁡(−∥I1−I2∥2h2)\text{sim}(I_1, I_2) = \exp\left(\frac{-\| I_1 - I_2 \|^2}{h^2}\right) sim(I1,I2)=exp(h2I1I22)
    其中:
    • I1I_1I1I2I_2I2 分别是两个区域的像素值。
    • ∥I1−I2∥2\| I_1 - I_2 \|^2I1I22 是两个区域之间的欧几里得距离的平方。
    • hhh 是平滑参数,用于控制相似度的衰减。通常需要通过实验来选择合适的 hhh 值。
  • (3)加权函数(Weight Function): 将相似性度量转化为权重,决定了周围像素对目标像素去噪结果的影响程度。在 NLM 中,最常见的加权函数是基于相似度的指数函数,即随着两块区域差异的增大,权重逐渐减小。权重 w(x′,y′)w(x', y')w(x,y) 可以定义为:
    w(x′,y′)=exp⁡(−∥I(x,y)−I(x′,y′)∥2h2)w(x', y') = \exp\left(\frac{-\| I(x, y) - I(x', y') \|^2}{h^2}\right) w(x,y)=exp(h2I(x,y)I(x,y)2)
    其中:
    • I(x,y)I(x, y)I(x,y)I(x′,y′)I(x', y')I(x,y) 是当前像素和候选像素的邻域块。
    • hhh 是一个控制相似度阈值的参数,值越小,只有相似度非常高的像素才会对去噪产生较大影响。
  • (4)加权平均:根据计算出的相似性,算法为每个像素计算加权平均值。与目标像素相似度较高的像素会对去噪结果贡献更多,而相似度较低的像素则贡献较少。这是通过对每个像素周围的小块区域计算加权平均值来实现的。去噪公式如下:
    I′(x,y)=∑(x′,y′)∈Ωw(x′,y′)I(x′,y)∑(x′,y′)∈Ωw(x′,y′)I'(x, y) = \frac{\sum_{(x', y') \in \Omega} w(x', y') I(x', y)}{\sum_{(x', y') \in \Omega} w(x', y')} I(x,y)=(x,y)Ωw(x,y)(x,y)Ωw(x,y)I(x,y)
    其中:
    • I′(x,y)I'(x, y)I(x,y) 是去噪后的像素值。
    • w(x′,y′)w(x', y')w(x,y) 是像素 (x′,y′)(x', y')(x,y) 的权重,通常与相似度成正比。
    • Ω\OmegaΩ 是搜索窗口范围内的像素集合。
  • (5)递归:对图像中的每个像素都执行相同的去噪过程,逐个计算每个像素的加权平均值,直到整个图像的所有像素都被去噪处理。

(3)优缺点

  • 优点
    • 保留图像的细节和边缘:非局部均值滤波(NLM)通过计算每个像素与其他像素区域的相似性来进行去噪,因此能够保留图像中的细节和边缘。与传统的滤波方法(如均值滤波)相比,NLM避免了过度平滑,能够更好地保持图像结构,避免模糊。
    • 只适用于去除高斯噪声,对非高斯噪声效果较差(如椒盐噪声):与高斯滤波器相比,NLM利用全局信息去噪,能够避免高斯滤波可能带来的模糊效应,特别是在处理具有细节和边缘的图像时。
  • 局限性
    • 计算量较大:由于NLM需要计算图像中每个像素与所有其他区域的相似性,尤其在处理高分辨率图像时,计算量会急剧增加,导致处理速度较慢。无法满足实时性

备注:局限性太高,且去噪效果没有预期那么好。不建议使用,学习一下即可。

二、函数详解

OpenCV官网:Image Denoising

  • 单帧去噪:cv.fastNlMeansDenoising() + cv.fastNlMeansDenoisingColored()
    仅基于当前图像本身的像素值进行降噪,它通过搜索空间上的相似性(即查找当前帧内相似的像素区域)来计算非局部均值滤波。
  • 利用时间维度信息来增强去噪效:cv.fastNlMeansDenoisingMulti() + cv.fastNlMeansDenoisingColoredMulti()
    指的是在多个连续帧(如视频帧或图像序列)之间寻找相似性,以优化当前帧的去噪效果。这并不是对所有帧同时进行去噪,而是利用前后多帧的信息来增强对某一帧的去噪处理,从而提高降噪效果,同时尽可能保留图像的细节。

三、项目实战

实战1:cv.fastNlMeansDenoising() —— 单张灰度图像去噪

在这里插入图片描述

import cv2img = cv2.imread(r'F:\py\die.png', cv2.IMREAD_GRAYSCALE)
dst = cv2.fastNlMeansDenoising(img, None, 30, 7, 21)cv2.imshow('Original Image', img)
cv2.imshow('Denoised Image', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()"""#############################################################################################
# 函数功能:非局部均值去噪(适用于单通道灰度图像)
# 函数说明:dst = cv2.fastNlMeansDenoising(src, dst=None, h=3, templateWindowSize=7, searchWindowSize=21)
# 参数说明:
#         src:输入图像,必须是单通道灰度图像(uint8)。
#         dst:输出去噪后的图像,可选项,默认为 None。
#         h:滤波强度,值越大去噪效果越强,但可能会导致细节损失,推荐范围 3~10。
#         templateWindowSize:模板窗口大小(奇数),通常为 7。
#         searchWindowSize:搜索窗口大小(奇数),通常为 21。
# 返回值:
#         返回去噪后的图像,与输入图像具有相同尺寸和类型。
# 功能描述:
#         - 该方法基于非局部均值(Non-Local Means, NLM)算法,能有效去除噪声,同时保留图像细节。
#         - 适用于单通道灰度图像,彩色图像需使用 cv2.fastNlMeansDenoisingColored() 。
#         - 常用于去除高斯噪声、均匀噪声等,适用于低噪声图像的平滑处理。
#############################################################################################"""

实战2:cv.fastNlMeansDenoisingColored() —— 单张彩色图像去噪

在这里插入图片描述

import cv2img = cv2.imread(r"F:\py\die.png")
dst = cv2.fastNlMeansDenoisingColored(img, None, 10, 10, 7, 21)cv2.imshow('Original Image', img)
cv2.imshow('Denoised Image', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()"""#############################################################################################
# 函数功能:非局部均值去噪(适用于彩色图像)
# 函数说明:dst = cv2.fastNlMeansDenoisingColored(src, dst=None, h=10, hForColorComponents=10, 
#                                                 templateWindowSize=7, searchWindowSize=21)
# 参数说明:
#         src:输入图像,必须是 3 通道 BGR 彩色图像(uint8)。
#         dst:输出去噪后的图像,可选项,默认为 None。
#         h:亮度通道的滤波强度,值越大去噪效果越强,但可能导致细节损失,推荐范围 3~10。
#         hForColorComponents:颜色通道的滤波强度,一般与 h 相同,控制颜色去噪强度。
#         templateWindowSize:模板窗口大小(奇数),通常为 7。
#         searchWindowSize:搜索窗口大小(奇数),通常为 21。
# 返回值:
#         返回去噪后的图像,与输入图像尺寸和类型相同。
# 功能描述:
#         - 该方法基于非局部均值(Non-Local Means, NLM)算法,能有效去除噪声,同时保留图像细节。
#         - 专为彩色图像设计,可同时对亮度和颜色通道进行去噪。
#         - 适用于高斯噪声、均匀噪声等,特别适用于低噪声图像的平滑处理。
#############################################################################################"""

实战3:cv.fastNlMeansDenoisingMulti() —— 多帧灰度图像去噪(增强单帧效果)

在这里插入图片描述

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt# 读取视频的帧图像
cap = cv.VideoCapture(r"D:\opencv c++\opencv\sources\samples\data\vtest.avi")
img = [cap.read()[1] for i in range(5)]  # create a list of first 5 frames
gray = [cv.cvtColor(i, cv.COLOR_BGR2GRAY) for i in img]  # convert all to grayscale
gray = [np.float64(i) for i in gray]  # convert all to float64noise = np.random.randn(*gray[1].shape)*20  # create a noise of variance 25
noisy = [i+noise for i in gray]  # Add this noise to images
noisy = [np.uint8(np.clip(i, 0, 255)) for i in noisy]  # Convert back to uint8dst = cv.fastNlMeansDenoisingMulti(noisy, 2, 5, None, 4, 7, 35)  # Denoise 3rd frame considering all the 5 framesplt.subplot(131), plt.imshow(gray[2], 'gray'), plt.title('Original'), plt.axis('off')
plt.subplot(132), plt.imshow(noisy[2], 'gray'), plt.title('Noisy'), plt.axis('off')
plt.subplot(133), plt.imshow(dst, 'gray'), plt.title('Denoised'), plt.axis('off')
plt.show()# import tifffile
# import numpy as np
# import cv2 as cv
# from matplotlib import pyplot as plt
# 
# # 读取tif图像
# img = tifffile.imread(r"F:\py\image.tif")
# img = [i for i in img]
# 
# noise = np.random.randn(*img[1].shape)*20  # create a noise of variance 25
# noisy = [i+noise for i in img]  # Add this noise to images
# noisy = [np.uint8(np.clip(i, 0, 255)) for i in noisy]  # Convert back to uint8
# 
# dst = cv.fastNlMeansDenoisingMulti(noisy, 2, 5, None, 4, 7, 35)  # Denoise 3rd frame considering all the 5 frames
# 
# plt.subplot(131), plt.imshow(img[2], 'gray'), plt.title('Original'), plt.axis('off')
# plt.subplot(132), plt.imshow(noisy[2], 'gray'), plt.title('Noisy'), plt.axis('off')
# plt.subplot(133), plt.imshow(dst, 'gray'), plt.title('Denoised'), plt.axis('off')
# plt.show()
"""#############################################################################################
# 函数功能:多帧非局部均值去噪(适用于多张灰度图像)
# 函数说明:
#         dst = cv2.fastNlMeansDenoisingMulti(srcImgs, imgToDenoiseIndex, temporalWindowSize, dst=None, 
#                                             h=10, templateWindowSize=7, searchWindowSize=21)
# 参数说明:
#         srcImgs:输入图像序列(列表形式),每个图像通常为单通道灰度图像(uint8)。
#         imgToDenoiseIndex:需要去噪的目标图像在输入序列中的索引(0 ≤ index < len(srcImgs))。
#         temporalWindowSize:时间窗口大小(奇数),决定用于去噪的前后帧数量,一般取 3~5。
#         dst:输出去噪后的图像,可选项,默认为 None。
#         h:滤波强度,值越大去噪效果越强,但可能导致细节损失,推荐范围 3~10。
#         templateWindowSize:模板窗口大小(奇数),通常为 7。
#         searchWindowSize:搜索窗口大小(奇数),通常为 21。
# 返回值:
#         返回去噪后的单通道灰度图像,与输入图像尺寸和类型相同。
# 功能描述:
#         - 该方法基于非局部均值(Non-Local Means, NLM)算法,利用时间维度的信息来增强去噪效果。
#         - 适用于视频降噪、医学影像处理等场景,可有效减少随机噪声,同时保留细节。
#         - 仅适用于灰度图像,若处理彩色图像,请使用 `cv2.fastNlMeansDenoisingColoredMulti()`。
#############################################################################################"""

实战4:cv.fastNlMeansDenoisingColoredMulti() —— 多帧彩色图像去噪(增强单帧效果)

在这里插入图片描述

import numpy as np
import cv2 as cv
from matplotlib import pyplot as pltcap = cv.VideoCapture(r"D:\opencv c++\opencv\sources\samples\data\vtest.avi")
img = [cap.read()[1] for i in range(5)]  # create a list of first 5 framesnoise = np.random.randn(*img[1].shape)*20  # create a noise of variance 25
noisy = [i+noise for i in img]  # Add this noise to images
noisy = [np.uint8(np.clip(i, 0, 255)) for i in noisy]  # Convert back to uint8dst = cv.fastNlMeansDenoisingMulti(noisy, 2, 5, None, 4, 7, 35)  # Denoise 3rd frame considering all the 5 framesplt.subplot(131), plt.imshow(cv.cvtColor(img[2], cv.COLOR_BGR2RGB)), plt.title('Original'), plt.axis('off')
plt.subplot(132), plt.imshow(cv.cvtColor(noisy[2], cv.COLOR_BGR2RGB)), plt.title('Noisy'), plt.axis('off')
plt.subplot(133), plt.imshow(cv.cvtColor(dst, cv.COLOR_BGR2RGB)), plt.title('Denoised'), plt.axis('off')
plt.show()"""#############################################################################################
# 函数功能:多帧彩色图像的非局部均值去噪(适用于多个彩色图像)
# 函数说明:
#         dst = cv2.fastNlMeansDenoisingColoredMulti(srcImgs, imgToDenoiseIndex, temporalWindowSize, dst=None, 
#                                                    h=10, hForColorComponents=10, 
#                                                    templateWindowSize=7, searchWindowSize=21)
# 参数说明:
#         srcImgs:输入图像序列(列表形式),每个图像应为彩色图像(BGR格式,uint8)。
#         imgToDenoiseIndex:需要去噪的目标图像在输入序列中的索引(0 ≤ index < len(srcImgs))。
#         temporalWindowSize:时间窗口大小(奇数),决定用于去噪的前后帧数量,一般取 3~5。
#         dst:输出去噪后的图像,可选项,默认为 None。
#         h:滤波强度(亮度通道),值越大去噪效果越强,但可能导致细节损失,推荐范围 3~10。
#         hForColorComponents:滤波强度(颜色通道),用于处理彩色噪声,推荐范围 3~10。
#         templateWindowSize:模板窗口大小(奇数),通常为 7。
#         searchWindowSize:搜索窗口大小(奇数),通常为 21。
# 返回值:
#         返回去噪后的彩色图像,与输入图像尺寸和类型相同。
# 功能描述:
#         - 该方法基于非局部均值(Non-Local Means, NLM)算法,利用时间维度信息来增强去噪效果。
#         - 适用于视频降噪、多帧影像处理等场景,可有效减少随机噪声,同时保留图像细节和颜色信息。
#############################################################################################"""

实战5:手搓代码(不加速版本)

在这里插入图片描述

import numpy as np
import cv2def non_local_means_denoising(img, h=10, templateWindowSize=7, searchWindowSize=21):"""非局部均值去噪算法(简化版)参数:img: 输入的灰度图像 (2D numpy array)。h: 控制去噪强度的参数,较大的 h 值会导致更强的平滑效果。templateWindowSize: 用于计算相似性的模板大小(通常为奇数)。searchWindowSize: 搜索窗口的大小,决定了搜索相似像素的范围。返回:去噪后的图像。"""height, width = img.shape  # 图像的高度和宽度denoised_img = np.zeros_like(img, dtype=np.float32)  # 输出去噪后的图像# 在图像上遍历每个像素for i in range(height):for j in range(width):# 定义目标像素的邻域(template window)x_start = max(i - templateWindowSize // 2, 0)x_end = min(i + templateWindowSize // 2 + 1, height)y_start = max(j - templateWindowSize // 2, 0)y_end = min(j + templateWindowSize // 2 + 1, width)# 获取目标像素的邻域区域(模板)template = img[x_start:x_end, y_start:y_end]# 定义搜索区域(search window)x_start_search = max(i - searchWindowSize // 2, 0)x_end_search = min(i + searchWindowSize // 2 + 1, height)y_start_search = max(j - searchWindowSize // 2, 0)y_end_search = min(j + searchWindowSize // 2 + 1, width)# 计算与目标像素模板相似的区域的权重weights = np.zeros_like(img, dtype=np.float32)weighted_sum = 0.0normalization_factor = 0.0# 遍历搜索窗口中的每个像素for x in range(x_start_search, x_end_search):for y in range(y_start_search, y_end_search):# 跳过当前目标像素if x == i and y == j:continue# 定义候选区域(模板),确保模板大小一致candidate_x_start = max(x - templateWindowSize // 2, 0)candidate_x_end = min(x + templateWindowSize // 2 + 1, height)candidate_y_start = max(y - templateWindowSize // 2, 0)candidate_y_end = min(y + templateWindowSize // 2 + 1, width)candidate_template = img[candidate_x_start:candidate_x_end, candidate_y_start:candidate_y_end]# 确保模板和候选区域大小一致if template.shape == candidate_template.shape:# 计算相似度(欧几里得距离),加入调试日志diff = template - candidate_templatesquared_diff = diff ** 2similarity = np.exp(-np.sum(squared_diff) / (h ** 2))# 打印日志,查看模板和候选区域之间的差异和相似度# print(f"Pixel ({i},{j}) - Diff: {squared_diff}, Similarity: {similarity}")# 防止溢出和无效相似度if similarity > 1.0:similarity = 1.0elif similarity < 0:similarity = 0.0# 更新权重和加权平均值weights[x, y] = similarityweighted_sum += similarity * img[x, y]normalization_factor += similarity# 防止除零错误if normalization_factor > 0:denoised_img[i, j] = weighted_sum / normalization_factorelse:denoised_img[i, j] = img[i, j]  # 如果没有有效的相似区域,保持原像素值# 打印日志,查看归一化因子print(f"Pixel ({i},{j})/({height}, {width}) - Weighted Sum: {weighted_sum}, Normalization Factor: {normalization_factor}")# 返回去噪后的图像return np.uint8(denoised_img)# (1)读取灰度图像
image = cv2.imread(r'F:\py\die.png', cv2.IMREAD_GRAYSCALE)# (2)调用非局部均值去噪算法
denoised_image = non_local_means_denoising(image, h=10, templateWindowSize=7, searchWindowSize=21)# (3)显示原图和去噪后的图像
cv2.imshow("Original Image", image)
cv2.imshow("Denoised Image", denoised_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
http://www.dtcms.com/a/605754.html

相关文章:

  • 基于AI Agent模板:快速生成 SQL 测试数据
  • 无锡网站建设方案企业计划书
  • 做购票系统网站网站开发推广方案策划书
  • JVM GC 垃圾回收体系完整讲解
  • JVM 内存结构的详细介绍
  • Linux命令-egrep命令(文本搜索工具)
  • 《Flutter全栈开发实战指南:从零到高级》- 14 -网络请求与数据解析
  • 模板网站配置文件seo难不难
  • div2 1052 个人补题笔记
  • 【1.10】基于FPGA的costas环开发4——鉴相器模块开发
  • C语言编译软件 | 如何选择适合自己的编译器
  • 怎么做网站外贸wordpress 本地 域名绑定
  • DSP中断工作原理
  • 【LeetCode】109. 有序链表转换二叉搜索树
  • Verilog 利用伪随机,时序,按键消抖等,实现一个(打地鼠)游戏
  • 【音视频】均衡器(Equalizer)技术详解
  • win11安装mysql社区版数据库
  • 菏泽定制网站建设推广花艺企业网站建设规划
  • 哪些网站可以做推广婚庆公司网站源码
  • LVS负载均衡群集(一) -- NAT模式
  • 【ZeroRnge WebRTC】RFC 8445:ICE 协议规范(中文整理与译注)
  • librtp 实现详解:仓颉语言中的 RTP和RTCP 协议库开发实践
  • Android http网络请求的那些事儿
  • 两台 centos 7.9 部署 pbs version 18.1.4 集群
  • 【动手学深度学习】8.1. 序列模型
  • 【AI软件开发】从文献管理到知识编织:构建AI驱动的学术研究工作流
  • 网站上面图片上传尺寸建设部二级结构工程师注销网站
  • PostIn从初级到进阶(3) - 如何对接口快速设计并管理接口文档
  • 按键精灵安卓/ios脚本开发辅助工具:yolo转换教程
  • 人工智能驱动下的OCR API技术演进与实践应用