基于sobel算子的边缘检测 (python实现)

巧了我就是萌 提交于 2020-01-28 05:17:09

算子 (Operator)

  在图像处理中,边缘检测是不可分割的一个组成部分,而算子,可以看作是边缘检测的一个媒介。像我们这种学EE的,算子就好比是一个巴特沃夫滤波器,滤掉我们不想要的,留下我们所需要的;又像是我们小时候看到的筛米的米筛子,那时候家里吃的米掺杂着许多“奇怪的”东西,小石砾、麦穗等等,不像现在买来的大米都是机器为我们筛好的,基本是很少能在吃米饭时牙齿突然咔嚓一下,当时确是蛮痛苦的。

  在本篇文章中用的是Sobel算子,是使用两个与原始图像卷积的3×3内核来计算导数的近似值-一个用于水平变化,一个用于垂直变化。

  如果我们将A定义为源图像,并且GxG_xGyG_y是两个图像,每个点分别包含垂直和水平导数近似值,则计算如下:
Gx=[10+120+210+1]AGy=[121000+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
这里,* 表示卷积运算,也就是两个矩阵对应位置相乘,即点乘。

  一张图片显然“pixel”不全是3×3的,甚至就没有图片是这么小的,那么上面的实施方法也很简单,就是从A的左上角开始,一行一行移动,到底后还下一行,直到右下角。

在这里插入图片描述

这里引用一个我很喜欢的博主(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

这是在垂直方向的检测,处理前后的图片对比如下:

原图和处理后图片的对比
那么水平方向的检测也就很简单了。

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

原图和处理后图片的对比

水平和垂直方向同时进行,也就是在计算每个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

原图和处理后图片的对比

很明显最后一张图片的效果是最好的。

题外话

  附上两个小程序,是用作图片显示和处理的,我上面的对比图就是由这两个程序给出。

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,av,h,a就是三张对比图啦。

(这只是CNN的一个铺垫)

----------------
该文章首发于 zyairelu.cn
欢迎来到我的网站进行评论及研讨
个人邮箱zyairelu@gmail.com
----------------

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!