作者|OpenCV-Python Tutorials
編譯|Vincent
來源|OpenCV-Python Tutorials
目標
在本章中,
- 你將學習用於去除圖像中噪聲的非局部均值去噪算法。
- 你將看到不同的函數,例如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 np
import cv2 as cv
from matplotlib import pyplot as plt
img = 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 (這里拍攝的第一張圖片)