欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-25 13:06:21
...

算子 (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的左上角开始,一行一行移动,到底后还下一行,直到右下角。

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

(这只是CNN的一个铺垫)

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