Python實現圖像的椒鹽噪聲添加和基礎的平滑處理(均值濾波與中值濾波)

均值濾波與中值濾波是最常見的兩種平滑的方式,尤其是中值濾波能起到強大的降噪效果。

本文內容分爲三部分:
1.實現添加圖片的椒鹽噪聲
2.實現調用內置函數進行均值和中值濾波
3.自編函數深刻理解均值和中值濾波

1.何爲椒鹽噪聲?如何添加椒鹽噪聲?

首先我們知道在圖像當中的噪聲實際上就是在圖像中搗亂的像素點。

懂了之後椒鹽噪聲就很好理解了。
其實椒鹽噪聲(pepper and salt noise),就是字面意思。好像是黑胡椒和白鹽的噪聲. 具體來講如下圖所示:
左側爲原圖 右側爲添加了4%椒鹽噪聲後的圖片。
在這裏插入圖片描述
放大了看上面有黑色和白色的小點。我們只要在原有的圖像中把相應的像素點隨機改爲黑色和白色的就好了.實現方法如下:

import cv2
import random
def pepper_and_salt(img,percentage):
    num=int(percentage*img.shape[0]*img.shape[1])#  椒鹽噪聲點數量
    random.randint(0, img.shape[0])
    img2=img.copy()
    for i in range(num):
        X=random.randint(0,img2.shape[0]-1)#從0到圖像長度之間的一個隨機整數,因爲是閉區間所以-1
        Y=random.randint(0,img2.shape[1]-1)
        if random.randint(0,1) ==0: #黑白色概率55開
            img2[X,Y] = (255,255,255)#白色
        else:
            img2[X,Y] =(0,0,0)#黑色
    return img2
img=cv2.imread("lena.tiff")
img2 = pepper_and_salt(img,0.04)#百分之4的椒鹽噪音
cv2.imshow("lena",img)
cv2.imshow("lena_pepper_and_salt",img2)
cv2.waitKey(0)

2.實現圖像均值濾波和中值濾波

二者的原理都十分簡單,常見的方法中

均值就是把一個像素點九宮格(取決於你的輸入)內所有點的rgb值加在一起再除以9,也就是取九宮格九個格子的平均值,來覆蓋原有的rgb值。而中值濾波則就是取九個格子的中位數來覆蓋原有的rgb值。

當然不一定是九宮格,這取決於你的輸入,反正是一個你輸入數字的n*n宮格的平均值(均值濾波) 或 中位數 (中值)

實現代碼非常簡單,如下所示:

img_averaging=cv2.blur(img2,(3,3)) #均值濾波
img_median = cv2.medianBlur(img2,3) #中值濾波

cv2.imshow("lena_averaging",img_averaging)
cv2.imshow("lena_median",img_median)
cv2.waitKey(0)

這裏面要注意的就是中值濾波中的輸入不能爲偶數,你想你一個偶數取中位數不就有小數點了嗎?或者是去前面和後面,就不準確了。所有隻能是奇數

效果如下
在這裏插入圖片描述
你可以明顯的看出來,均值濾波的效果不是十分明顯,而中值濾波簡直神了,幾乎還原了原圖。

到了這裏,題目的要求就已經完成了。

3、自行實現兩者

首先來說,一般來說如果有內置的函數儘量使用內置的函數,這樣運行速度快,相對來講兼容性要好而且方便。但是這裏只是提供一個大致的編程思路。

話不多說了,因爲邏輯上十分簡單,所以實現起來也不困難。
直接上代碼:
1.均值濾波

def averaging_filter(img,tuple_reform):
    img2=img.copy()
    X=img2.shape[0]
    Y=img2.shape[1]
    shift=int((tuple_reform[0]+tuple_reform[1]-2)/2)
    for x in range(shift,X-shift):
        for y in range(shift,Y-shift):
            pixel_r=0
            pixel_g=0
            pixel_b=0

            for i in range(tuple_reform[0]): #方位上取前3個的維度的
                for j in range(tuple_reform[1]):
                    pixel_r+=int(img[x+i-shift,y+j-shift,0])
                    pixel_g+=int(img[x+i-shift,y+j-shift,1])
                    pixel_b+=int(img[x+i-shift,y+j-shift,2])

            num=tuple_reform[0]*tuple_reform[1]
            img2[x,y,0] = int(pixel_r/num)
            img2[x,y,1] = int(pixel_g/num)
            img2[x,y,2] = int(pixel_b/num)
            #該像素點等於9宮格內所有相加取平均而成,
    return img2

2.中值濾波

def median_filter(img,median):
    img2 = img.copy()
    X = img2.shape[0]
    Y = img2.shape[1]
    edge = int((median) -1/ 2) # 每條邊上做這麼多次
    shift = int(edge / 2)  # 計算位置的偏移量
    edge+=1
    for x in range(shift, X - shift):
        for y in range(shift, Y - shift):
            List_r=[] #收集五個點的rgb值
            List_g=[]
            List_b=[]
            for e in range(2): #兩種情況爲0對x加減,爲1對y加減
                for i in range(edge):  # 方位上取前3個的維度的
                    if e == 0:
                        List_r.append(int(img2[x + i - shift, y, 0]))
                        List_g.append(int(img2[x + i - shift, y, 1]))
                        List_b.append(int(img2[x + i - shift, y, 2]))
                    else:
                        List_r.append(int(img2[x, y + i - shift, 0]))
                        List_g.append(int(img2[x, y + i - shift, 1]))
                        List_b.append(int(img2[x, y + i - shift, 2]))
            List_r.remove(img2[x,y,0]) #消除重複元素
            List_g.remove(img2[x, y, 1])
            List_b.remove(img2[x, y, 2])

            img2[x, y, 0] = np.median(List_r)
            img2[x, y, 1] = np.median(List_g)
            img2[x, y, 2] = np.median(List_b)
    return img2

提示:我所實現的中值濾波方式與正常的九宮格式不同,而是一個十字型陣列,以原來的那個像素點爲十字交叉點,同樣也是取中值。

且我實現的方法從算法的角度上不好,因爲時間複雜度很高,再加上實現中值濾波時採用了每個像素點都要創建列表進行收集。

效果如下:

其實剛纔有的小夥伴就以及想到了,我那樣子去進行九宮格似的取中位數和平均那周圍的點怎麼辦呢?
常見的處理辦法有三種:
1.不做處理。就像我這裏一樣,因爲邊界很小,不影響大局,但是邊上還是會存在一些噪聲
2.邊上的rgb值取0.這個方法會使得邊上出現一個黑框
3.濾波後,邊框上的點的rgb值等於 距離邊框上每個像素點最近的像素點的rgb值.應該就是內置函數的操作,邊上就不會有噪聲

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章