? ? ? ? 無論是平均平滑還是高斯平滑,在處理圖像噪聲時,都或多或少會對圖片產生一定的模糊,損失部分信息。較為理想的情況,是可以選擇性地進行濾波,只在噪聲區域進行平滑,而在無噪聲區域不進行平滑,將模糊的影響降到最低,這就是自適應性濾波的思想。通常噪聲的存在,可能會使得附近鄰域內,極值的上下差距較大,或者是方差較大,我們可以設置一定的閾值來判斷該點是否需要進行平滑。不過這個不是該章節的內容,這一章是要學習中值濾波,中值濾波本質上是一個 統計排序濾波器 ,是以該點為中心的的鄰域內的所有像素的統計排序中值作為該點的響應;而平滑就是加權平均數作為響應,概念上有一定差別。
? ? ? ?不同的濾波器在處理不同類型的噪聲是效果不同,對于線性平滑濾波,在處理像素鄰域內的噪聲點時,噪聲或多或少都會影響該點的像素值計算(以高斯平滑為例,距離近則影響大,距離遠則影響小,與距離的平方呈反比);但是中值濾波通常可以將噪聲點直接忽略掉。同時,中值濾波在降噪的同時引起的模糊效應較低。中值濾波的一種典型應用,就是用來消除椒鹽(salt & pepper)噪聲。于是我們先編寫一個函數來為我們的灰度圖像添加椒鹽噪聲。
from PIL import Image
import numpy as np
def AddNoise(src, dst, probility = 0.05, method = "salt_pepper"):
imarray = np.array(Image.open(src))
height, width = imarray.shape
for i in range(height):
for j in range(width):
if np.random.random(1) < probility:
if np.random.random(1) < 0.5:
imarray[i, j] = 0
else:
imarray[i, j] = 255
new_im = Image.fromarray(imarray)
new_im.save(dst)
gray_girl = "C:/Users/60214/Desktop/python_work/DigitalExecution/gray_girl.jpg"
tar = "C:/Users/60214/Desktop/python_work/DigitalExecution/gray_girl_saltpepper.jpg"
AddNoise(gray_girl, tar)
? ? ? ?處理之后的圖像如下,這就是椒鹽噪聲。
? ? ? ? ?使用平均模板處理之后的圖像如下,圖片變模糊的同時并沒有消除椒鹽噪聲。雖然沒有擺圖,但是如果使用高斯平滑,也是同樣的效果,椒鹽噪聲的影響依舊存在。
? ? ? ? ? 使用一個3x3尺寸的中值濾波來處理含有突發性的椒鹽噪聲的代碼如下。其中我們選擇的填充方式是無填充,也就是對圖像邊緣,上下左右處忽略掉不進行濾波,只對可以容納下一個濾波模板的區域濾波。這樣子的做法好處是代碼編寫起來比較簡單,而一般情況下圖像邊緣出的信息不是那么重要所以這樣子做的風險比較小。另外,執行尋找中值的用numpy自帶的median方法,我們也可以自己寫一個排序算法來執行。
from PIL import Image
import numpy as np
def MedianFilter(src, dst, k = 3, padding = None):
imarray = np.array(Image.open(src))
height, width = imarray.shape
if not padding:
edge = int((k-1)/2)
if height - 1 - edge <= edge or width - 1 - edge <= edge:
print("The parameter k is to large.")
return None
new_arr = np.zeros((height, width), dtype = "uint8")
for i in range(height):
for j in range(width):
if i <= edge - 1 or i >= height - 1 - edge or j <= edge - 1 or j >= height - edge - 1:
new_arr[i, j] = imarray[i, j]
else:
new_arr[i, j] = np.median(imarray[i - edge:i + edge + 1, j - edge:j + edge + 1])
new_im = Image.fromarray(new_arr)
new_im.save(dst)
src = "C:/Users/60214/Desktop/python_work/DigitalExecution/gray_girl_saltpepper.jpg"
dst = "C:/Users/60214/Desktop/python_work/DigitalExecution/aaa.jpg"
MedianFilter(src, dst)
?? ? ? 代碼運行的結果是得到一張處理后的圖像,如上圖所示。可以看到確實把絕大部分的椒鹽點都去除了,除了在邊緣上一個像素寬度的區域有一些零星的點。但是,跟其他平滑的結果類似的,中值濾波也使得圖像的清晰度有所下降。這是因為在處理一些邊緣的時候也采用了中值濾波,導致了清晰度的下降。所以如果要解決這個問題,可以在對像素點賦予鄰域的中位數之前添加一個判斷條件。因為我們知道,噪聲,往往都是數值與附近的區域相差很大,接近0或者是255,也就是很大可能是附近鄰域內的極值。所以我們的判斷條件就是,該像素是否是濾波窗口覆蓋下鄰域的極大值或極小值,如果是就進行中值濾波;如果不是就不予處理。修改后的新的代碼為
from PIL import Image
import numpy as np
def BetterMedianFilter(src, dst, k = 3, padding = None):
imarray = np.array(Image.open(src))
height, width = imarray.shape
if not padding:
edge = int((k-1)/2)
if height - 1 - edge <= edge or width - 1 - edge <= edge:
print("The parameter k is to large.")
return None
new_arr = np.zeros((height, width), dtype = "uint8")
for i in range(height):
for j in range(width):
if i <= edge - 1 or i >= height - 1 - edge or j <= edge - 1 or j >= height - edge - 1:
new_arr[i, j] = imarray[i, j]
else:
#nm:neighbour matrix
nm = imarray[i - edge:i + edge + 1, j - edge:j + edge + 1]
max = np.max(nm)
min = np.min(nm)
if imarray[i, j] == max or imarray[i, j] == min:
new_arr[i, j] = np.median(nm)
else:
new_arr[i, j] = imarray[i, j]
new_im = Image.fromarray(new_arr)
new_im.save(dst)
src = "C:/Users/60214/Desktop/python_work/DigitalExecution/gray_girl_saltpepper.jpg"
dst = "C:/Users/60214/Desktop/python_work/DigitalExecution/aaaa.jpg"
MedianFilter(src, dst)
? ? ? ?下圖是k=3是的改進后的中值濾波策略的結果,可以看到圖像的清晰度得到了較大的保留,噪聲的數量就相對也殘留的比較多。從中可以看到,二者之間有此消彼長的關系。至于為什么還有這么多的椒鹽噪聲,原因是因為我們添加噪聲的代碼中設置的概率太高了,導致圖像中的椒鹽噪聲數量非常多,在小區域內有可能有許多的噪聲點,導致算法所尋找到的中值仍然是噪聲的數值范圍。這種情況下擴大濾波模板的大小并不會有多大的改變。此時可以將已經執行過一次中值濾波的結果圖像再執行一次中值濾波,效果就會更好一些。


更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
