目標
在本章中,
你將學習用於去除圖像中噪聲的非局部均值去噪算法。你將看到不同的函數,例如cv.fastNlMeansDenoising(),cv.fastNlMeansDenoisingColored()等。理論
在前面的章節中,我們已經看到了許多圖像平滑技術,例如高斯模糊,中值模糊等,它們在某種程度上可以消除少量噪聲。在這些技術中,我們在像素周圍採取了一個較小的鄰域,並進行了一些操作,例如高斯加權平均值,值的中位數等來替換中心元素。簡而言之,在像素處去除噪聲是其周圍的局部現象。 有噪聲的性質。
通常認為噪聲是零均值的隨機變量。考慮一個有噪聲的像素,$p=p_0+n$,其中$p_0$是像素的真實值,$n$是該像素中的噪聲。你可以從不同的圖像中獲取大量相同的像素(例如N)並計算其平均值。理想情況下,由於噪聲的平均值為零,因此應該得到$p = p_0$。
你可以通過簡單的設置自己進行驗證。將靜態相機固定在某個位置幾秒鐘。這將為你提供很多幀或同一場景的很多圖像。然後編寫一段代碼,找到視頻中所有幀的平均值(這對你現在應該太簡單了)。 比較最終結果和第一幀。你會看到噪聲減少。不幸的是,這種簡單的方法對攝像機和場景的運動並不穩健。通常,只有一張嘈雜的圖像可用。
因此想法很簡單,我們需要一組相似的圖像來平均噪聲。考慮圖像中的一個小窗口(例如5x5窗口)。 很有可能同一修補程序可能位於圖像中的其他位置。有時在它周圍的一個小社區中。一起使用這些相似的補丁並找到它們的平均值怎麼辦?對於那個特定的窗口,這很好。請參閱下面的示例圖片:
圖像中的藍色補丁看起來很相似。綠色補丁看起來很相似。因此,我們獲取一個像素,在其周圍獲取一個小窗口,在圖像中搜索相似的窗口,對所有窗口求平均,然後用得到的結果替換該像素。此方法是「非本地均值消噪」。與我們之前看到的模糊技術相比,它花費了更多時間,但是效果非常好。更多信息和在線演示可在其他資源的第一個連結中找到。
對於彩色圖像,圖像將轉換為CIELAB色彩空間,然後分別對L和AB分量進行降噪。
OpenCV中的圖像去噪
OpenCV提供了此方法的四個變體。
cv.fastNlMeansDenoising()-處理單個灰度圖像cv.fastNlMeansDenoisingColored()-處理彩色圖像。cv.fastNlMeansDenoisingMulti()-處理在短時間內捕獲的圖像序列(灰度圖像)cv.fastNlMeansDenoisingColoredMulti()-與上面相同,但用於彩色圖像。常用參數為:
h:決定濾波器強度的參數。較高的h值可以更好地消除噪點,但同時也可以消除圖像細節。(可以設為10)hForColorComponents:與h相同,但僅用於彩色圖像。(通常與h相同)templateWindowSize:應為奇數。(建議設為7)searchWindowSize:應為奇數。(建議設為21)請訪問其他資源中的第一個連結,以獲取有關這些參數的更多詳細信息。 我們將在此處演示2和3。剩下的留給你。
cv.fastNlMeansDenoisingColored() 如上所述,它用於消除彩色圖像中的噪點。(噪聲可能是高斯的)。請參閱以下示例:
import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg = cv.imread('die.png')dst = cv.fastNlMeansDenoisingColored(img,None,10,10,7,21)plt.subplot(121),plt.imshow(img)plt.subplot(122),plt.imshow(dst)plt.show()以下是結果的放大版本。我的輸入圖像的高斯噪聲為σ= 25。查看結果:
cv.fastNlMeansDenoisingMulti() 現在,我們將對視頻應用相同的方法。第一個參數是噪聲幀列表。第二個參數 imgToDenoiseIndex 指定我們需要去噪的幀,為此,我們在輸入列表中傳遞幀的索引。第三是 temporalWindowSize,它指定要用於降噪的附近幀的數量。應該很奇怪。在那種情況下,總共使用 temporalWindowSize 幀,其中中心幀是要被去噪的幀。例如,你傳遞了一個5幀的列表作為輸入。令 imgToDenoiseIndex = 2 , temporalWindowSize =3。然後使用 frame-1,frame-2 和 frame-3 去噪 frame-2。讓我們來看一個例子。
import numpy as np import cv2 as cv from matplotlib import pyplot as plt cap = cv.VideoCapture('vtest.avi') # 創建5個幀的列表img = [cap.read()[1] for i in xrange(5)] # 將所有轉化為灰度 gray = [cv.cvtColor(i, cv.COLOR_BGR2GRAY) for i in img] # 將所有轉化為float64 gray = [np.float64(i) for i in gray] # 創建方差為25的噪聲 noise = np.random.randn(*gray[1].shape)*10 # 在圖像上添加噪聲 noisy = [i+noise for i in gray] # 轉化為unit8 noisy = [np.uint8(np.clip(i,0,255)) for i in noisy] # 對第三幀進行降噪 dst = cv.fastNlMeansDenoisingMulti(noisy, 2, 5, None, 4, 7, 35) plt.subplot(131),plt.imshow(gray[2],'gray') plt.subplot(132),plt.imshow(noisy[2],'gray') plt.subplot(133),plt.imshow(dst,'gray') plt.show()
計算需要花費大量時間。結果,第一個圖像是原始幀,第二個是噪聲幀,第三個是去噪圖像。
附加資源
http://www.ipol.im/pub/art/2011/bcm_nlm/ (它包含詳細信息,在線演示等。強烈建議訪問。我們的測試圖像是從此連結生成的)Online course at coursera (這裡拍攝的第一張圖片)