传统图像去噪方法(三)之非局部均值去噪(NLM)
前面基于邻域像素的滤波方法,基本上只考虑了有限窗口范围内的像素灰度值信息,没有考虑该窗口范围内像素的统计信息如方差,也没有考虑整个图像的像素分布特性,和噪声的先验知识。
NLM算法使用自然图像中普遍存在的冗余信息来去噪,它利用了整幅图像来去噪,以图像块为单位在图像中寻找相似区域,再对这些区域求平均,能够比较好的去掉图像中存在的高斯噪声。
基本思想是:当前像素的估计值由图像中与它具有相似邻域结构的像素加权平均得到。
TV算法在平滑噪声的同时也把很多图像本身的纹理边缘细节去掉。而(各向异性滤波)AD算法在保持细节信息的同时也保留了很多的噪声。而NL算法则在去除噪声和保持纹理细节方面都取得比较好的效果。
下图是NL-means算法执行过程,大窗口是以目标像素为中心的搜索窗口,两个灰色小窗口分别是以x,y为中心的邻域窗口。其中以y为中心的邻域窗口在搜索窗口中滑动,通过计算两个邻域窗口间的相似程度为y赋以权值 。
(一)opencv自带的NLM算法
- cv2.fastNIMeansDenoising()使用对象为灰度图像
- cv2.fastNIMeansDenoisingColored()使用对象为彩色图像
- cv2.fastNIMeansDenosingMulti()适用于短时间的图像序列(灰度图像)
- cv2.fastNIMeansDenoisingColoredMulti()适用于短时间的图像序列(彩色图像)
void fastNlMeansDenoising( InputArray src, OutputArray dst, float h = 3, int templateWindowSize = 7, int searchWindowSize = 21);# scr 必须为u8# h 参数决定滤波器强度。较高的h值可以更好地消除噪声,但也会删除图像的细节 (10 is ok)# templateWindowSize 邻域窗口大小# searchWindowSize 搜索窗口大小void fastNIMeansDenoisingColored( InputArray src, OutputArray dst, float h = 3, float hColor = 3, int templateWindowSize = 7, int searchWindowSize = 21);
# hForColorComponents:与h相同,但仅适用于彩色图像。 (通常与h相同)void fastNlMeansDenoisingMulti( InputArray Of Arrays srcImgs, OutputArray dst,int imgToDenoiseIndex, int temporalWindowSize, float h = 3, int templateWindowSize = 7, int searchWindowSize = 21);void fastNlMeansDenoisingColoredMulti( InputArray Of Arrays srcImgs, OutputArray dst, int imgToDenoiseIndex, int temporalWindowSize, float h = 3, float hColor = 3,int templateWindowSize = 7, int searchWindowSize = 21);
非局部均值去噪最优参数选取:
(二)自定义NLM算法
1.PSNR指标
PSNR 和 MSE 就是基于这种简单直接的思路确定的指标,MSE(Mean Squared Error),顾名思义,定义略。PSNR(Peak Signal to Noise Ratio),峰值信噪比,即峰值信号的能量与噪声的平均能量之比,通常表示的时候取 log 变成分贝(dB),由于 MSE 为真实图像与含噪图像之差的能量均值,而两者的差即为噪声,因此 PSNR 即峰值信号能量与 MSE 之比。定义式如下:
第二个等式由于图像像素点数值以量化方式保存,bits 即每个像素点存储所占的位数。因此 MaxValue 即为 2^bits - 1。
def psnr(A,B):val=255mse=((A.astype(np.float)-B)**2).mean()return 10*np.log10((val*val)/mse)
因为灰度图像一般存储为8bit,所以val=255
2.给图像加高斯噪声
给加高斯噪声的意思,就是在原图像矩阵上面加一个符合高斯或者叫正态分布特征的矩阵。
生成随机噪声的三个方法,如果我们的目标矩阵是一个r*c的矩阵,要生成一个均值是mean,标准差sigma的随机噪声矩阵,那么是这样
sigma*np.random.randn(r,c)+mean, #输入是两个参数,一个mean,一个sigmasigma*np.random.standard_normal((r,c)) #输入是一个tuple,里面包含两个元素。 和上面那个是完全一样的。 numpy.random.normal(mean,sigma, size=(r,c)) #mean,sigma和大小都作为输入放进函数了。
image读取出来的图像,类型是uin8的(也就是取值范围是0-255),我们计算的随机噪声值,可能是或负或正的小数,直接叠加噪声的图像img_with_noise,其实是有可能是负值,有可能超了255的,而且这个np.ndarray类型是普通的float64了,这个时候用imshow函数来显示,会出现全白全黑的图像bug。
解决方法是在显示前将图像做归一化normalization转成0-255区间的unint类型。
现在看看生成噪声图像的代码:
def double2unit8(I,L,ratio=1.0,sigma=20.0):I=I.astype(np.float64) # 转换成float形式便于计算noise=np.random.randn(*I.shape)*sigma # 生成的时形状与I相同,均值为0,标准差为sigam的随机高斯噪声矩阵noisy=I+noise # 噪声图像return np.clip(np.round(noisy*ratio),0,255).astype(L.dtype) # 转换回图像的unit8均值,限制在0--255
clip(a, a_min, a_max, out=None):
将数组a中的所有数限定到范围a_min和a_max中,即az中所有比a_min小的数都会强制变为a_min,a中所有比a_max大的数都会强制变为a_max.
np.round(a,b)
第一个参数为待操作数据,第二个为小数点后几位,默认取整
3.生成高斯核
def make_kernel(f): # 计算得到一个高斯核,用于后续的计算kernel=np.zeros((2*f+1,2*f+1))for d in range(1,f+1):kernel[f-d:f+d+1,f-d:f+d+1] += (1.0/((2*d+1)**2))return kernel/kernel.sum()
4.NLM
def NLmeansfilter(I,L,h_=10,templateWindowSize=5,searchWindowSize=11): I=I.astype(np.float64)f=int(templateWindowSize/2)t=int(searchWindowSize/2)height,width=I.shape[:2] # 利用ndarray的索引得到长宽padLength=t+fI2=np.pad(I,padLength,'symmetric') # symmetric——表示对称填充,每侧填充均为padLength kernel=make_kernel(f)h=(h_**2)I_=I2[padLength-f:padLength+f+height,padLength-f:padLength+f+width] # 在原图大小的基础上,上下左右均延拓了f大小的图,固定的领域窗口yaverage=np.zeros(I.shape)sweight=np.zeros(I.shape)wmax=np.zeros(I.shape)for i in range(-t, t+1):for j in range (-t,t+1):if i==0 and j==0:continueI2_=I2[padLength+i-f:padLength+i+f+height,padLength+j-f:padLength+j+f+width] # 移动的领域窗口xw = np.exp(-cv2.filter2D((I2_ - I_)**2, -1, kernel)/h)[f:f+height, f:f+width] # 计算权重w,保持形状sweight += w # 将所有的权值相加wmax=np.maximum(wmax,w) # 求最大average += (w*I2_[f:f+height,f:f+width]) # 得到权值与窗口x相乘的值并求和I2=(average+wmax*I)/(sweight+wmax) # 权值最大的是自身return np.clip(np.round(I1),0,255).astype(L.dtype)
上述计算过程实际上是:
设含噪声图像为v,去噪后的图像为u。u中像素点x处的灰度值通过如下方式得到:
其中权值w表示像素点x和y间的相似度,它的值由以V(x)、V(y)为中心的矩形邻域间的距离决定:
Z(x)为归一化系数,h为平滑参数,控制高斯函数的衰减程度。h越大高斯函数变化越平缓,去噪水平越高,但同时也会导致图像越模糊。h越小,边缘细节成分保持得越多,但会残留过多的噪声点。h的具体取值应当以图像中的噪声水平为依据。
(三)代码实现
附上完整代码:
import cv2
import numpy as npdef psnr(A,B):val=255mse=((A.astype(np.float)-B)**2).mean()return 10*np.log10((val*val)/mse)def double2unit8(I,L,ratio=1.0,sigma=20.0):I=I.astype(np.float64) # 转换成float形式便于计算noise=np.random.randn(*I.shape)*sigma # 生成的时形状与I相同,均值为0,标准差为sigam的随机高斯噪声矩阵noisy=I+noise # 噪声图像return np.clip(np.round(noisy*ratio),0,255).astype(L.dtype) # 转换回图像的unit8均值def make_kernel(f): # 计算得到一个高斯核,用于后续的计算kernel=np.zeros((2*f+1,2*f+1))for d in range(1,f+1):kernel[f-d:f+d+1,f-d:f+d+1] += (1.0/((2*d+1)**2))return kernel/kernel.sum()def NLmeansfilter(I,L,h_=10,templateWindowSize=5,searchWindowSize=11):I=I.astype(np.float64)f=int(templateWindowSize/2)t=int(searchWindowSize/2)height,width=I.shape[:2] # 利用ndarray的索引得到长宽padLength=t+fI2=np.pad(I,padLength,'symmetric') # kernel=make_kernel(f)h=(h_**2)I_=I2[padLength-f:padLength+f+height,padLength-f:padLength+f+width]average=np.zeros(I.shape)sweight=np.zeros(I.shape)wmax=np.zeros(I.shape)for i in range(-t, t+1):for j in range (-t,t+1):if i==0 and j==0:continueI2_=I2[padLength+i-f:padLength+i+f+height,padLength+j-f:padLength+j+f+width]w = np.exp(-cv2.filter2D((I2_ - I_)**2, -1, kernel)/h)[f:f+height, f:f+width]sweight += wwmax=np.maximum(wmax,w)average += (w*I2_[f:f+height,f:f+width])I1=(average+wmax*I)/(sweight+wmax)return np.clip(np.round(I1),0,255).astype(L.dtype)if __name__=='__main__':I=cv2.imread('E:\opencv\long.jpg',0) # 以灰度图像形式读取sigma=20.0I1=double2unit8(I,I,sigma=20.0) # 对图像加上高斯噪声R2 = cv2.fastNlMeansDenoising(I1, None, sigma, 5, 11) # 利用opencv自带的NLM去噪R1=NLmeansfilter(I,I, sigma, 5, 11) # 自定义去噪cv2.imshow("Image",I)cv2.imshow("noisy",I1)cv2.imshow("NLM",R1)cv2.imshow("fastNLM",R2)print ('噪声图像PSNR',psnr(I, I1))print ('CV去噪PSNR',psnr(I,R2))print ('NLM去噪PSNR',psnr(I,R1))cv2.waitKey(0) #显示图像必备cv2.destroyALLWindows() #释放窗口
实际上凭肉眼来看,我觉得自定义的NLM效果更好一i点,但是从PSNR结果上来看确实CV自带的函数效果更好。这是因为PSNR是最普遍和使用最为广泛的一种图像客观评价指标,然而它是基于对应像素点间的误差,即 基于误差敏感的图像质量评价由于并未考虑到人眼的视觉特性(人眼对空间频率较低的对比差异敏感度较高,人眼对亮度对比差异的敏感度较色度高,人眼对一个 区域的感知结果会受到其周围邻近区域的影响等),因而经常出现评价结果与人的主观感觉不一致的情况。
同时结合之前学到的一些去噪方法进行对比实验:
if __name__=='__main__':I=cv2.imread('E:\opencv\long.jpg',0) # 以灰度图像形式读取sigma=20.0I1=double2unit8(I,I,sigma=20.0) # 对图像加上高斯噪声R2 = cv2.fastNlMeansDenoising(I1, None, sigma, 5, 11) # 利用opencv自带的NLM去噪R1=NLmeansfilter(I,I, sigma, 5, 11) # 自定义去噪dst2=cv2.ximgproc.guidedFilter(guide=I,src=I1,radius=8,eps=200,dDepth=-1)img=cv2.medianBlur(I1,5)gaussian=cv2.GaussianBlur(I1,(5,5),1.5)cv2.imshow("Image",I)cv2.imshow("noisy",I1)cv2.imshow("NLM",R1)cv2.imshow("fastNLM",R2)cv2.imshow("guided",dst2)cv2.imshow("median",img)cv2.imshow("GaussianBlur",gaussian)print ('噪声图像PSNR',psnr(I, I1))print ('CV去噪PSNR',psnr(I,R2))print ('NLM去噪PSNR',psnr(I,R1))print('guided图像去噪PSNR',psnr(I,dst2))print('median去噪PSNR',psnr(I,img))print('高斯去噪PSNR',psnr(I,gaussian))cv2.waitKey(0) #显示图像必备cv2.destroyALLWindows() #释放窗口
引导滤波效果真心不错:
参考链接:
图像质量评估
非局部均值滤波的python实现
传统图像去噪方法(三)之非局部均值去噪(NLM)相关推荐
- 基于matlab 非局部均值(NLM)滤波图像去噪
基于matlab 非局部均值(NLM)滤波图像去噪 一.简介 1 NLM滤波原理 2 Pixelwise Implementation 3 Patchwise Implementation 二.源代码 ...
- Python,OpenCV中的非局部均值去噪(Non-Local Means Denoising)
Python,OpenCV中的非局部均值去噪(Non-Local Means Denoising) 1. 效果图 2. 原理 3. 源码 2.1 单彩色图去噪 2.2 多连续彩色帧去噪 参考 这篇博客 ...
- 经典非局部均值滤波(NLM)算法python实现(1)
经典非局部均值滤波(NLM)算法python实现(单通道图像版本) 概述:非局部均值(NL-means)是近年来提出的一项新型的去噪技术.该方法充分利用了图像中的冗余信息,在去噪的同时能最大程度地保持 ...
- 全极化雷达遥感图像的迭代优化非局部均值去噪法
文章提出了一种迭代优化的PolSAR的非局部均值去噪方法.该方法在每次迭代去噪过程中,通过同时考虑原始图像全极化噪声统计特性和前一次迭代所得影像的全极化信息来完善像素间极化相似性的度量,从而实现对影像 ...
- 经典非局部均值滤波(NLM)算法python实现(2)
经典非局部均值滤波(NLM)算法python实现(三通道图像版本) 单通道图像版本已发布: https://blog.csdn.net/yy0722a/article/details/11392408 ...
- 非局部均值去噪(NL-means)
非局部均值(NL-means)是近年来提出的一项新型的去噪技术.该方法充分利用了图像中的冗余信息,在去噪的同时能最大程度地保持图像的细节特征.基本思想是:当前像素的估计值由图像中与它具有相似邻域结构的 ...
- 【图像去噪】基于非局部均值(NLM)滤波图像去噪含Matlab源码
1 简介 图像在获取和传输过程中,不可避免地受到外部和内部的干扰,常常因为各种因素的影响而被加入很多噪声,这十分严重的影响了人们对传输后图像信息的读取.因此通过一定方法将被噪声污染的图像进行去噪处理一 ...
- 非局部相似性 matlab,非局部均值滤波(NLM)和MATLAB程序详解视频教程保持图像细节...
[内容简介]<非局部均值滤波与应用和MATLAB程序详解视频>共6章28节视频,总学时698分钟,合11.6小时.主要内容包括:非局部均值滤波类算法入门,基于滤波参数自适应的非局部均值滤波 ...
- 非线性邻域滤波(NNFs)在MR-FBP图像重建算法中的应用(基于astra-toolbox开发, 实现双边滤波,非局部均值滤波(NLM)的惩戒项的改进,并进行MAE,MAR分析)
本科荒废了两年,大三终于开始好好学习了,,,,但是跟无头苍蝇,只知道上课,大四即将找工作,心理慌得一批,由于自己太辣鸡,,,只能找到3,4000的,,,终于还是决定步入研究生大抗,,,上了后发现他娘的 ...
最新文章
- html5移动端根据百度地图api获取详细地址
- python利器怎么编程-python 开发利器UliPad(图文详细介绍)
- C# 9 record 并非简单属性 POCO 的语法糖
- H3C 以太网集线器
- ZZULIOJ 1101: 逆序数字(函数专题)
- 【BZOJ1003】【codevs1655】物流运输,最短路+DP
- 《PHP、MySQL和Apache入门经典(第5版)》一2.7 基本安全规则
- java实现电子面单pdf生成_快递鸟电子面单接口打印实现代码
- 社会工程学部分攻击经典方法总结
- php 心愿墙系统源码,php开发|源码|微信留言板|微信表白墙|吐槽墙|心愿墙|2017V2.1版...
- 论文阅读笔记:Weakly-supervised Semantic Segmentation in Cityscape via Hyperspectral Image
- 计算机文字识别的过程包括哪些步骤,在电脑上怎样实现手写文字识别?
- 错误: 找不到或无法加载主类 org.sang.BlogserverApplication
- Cannot lock file hash cache (E:\blackWu\github\X5WebView\WebViewX5\.gradle\4.6\fileHashes) as it has
- android 简单快速 倒计时动画
- 艾永亮:巴奴火锅的自救与救他计划,超级产品战略打响门店保卫战
- omapl138移植uboot系列之移植板卡(第五篇)
- 第三讲 外国古代密码艺术
- 小sugar呀——入门——记录
- 为什么超凡先锋显示未选择服务器,超凡先锋画质不太流畅怎么弄 游戏画质设置方法介绍_超凡先锋...