天天看點

基于sobel算子的邊緣檢測 (python實作)

算子 (Operator)

  在圖像進行中,邊緣檢測是不可分割的一個組成部分,而算子,可以看作是邊緣檢測的一個媒介。像我們這種學EE的,算子就好比是一個巴特沃夫濾波器,濾掉我們不想要的,留下我們所需要的;又像是我們小時候看到的篩米的米篩子,那時候家裡吃的米摻雜着許多“奇怪的”東西,小石礫、麥穗等等,不像現在買來的大米都是機器為我們篩好的,基本是很少能在吃米飯時牙齒突然咔嚓一下,當時确是蠻痛苦的。

  在本篇文章中用的是Sobel算子,是使用兩個與原始圖像卷積的3×3核心來計算導數的近似值-一個用于水準變化,一個用于垂直變化。

  如果我們将A定義為源圖像,并且 G x G_x Gx​和 G y G_y Gy​是兩個圖像,每個點分别包含垂直和水準導數近似值,則計算如下:

G x = [ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 ] ∗ A G y = [ − 1 − 2 − 1 0 0 0 + 1 + 2 + 1 ]   ∗ A G_x =\begin{bmatrix} -1 & 0 & +1\\ -2 & 0 & +2\\ -1 & 0 & +1\\ \end{bmatrix} * A\quad\quad\quad G_y = \begin{bmatrix} -1 & -2 & -1\\ 0 & 0 & 0\\ +1 & +2 & +1\\ \end{bmatrix}\ * A Gx​=⎣⎡​−1−2−1​000​+1+2+1​⎦⎤​∗AGy​=⎣⎡​−10+1​−20+2​−10+1​⎦⎤​ ∗A

這裡, ∗ * ∗ 表示卷積運算,也就是兩個矩陣對應位置相乘,即點乘。

  一張圖檔顯然“pixel”不全是3×3的,甚至就沒有圖檔是這麼小的,那麼上面的實施方法也很簡單,就是從A的左上角開始,一行一行移動,到底後還下一行,直到右下角。

基于sobel算子的邊緣檢測 (python實作)

這裡引用一個我很喜歡的部落客(victorzhou)的圖。

  在大多數情況下,我們“篩選”後的圖檔大小要和原圖檔相等,一般有兩種方法可以解決,這裡我采用的是在處理後的圖檔外圍一圈補零,即塗黑一圈。

算法實作

  簡單的介紹過後,下面給出我的代碼,代碼由幾個部分組成,首先給出核心部分:

def sobel_v(img, threshold):
    '''
    edge detection with the vertical Sobel filter

    Parameters
    ----------
    img : TYPE
        the image input.
    threshold : TYPE
         varies for application [0 255].

    Returns
    -------
    mag : TYPE
        output after edge detection.

    '''
    G_x = np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]])
    rows = np.size(img, 0)
    columns = np.size(img, 1)
    mag = np.zeros(img.shape)
    for i in range(0, rows - 2):
        for j in range(0, columns - 2):
            v = sum(sum(G_x * img[i:i+3, j:j+3]))  # vertical
            mag[i+1, j+1] = v
            
    for p in range(0, rows):
        for q in range(0, columns):
            if mag[p, q] < threshold:
                mag[p, q] = 0
    return mag
           

這是在垂直方向的檢測,處理前後的圖檔對比如下:

基于sobel算子的邊緣檢測 (python實作)

那麼水準方向的檢測也就很簡單了。

def sobel_h(img, threshold):
    '''
    edge detection with the horizon Sobel filter

    Parameters
    ----------
    img : TYPE
        the image input.
    threshold : TYPE
         varies for application [0 255].

    Returns
    -------
    mag : TYPE
        output after edge detection.

    '''
    G_y = np.array([[-1, -2, -1],[0, 0, 0],[1, 2, 1]])
    rows = np.size(img, 0)
    columns = np.size(img, 1)
    mag = np.zeros(img.shape)
    for i in range(0, rows - 2):
        for j in range(0, columns - 2):
            h = sum(sum(G_y * img[i:i+3, j:j+3]))  # horizon
            mag[i+1, j+1] = h
            
    for p in range(0, rows):
        for q in range(0, columns):
            if mag[p, q] < threshold:
                mag[p, q] = 0
    return mag
           
基于sobel算子的邊緣檢測 (python實作)

水準和垂直方向同時進行,也就是在計算每個pixel的時候,将水準和垂直的值作一次平方和的處理即可。

def sobel(img, threshold):
    '''
    edge detection based on sobel

    Parameters
    ----------
    img : TYPE
        the image input.
    threshold : TYPE
         varies for application [0 255].

    Returns
    -------
    mag : TYPE
        output after edge detection.

    '''
    G_x = np.array([[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]])
    G_y = np.array([[-1, -2, -1],[0, 0, 0],[1, 2, 1]])
    rows = np.size(img, 0)
    columns = np.size(img, 1)
    mag = np.zeros(img.shape)
    for i in range(0, rows - 2):
        for j in range(0, columns - 2):
            v = sum(sum(G_x * img[i:i+3, j:j+3]))  # vertical
            h = sum(sum(G_y * img[i:i+3, j:j+3]))  # horizon
            mag[i+1, j+1] = np.sqrt((v ** 2) + (h ** 2))
            
    for p in range(0, rows):
        for q in range(0, columns):
            if mag[p, q] < threshold:
                mag[p, q] = 0
    return mag
           
基于sobel算子的邊緣檢測 (python實作)

很明顯最後一張圖檔的效果是最好的。

題外話

  附上兩個小程式,是用作圖檔顯示和處理的,我上面的對比圖就是由這兩個程式給出。

import numpy as np
import cv2

def img_show(img):  
    cv2.namedWindow("Image")
    cv2.imshow("Image", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
def sub_plot(img_1, img_2):
    l = np.size(img, 1)/4  # a quarter of the columns
    rows = np.size(img, 0) 
    interval = np.ones((rows, int(l)))
    interval = interval * 255
    
    img_o = np.concatenate((img_1, interval, img_2), axis=1)
    return img_o
img = cv2.imread('CNN/pic1.jpg', 0)  # read an image
mag = sobel(img, 70)
mag_v = sobel_v(img, 70)
mag_h = sobel_h(img, 70)
# img_show(mag)

v = sub_plot(img, mag_v)
h = sub_plot(img, mag_h)
a = sub_plot(img, mag)
           

v , h , a v,h,a v,h,a就是三張對比圖啦。

(這隻是CNN的一個鋪墊)

− − − − − − − − − − − − − − − − ---------------- −−−−−−−−−−−−−−−−

該文章首發于 zyairelu.cn

歡迎來到我的網站進行評論及研讨

個人郵箱[email protected]

− − − − − − − − − − − − − − − − ---------------- −−−−−−−−−−−−−−−−

繼續閱讀