天天看點

數字圖像處理:空間濾波

要求

對一副圖像加噪聲,進行平滑,銳化作用。

待處理圖像:

數字圖像處理:空間濾波

加噪

生成椒鹽噪聲:

def sp_noisy(image, s_vs_p=0.5, amount=0.08):
    out = np.copy(image)
    num_salt = np.ceil(amount * image.size * s_vs_p)
    coords = [np.random.randint(0, i - 1, int(num_salt)) for i in image.shape]
    out[tuple(coords)] = 255
    num_pepper = np.ceil(amount * image.size * (1. - s_vs_p))
    coords = [np.random.randint(0, i - 1, int(num_pepper)) for i in image.shape]
    out[tuple(coords)] = 0
    return out
           

結果

胡椒和鹽各占0.5,總密度0.08的椒鹽噪聲:

數字圖像處理:空間濾波

平滑空間濾波(線性)

均值濾波

均值濾波過程:

g ( x , y ) = ∑ s = − a a ∑ t = − b b w ( s , t ) f ( x + s , y + t ) ∑ s = − a a ∑ t = − b b w ( s , t ) g(x, y) = \frac{\sum_{s=-a}^a \sum_{t=-b}^b{ w(s, t) f(x+s, y+t)} }{\sum_{s=-a}^a \sum_{t=-b}^b w(s, t)} g(x,y)=∑s=−aa​∑t=−bb​w(s,t)∑s=−aa​∑t=−bb​w(s,t)f(x+s,y+t)​

a = ( m − 1 ) / 2 a = (m -1)/2 a=(m−1)/2

b = ( n − 1 ) / 2 b = (n - 1)/2 b=(n−1)/2

m=n=3方形卷積模闆:

kernel = np.array([[1, 1, 1],
                   [1, 1, 1],
                   [1, 1, 1]], np.float32)/9
           

外圍補0的線性濾波器:

def linear_filter(image, x, y, kernel, out):
    sum_wf = 0
    m = kernel.shape[0]
    n = kernel.shape[1]
    a = int((m - 1) / 2)
    b = int((n - 1) / 2)
    for s in range(-a, a + 1):
        for t in range(-b, b + 1):
            # convolution rotation 180
            x_s = (x - s) if (x - s) in range(0, image.shape[0] - 1) else 0
            y_t = (y - t) if (y - t) in range(0, image.shape[1] - 1) else 0
            sum_wf += kernel[a + s][b + t] * image[x_s][y_t]
    out[x][y] = sum_wf
           

空間濾波函數實作:

def spatial_filtering(image, kernel, filter_):
    out = np.copy(image)
    h = image.shape[0]
    w = image.shape[1]
    for x in range(h):
        print(str(int(x/h * 100)) + "%")
        for y in range(w):
            filter_(image, x, y, kernel, out)
    return out

           

調用

3 * 3均值濾波後:

數字圖像處理:空間濾波

另一個3 * 3 的均值濾波模闆結果:

kernel = np.array([[1, 2, 1],
                   [2, 4, 2],
                   [1, 2, 1]], np.float32)/16
           
數字圖像處理:空間濾波

opencv 實作:

數字圖像處理:空間濾波

opencv速度要快很多,最後的效果是一樣

5 * 5均值濾波:

數字圖像處理:空間濾波

15 * 15均值濾波:

數字圖像處理:空間濾波

圖像太過模糊,因為對外圍取了0,可以明顯看到周圍有暗邊

opencv:

數字圖像處理:空間濾波

opencv外圍不是補0

Embossment算子

kernel = np.array([[2, 0, 0],
                   [0, 0, 0],
                   [0, 0, 2]], np.float32)/4
           
數字圖像處理:空間濾波

對去椒鹽燥沒什麼效果

統計排序濾波(非線性)

中值濾波

過程為求領域内像素值的中值,視窗由kernel給出,置1為需要統計的像素

中值濾波器:

def nonlinear_median_filter(image, x, y, kernel, out):
    sp = []
    m = kernel.shape[0]
    n = kernel.shape[1]
    a = int((m - 1) / 2)
    b = int((n - 1) / 2)
    for s in range(-a, a + 1):
        for t in range(-b, b + 1):
            x_s = (x + s) if (x + s) in range(0, image.shape[0] - 1) else 0
            y_t = (y + t) if (y + t) in range(0, image.shape[1] - 1) else 0
            if kernel[a + s][b + t]:
                sp.append(image[x_s][y_t])
    out[x][y] = np.median(sp)
           

3*3中值濾波結果

模闆:

數字圖像處理:空間濾波

最大值最小值同理,下面是去取椒鹽噪聲對比圖(均值,中值,最大值,最小值):

數字圖像處理:空間濾波

可以看到中值效果最好,最大值和最小值不适用于去除椒鹽噪聲

不同模闆對比

k1 = np.array([
    [1, 1, 1],
    [1, 1, 1],
    [1, 1, 1]
], np.float32)

k2 = np.ones((5, 5))

k3 = np.array([
    [0, 0, 1, 0, 0],
    [0, 0, 1, 0, 0],
    [1, 1, 1, 1, 1],
    [0, 0, 1, 0, 0],
    [0, 0, 1, 0, 0],
])
           
數字圖像處理:空間濾波

使用k2圖像整體顔色偏暗,個人感覺k3效果最好

空間銳化濾波器

待處理圖:

數字圖像處理:空間濾波

二階微分-拉普拉斯算子(線性)

∇ 2 f = f ( x + 1 , y ) + f ( x − 1 , y ) + f ( x , y + 1 ) + f ( x , y − 1 ) − 4 f ( x , y ) \nabla^2f =f(x+1,y) + f(x-1,y) + f(x,y+1) + f(x,y-1) - 4f(x,y) ∇2f=f(x+1,y)+f(x−1,y)+f(x,y+1)+f(x,y−1)−4f(x,y)

g ( x , y ) = f ( x , y ) + c [ ∇ 2 f ( x , y ) ] g(x,y) = f(x,y) +c[\nabla^2f(x,y)] g(x,y)=f(x,y)+c[∇2f(x,y)]

當 c = 1 時 當c =1時 當c=1時

g ( x , y ) = f ( x + 1 , y ) + f ( x − 1 , y ) + f ( x , y + 1 ) + f ( x , y − 1 ) − 3 f ( x , y ) g(x,y) = f(x+1,y) + f(x-1,y) + f(x,y+1) + f(x,y-1) - 3f(x,y) g(x,y)=f(x+1,y)+f(x−1,y)+f(x,y+1)+f(x,y−1)−3f(x,y)

線性濾波實作函數基本和平滑的一樣,但是銳化運算時會出現小于0或大于255的情況,是以需要對其處理

也是進行卷積運算:

def spatial_filtering(image, kernel, filter_):
    out = np.copy(image)
    h = image.shape[0]
    w = image.shape[1]
    for x in range(h):
        # print(str(int(x/h * 100)) + "%")
        for y in range(w):
            filter_(image, x, y, kernel, out)
    return out


def linear_filter(image, x, y, kernel, out):
    sum_wf = 0
    m = kernel.shape[0]
    n = kernel.shape[1]
    a = int((m - 1) / 2)
    b = int((n - 1) / 2)
    for s in range(-a, a + 1):
        for t in range(-b, b + 1):
            # convolution rotation 180
            x_s = (x - s) if (x - s) in range(0, image.shape[0] - 1) else 0
            y_t = (y - t) if (y - t) in range(0, image.shape[1] - 1) else 0
            sum_wf += kernel[a + s][b + t] * image[x_s][y_t]
    if sum_wf < 0:
        sum_wf = 0
    if sum_wf > 255:
        sum_wf = 255
    out[x][y] = int(sum_wf)
           

模闆:

laplacian_mask1 = np.array([
    [0,  1, 0],
    [1, -4, 1],
    [0,  1, 0],
])

laplacian_mask2 = np.array([
    [1,  1, 1],
    [1, -8, 1],
    [1,  1, 1],
])

laplacian_mask3 = np.array([
    [-1, -1, -1],
    [-1,  9, -1],
    [-1, -1, -1],
])

           

模闆2考慮了對角項,模闆3對原圖像進銳化,由于是線性操作,直接調用線性濾波

調用:

結果

數字圖像處理:空間濾波
數字圖像處理:空間濾波
數字圖像處理:空間濾波

可以看到模闆2的濾波效果要好與模闆1,模闆3實作了對原圖像的銳化

一階微分-梯度(非線性)

雖然是非線性的操作,但是求 g x , g y g_x, g_y gx​,gy​是線性操作,是以可以分開求解,最後做非線性的操作,如求開方和絕對值:

簡單起見,直接修改原來的線性濾波函數,改成求絕對值:

def linear_filter(image, x, y, kernel, out):
    sum_wf = 0
    m = kernel.shape[0]
    n = kernel.shape[1]
    a = int((m - 1) / 2)
    b = int((n - 1) / 2)
    for s in range(-a, a + 1):
        for t in range(-b, b + 1):
            # convolution rotation 180
            x_s = (x - s) if (x - s) in range(0, image.shape[0] - 1) else 0
            y_t = (y - t) if (y - t) in range(0, image.shape[1] - 1) else 0
            sum_wf += kernel[a + s][b + t] * image[x_s][y_t]

    sum_wf = abs(sum_wf)
    if sum_wf > 255:
        sum_wf = 255
    out[x][y] = int(sum_wf)
           

然後分别求 ∣ g x ∣ , ∣ g y ∣ |g_x|,|g_y| ∣gx​∣,∣gy​∣:

gradient_mask_1 = np.array([
    [0,  0,  0],
    [0, -1,  1],
    [0,  0,  0],
])
gradient_mask_2 = np.array([
    [0,  0,  0],
    [0, -1,  0],
    [0,  1,  0],
])
image_gradient_mask_1 = spatial_filtering(image, gradient_mask_1, linear_filter)
image_gradient_mask_2 = spatial_filtering(image, gradient_mask_1, linear_filter)
image_gradient_mask = image_gradient_mask_1 + image_gradient_mask_2
           

結果:

數字圖像處理:空間濾波

Roberts 算法 交叉差分

調用

roberts_mask_1 = np.array([
    [0,  0,  0],
    [0, -1,  0],
    [0,  0,  1],
])
roberts_mask_2 = np.array([
    [0,  0,  0],
    [0, 0,  -1],
    [0,  1,  0],
])

image_soble_mask_1 = spatial_filtering(image, gradient_mask_1, linear_filter)
image_soble_mask_2 = spatial_filtering(image, gradient_mask_1, linear_filter)
image_soble_mask = image_soble_mask_1 + image_soble_mask_2
           

結果

數字圖像處理:空間濾波

Soble算子

調用:

soble_mask_1 = np.array([
    [-1,  -2,  -1],
    [0,    0,   0],
    [1,    2,   1],
])
soble_mask_2 = np.array([
    [-1,   0,   1],
    [-2,   0,   2],
    [-1,   0,   1],
])

image_soble_mask_1 = spatial_filtering(image, soble_mask_1, linear_filter)
image_soble_mask_2 = spatial_filtering(image, soble_mask_2, linear_filter)
image_soble_mask = image_soble_mask_1 + image_soble_mask_2
           

結果

數字圖像處理:空間濾波

最後都增加到原圖中的效果:

數字圖像處理:空間濾波

可以看到:從梯度算子、Roberts 算子、Soble算子,效果依次增強