理論
在早先的章節(jié)里,我們看到很多圖像平滑技術(shù)如高斯模糊屉栓,Median模糊等舷蒲,它們?cè)谝瞥龜?shù)量小的噪音時(shí)在某種程度上比較好用。在這些技術(shù)里友多,我們?nèi)∠袼刂車囊恍〔糠粥従由剑鲆恍╊愃朴诟咚蛊骄鶛?quán)重,中值等替換掉中間的元素域滥。簡單說纵柿,移除一個(gè)像素的噪音是基于本地鄰居的纳像。
噪音有一個(gè)屬性锉罐,噪音一般被認(rèn)為是具有零平均值的隨機(jī)變量。假設(shè)一個(gè)像素噪音瓶蝴,p = p0 + n, 其中p0是像素的真實(shí)值委可,n是那個(gè)像素的噪音渊跋。你可以從不同圖像取大量的同一個(gè)像素(N)并計(jì)算他們的平均值,理想情況下撤缴,你應(yīng)該得到p=p0刹枉,因?yàn)榫凳?.
你可以自己通過一個(gè)簡單例子驗(yàn)證一下。保持一個(gè)靜止的攝像機(jī)對(duì)準(zhǔn)一個(gè)位置多呆幾秒屈呕,這會(huì)給你很多幀微宝,或者是對(duì)一個(gè)場景的很多圖像。然后寫一些代碼來找到視頻里所有幀的平均值虎眨。比較最終的結(jié)果和第一幀蟋软。你可以看到噪點(diǎn)被去掉了。不幸的是這個(gè)簡單的方法對(duì)于攝像機(jī)和場景的運(yùn)動(dòng)來說就不健壯了嗽桩。而且經(jīng)常你也只有一個(gè)噪音圖像可用岳守。
所以思路很簡單,我們需要一套類似的圖像來平均去掉噪點(diǎn)碌冶,假設(shè)圖像上一個(gè)小窗口(比如5x5的窗口)湿痢。很有可能在圖像里的某處還有一個(gè)相同的塊。有時(shí)候是在它附近的鄰居扑庞。用這樣類似的塊來做他們的平均會(huì)怎么樣呢譬重?對(duì)于這個(gè)特定的窗口,看下面的例子:
圖像里藍(lán)色的塊看上去一樣罐氨,綠色塊看上去也類似臀规,所以我們?nèi)∫粋€(gè)像素,取它周圍的一個(gè)小窗口栅隐,找到圖像里和它類似的窗口塔嬉,平均所有的窗口玩徊,然后用結(jié)果來替換掉這個(gè)像素。這哥方法就是非局部均值去噪谨究。它要比其他我們之前介紹過的模糊技術(shù)要花更多時(shí)間恩袱。但是結(jié)果要更好。
對(duì)于彩色圖像记盒,圖像先要轉(zhuǎn)換成CIELAB顏色空間然后再分成L去噪和AB部分憎蛤。
OpenCV里的圖像去噪
OpenCV提供了這個(gè)技術(shù)的四個(gè)變形:
1.cv2.fastNlMeansDenoising() - 對(duì)于一個(gè)灰度圖像的
2.cv2.fastNlMeansDenoisingColored() - 對(duì)于彩色圖像的
3.cv2.fastNlMeansDenoisingMulti() - 對(duì)于短時(shí)間內(nèi)拍攝的一序列圖像的(灰度圖像)
4.cv2.fastNlMeansDenoisingColoredMulti() - 和上面一眼個(gè),不過是彩色圖像纪吮。
通用參數(shù)如下:
·h: 決定過濾器強(qiáng)度的參數(shù)。更高的h值能夠更好去噪萎胰,但是會(huì)去掉更多圖像細(xì)節(jié)(10就ok)
·hForColorComponents: 和h一樣碾盟,不過只是針對(duì)彩色圖像的(一般和h一樣)
·templateWindowSize:應(yīng)該是奇數(shù)(推薦7)
·searchWindowSize:應(yīng)該是奇數(shù)(推薦21)
我們會(huì)演示幾個(gè)例子。
1.cv2.fastNlMeansDenoisingColored()
上面說過這事去除彩色圖像噪點(diǎn)的(噪點(diǎn)應(yīng)該是符合高斯分布的)
import numpy as np
import cv2
from matplotlib import pyplot as pltimg = cv2.imread('die.png')
dst = cv2.fastNlMeansDenoisingColored(img,None,10,10,7,21)
plt.subplot(121),plt.imshow(img)
plt.subplot(122),plt.imshow(dst)
plt.show()
下面是一個(gè)放大的結(jié)果技竟。我的輸入圖像是一個(gè)σ=25的高斯噪點(diǎn)
2. cv2.fastNlMeansDenoisingMulti()
現(xiàn)在我們把方法應(yīng)用到視頻上冰肴,第一個(gè)參數(shù)是帶噪點(diǎn)的幀的列表。第二個(gè)參數(shù)imgToDenoiseIndex 指定我們需要降哪一幀的噪榔组,應(yīng)該寫輸入列表里的幀的索引熙尉。第三個(gè)參數(shù)temporalWindowSize指定多少個(gè)周圍的幀用來去噪。應(yīng)該是奇數(shù)搓扯。這種情況下检痰,temporalWindowSize數(shù)量的幀被用來去噪,其中中間幀是要去噪的锨推。比如你傳入了5幀的列表作為輸入铅歼,imgToDenoiseIndex = 2, temporalWindowSize = 3.那么幀1换可,幀2椎椰, 幀3倍用來給幀2去噪,看下面的例子:
import numpy as np
import cv2
from matplotlib import pyplot as pltcap = cv2.VideoCapture('vtest.avi')
# create a list of first 5 frames
img = [cap.read()[1] for i in xrange(5)]# convert all to grayscale
gray = [cv2.cvtColor(i, cv2.COLOR_BGR2GRAY) for i in img]# convert all to float64
gray = [np.float64(i) for i in gray]# create a noise of variance 25
noise = np.random.randn(*gray[1].shape)*10# Add this noise to images
noisy = [i+noise for i in gray]# Convert back to uint8
noisy = [np.uint8(np.clip(i,0,255)) for i in noisy]# Denoise 3rd frame considering all the 5 frames
dst = cv2.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()
它會(huì)花掉很多時(shí)間計(jì)算沾鳄,上面的結(jié)果里慨飘,第一張圖是原始幀,第二張圖是噪點(diǎn)圖译荞,第三章是去噪的瓤的。