一、算法原理
非局部均值濾波(Non-Local Means,NLM)是Buades等人於2005年在論文“A non-local algorithm for image denoising”中提出的對傳統鄰域濾波方法的一種改進濾波,考慮到了圖像的自相似性質,它充分利用了圖像中的冗餘信息,在去噪的同時能夠最大程度的保持圖像的細節特徵。【論文及源碼地址】
該算法需要計算圖像中所有像素與當前像素之間的相似性,考慮到這個計算量與效率的問題,一般會設定兩個固定大小的窗口,一個大的搜索窗口(D×D)和一個小的鄰域窗口(d×d),鄰域窗口在搜索窗口中進行滑動,根據鄰域間的相似性來確定對應中心像素對當前像素的影響度,也就是權值。
下圖是NLM算法執行過程,大窗口是以目標像素爲中心的搜索窗口,兩個灰色小窗口分別是以x,y爲中心的鄰域窗口。其中以y爲中心的鄰域窗口在搜索窗口中滑動,通過計算兩個鄰域窗口間的相似程度爲y賦以權值w(x,y) 。
基本原理
- 該算法需要遍歷整個原圖像;首先取出一個原圖像pixel,以該pixel座標爲中心,圈出一大、一小兩個矩形。大的矩形表示紋理替換搜索區域R,小的矩形表示待處理pixel的紋理區域L。
- 將R矩形區域,分成若干個和R矩形區域一樣的大小的矩形L1。計算出每塊L1和L之間的權重W。
- 將L的像素值都設置爲0,然後根據L與每塊L1的權重W,疊加當前L的像素值爲:w * L1。
- 將L和每塊L1之間的權重W,同樣累加起來到 。
- 所有L1遍歷完了之後,。就得到了經過去噪處理之後的L區域像素。
二、代碼實現
import numpy as np
import cv2
import time
def nlm(array,N,K,sigma):
height = array.shape[0]
width = array.shape[1]
pad_len = N+K
arraypad = np.pad(array,pad_len,'constant',constant_values=0)
yy = np.zeros(array.shape)
B = np.zeros((height,width))
for ny in range(-N,N+1):
for nx in range(-N,N+1):
ssd = np.zeros((height,width))
for ky in range(-K,K+1):
for kx in range(-K, K + 1):
ssd += np.square(arraypad[pad_len+ny+ky:height+pad_len+ny+ky,pad_len+nx+kx:width+pad_len+nx+kx] - arraypad[pad_len+ky:height+pad_len+ky,pad_len+kx:width+pad_len+kx])
ex = np.exp(-ssd/(2*sigma*sigma))
B +=ex
yy += ex*arraypad[pad_len+ny:height+pad_len+ny,pad_len+nx:width+pad_len+nx]
return yy/B
if __name__ == '__main__':
t1 = time.time()
noise_img = cv2.imread("./xxxnlm.png",0)
noise_img = noise_img/255.0
img_nlm = nlm(noise_img,10,4,0.6)
t2 = time.time()
print("Cost time :%f s"%(t2-t1))
cv2.imshow("img_nlm",img_nlm)
cv2.waitKey(0)
cv2.destroyAllWindows()
【參考】
https://blog.csdn.net/weixin_30570101/article/details/97913312
https://max.book118.com/html/2016/1206/68911778.shtm