完整代碼可以在 我的AI學習筆記 - github 中獲取
原理
傳統的中值濾波算法在椒鹽噪聲的去除領域有着比較廣泛的應用,其具有較強的噪點鑑別和恢復能力,也有比較低的時間複雜度:其基本思想是採用像素點周圍鄰接的若干像素點的中值來代替被污染的像素點;但也存在一定的缺陷,隨着圖像被污染程度的加深,此方法恢復的圖像細節模糊、邊緣損失也會越嚴重。
中值濾波的思想就是比較一定領域內的像素值的大小,取出其中值作爲這個領域的中心像素新的值。假設對一定領域內的所有像素從小到大進行排序,如果存在孤立的噪聲點,比如椒鹽噪聲(椒噪聲——較小的灰度值,呈現的效果是小黑點;鹽噪聲——較大的灰度值,呈現的效果是小白點),那麼從小到大排序的這個數組中,那些孤立的噪聲一定會分佈在兩邊(要麼很小,要麼很大),這樣子取出的中值點可以很好地保留像素信息,而濾除了噪聲點的影響。
中值濾波器受濾波窗口大小影響較大,用於消除噪聲和保護圖像細節,兩者會存在衝突。如果窗口較小,則能較好地保護圖像中的一些細節信息,但對噪聲的過濾效果就會打折扣;反之,如果窗口尺寸較大則會有較好的噪聲過濾效果,但也會對圖像造成一定的模糊效果,從而丟失一部分細節信息。
此處採用改進的自適應中值濾波算法進行圖像恢復:
- 根據圖像處理的空間相關性原則,採用自適應的方法選擇不同的滑動窗口大小;
- 在算法中單濾波窗口大小達到最大值時,採用均值濾波;
代碼實現
def get_window(res_img,noise_mask,sc,i,j,k):
listx = []
if i-sc >= 0:
starti = i-sc
else:
starti = 0
if j+1 <= res_img.shape[1]-1 and noise_mask[0,j+1,k] !=0:
listx.append(res_img[0,j+1,k])
if j-1 >=0 and noise_mask[0,j-1,k] !=0:
listx.append(res_img[0,j-1,k])
if i+sc <= res_img.shape[0]-1:
endi = i+sc
else:
endi = res_img.shape[0]-1
if j+1 <= res_img.shape[1]-1 and noise_mask[endi,j+1,k] !=0:
listx.append(res_img[endi,j+1,k])
if j-1 >=0 and noise_mask[endi,j-1,k] !=0:
listx.append(res_img[endi,j-1,k])
if j+sc <= res_img.shape[1]-1:
endj = j+sc
else:
endj = res_img.shape[1]-1
if i+1 <= res_img.shape[0]-1 and noise_mask[i+1,endj,k] !=0:
listx.append(res_img[i+1,endj,k])
if i-1 >=0 and noise_mask[i-1,endj,k] !=0:
listx.append(res_img[i-1,endj,k])
if j-sc >= 0:
startj = j-sc
else:
startj = 0
if i+1 <= res_img.shape[0]-1 and noise_mask[i+1,0,k] !=0:
listx.append(res_img[i+1,0,k])
if i-1 >=0 and noise_mask[i-1,0,k] !=0:
listx.append(res_img[i-1,0,k])
for m in range(starti,endi+1):
for n in range(startj,endj+1):
if noise_mask[m,n,k] != 0:
listx.append(res_img[m,n,k])
listx.sort()
return listx
def get_window_small(res_img,noise_mask,i,j,k):
listx = []
sc = 1
if i-sc >= 0 and noise_mask[i-1,j,k]!=0:
listx.append(res_img[i-1,j,k])
if i+sc <= res_img.shape[0]-1 and noise_mask[i+1,j,k]!=0:
listx.append(res_img[i+1,j,k])
if j+sc <= res_img.shape[1]-1 and noise_mask[i,j+1,k]!=0:
listx.append(res_img[i,j+1,k])
if j-sc >= 0 and noise_mask[i,j-1,k]!=0:
listx.append(res_img[i,j-1,k])
listx.sort()
return listx
def restore_image(noise_img, size=4):
"""
使用 你最擅長的算法模型 進行圖像恢復。
:param noise_img: 一個受損的圖像
:param size: 輸入區域半徑,長寬是以 size*size 方形區域獲取區域, 默認是 4
:return: res_img 恢復後的圖片,圖像矩陣值 0-1 之間,數據類型爲 np.array,
數據類型對象 (dtype): np.double, 圖像形狀:(height,width,channel), 通道(channel) 順序爲RGB
"""
# 恢復圖片初始化,首先 copy 受損圖片,然後預測噪聲點的座標後作爲返回值。
res_img = np.copy(noise_img)
# 獲取噪聲圖像
noise_mask = get_noise_mask(noise_img)
for i in range(noise_mask.shape[0]):
for j in range(noise_mask.shape[1]):
for k in range(noise_mask.shape[2]):
if noise_mask[i,j,k] == 0:
sc = 1
listx = get_window_small(res_img,noise_mask,i,j,k)
if len(listx) != 0:
res_img[i,j,k] = listx[len(listx)//2]
else:
while(len(listx) == 0):
listx = get_window(res_img,noise_mask,sc,i,j,k)
sc = sc+1
if sc > 4:
res_img[i,j,k] = np.mean(listx)
else:
res_img[i,j,k] = listx[len(listx)//2]
return res_img
恢復效果:
原始圖片
添加噪點
恢復後