Pyhton实现边缘检测Robert算子、Sobel算子、Canny算子

  这次我们学习一下计算机视觉的边缘检测算子,主要介绍Robert、Sobel、Canny算子的python实现。
  1、Canny算法,主要有以下步骤:
  (1)灰度化(通常灰度化采用的公式是:Gray=0.299R+0.587G+0.114B;)
  (2)高斯滤波
  (3)计算图像的梯度和梯度方向,(本文使用Sobel算子)
  (4)非极大值抑制(上一步得到的边缘较粗,这里会细化边缘)
  (5)双阈值筛选边缘(二值化显示)

// Canny算子实现
import numpy as np
import cv2
import math


def Canny(img,threshold1,threshold2):
    #step1:高斯滤波
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    new_gray=cv2.GaussianBlur(gray,(5,5),1)

    #展示高斯滤波后的图片
    # gaus_result=new_gray.copy()
    gaus_result=np.uint8(np.copy(new_gray))
    cv2.imshow('gaus',gaus_result)
    # cv2.waitKey(0)

    #step2:求梯度值及梯度方向
    W1,H1=new_gray.shape
    print(new_gray.shape)
    dx=np.zeros([W1-1,H1-1])
    dy=np.zeros([W1-1,H1-1])
    #求出的图像值
    d=np.zeros([W1-1,H1-1])
    #梯度方向
    dgree=np.zeros([W1-1,H1-1])
    for i in range(1,W1-1):
        for j in range(1,H1-1):
            #dx水平方向
            dx[i,j]=new_gray[i-1,j-1]+2*new_gray[i,j-1]+new_gray[i+1,j-1]-\
                    new_gray[i-1,j+1]-2*new_gray[i,j+1]-new_gray[i+1,j+1]
            #dy垂直方向
            dy[i,j]=new_gray[i-1,j-1]+2*new_gray[i-1,j]+new_gray[i-1,j+1]-\
                    new_gray[i+1,j-1]-2*new_gray[i+1,j]-new_gray[i+1,j+1]
            #G=sqrt(Gx**2+Gy**2)
            d[i,j]=np.sqrt(np.square(dx[i,j])+np.square(dy[i,j]))
            #math.atan2求出弧度,math.degrees转为角度
            dgree[i,j]=math.degrees(math.atan2(dy[i,j],dx[i,j]))
            if dgree[i,j]<0:
                dgree+=360

    #
    d_show=np.uint8(np.copy(d))
    cv2.imshow('d_show',d_show)

    #非极大值抑制
    W2, H2=d.shape
    NMS=np.uint8(np.copy(d))
    NMS[0,:]=NMS[W2-1,:]=NMS[:,0]=NMS[:,H2-1]=0
    for i in range(1,W2-1):
        for j in range(1,H2-1):
            if d[i,j]==0:
                NMS[i,j]=0
            else:
                g1=None
                g2=None
                #也可以使用插值方法,此处为设定角度计算
                #0度水平方向
                if (dgree[i,j]<=22.5 and dgree[i,j]>=0) or (dgree[i,j]>=337.5):
                    g1=NMS[i,j-1]
                    g2=NMS[i,j+1]
                #45度方向
                elif (dgree[i,j]<=67.5 and dgree[i,j]>22.5) or (dgree[i,j]<=337.5 and dgree[i,j]>292.5):
                    g1=NMS[i-1,j+1]
                    g2=NMS[i+1,j-1]
                #90度方向
                elif (dgree[i,j]<=112.5 and dgree[i,j]>67.5) or (dgree[i,j]<=292.5 and dgree[i,j]>247.5):
                    g1=NMS[i-1,j]
                    g2=NMS[i+1,j]
                #135度方向
                elif (dgree[i,j]<=157.5 and dgree[i,j]>112.5) or (dgree[i,j]<=247.5 and dgree[i,j]>202.5):
                    g1=NMS[i-1,j-1]
                    g2=NMS[i+1,j+1]
                #180度方向
                else:
                    g1=NMS[i,j-1]
                    g2=NMS[i,j+1]
                #如果当前值小于梯度方向上的任一值,则NMS[i,j]=0,否则保留原值
                if NMS[i,j]<g1 or NMS[i,j]<g2:
                    NMS[i,j]=0

    cv2.imshow('NMS_show',NMS)

    #双阈值算法检测,连接边缘
    W3,H3=NMS.shape
    DT=np.zeros([W3,H3])
    #定义高低阈值
    TL=min(threshold1,threshold2)
    TH=max(threshold1,threshold2)

    for i in range(1,W3-1):
        for j in range(1,H3-1):
            #小于TL的值设置为0
            if (NMS[i,j]<TL):
                DT[i,j]=0
            #大于TH的值设置为255,即边缘
            elif (NMS[i,j]>TH):
                DT[i,j]=255
            #对于在TL~TH之间的数,如果相邻点大于TH,即和边缘值有连接,则也为边缘值,设置为255
            else:
                if NMS[i-1,j]>TH or NMS[i-1,j-1]>TH or NMS[i-1,j+1]>TH or NMS[i,j-1]>TH \
                    or NMS[i,j+1]>TH or NMS[i+1,j]>TH or NMS[i+1,j-1]>TH or NMS[i+1,j+1]>TH:
                    DT[i,j]=255

    return DT

img=cv2.imread('data/lena.png')
cv2.imshow('orginal_img',img)
canny_img=Canny(img,50,140)
cv2.imshow('canny_img',canny_img)
cv2.waitKey(0)



#OpenCV实现Canny算子
# import cv2
#
# img=cv2.imread('data/lena.png')
# canny_img=cv2.Canny(img,150,200)
# cv2.imshow('canny_img',canny_img)
# cv2.waitKey(0)

原图
在这里插入图片描述
step1:高斯滤波
在这里插入图片描述step2:sobel算子得到边缘在这里插入图片描述
step3:非极大值抑制(上一步得到的边缘较粗,这里会细化边缘)
在这里插入图片描述
step4:双阈值筛选边缘(二值化显示),输出Canny结果。
在这里插入图片描述
2、Robert算子
原理可以参考文章:https://blog.csdn.net/u013007900/article/details/78301951
代码实现入下。

// Robert算子
import cv2


#robert算子[[-1,-1],[1,]]
def robert(img):
    w,h=img.shape[:2]
    r=[[-1,-1],[1,1]]
    for i in range(w):
        for j in range(h):
            if (j+2<h) and (i+2<=w):
                process_img=img[i:i+2,j:j+2]
                list_robert=r*process_img
                img[i,j]=abs(list_robert.sum())

    return img

img=cv2.imread('data/lena.png',cv2.IMREAD_GRAYSCALE)
cv2.imshow('orl_img',img)
img=robert(img)
cv2.imshow('robert',img)
cv2.waitKey(0)

原图
在这里插入图片描述
Robert结果
在这里插入图片描述
3、Sobel算子
原理参考:边缘检测:Canny算子,Sobel算子
代码实现

// Sobel算子
import cv2
import numpy as np


def sobel(img):
    w,h=img.shape
    new_img=np.zeros([w,h])
    x_img=np.zeros(img.shape)
    y_img=np.zeros(img.shape)
    sobel_x=np.array([[-1,0,1],[-2,0,2],[-1,0,1]])
    sobel_y=np.array([[-1,-2,-1],[0,0,0],[1,2,1]])
    for i in range(w-2):
        for j in range(h-2):
            x_img[i+1,j+1]=abs(np.sum(img[i:i+3,j:j+3]*sobel_x))
            y_img[i+1,j+1]=abs(np.sum(img[i:i+3,j:j+3]*sobel_y))
            new_img[i+1,j+1]=np.sqrt(np.square(x_img[i+1,j+1])+np.square(y_img[i+1,j+1]))

    return np.uint8(new_img)

img=cv2.imread('data/lena.png',cv2.IMREAD_GRAYSCALE)
cv2.imshow('orl_img',img)
img=sobel(img)
cv2.imshow('sobel',img)
cv2.waitKey(0)

原图灰度后
在这里插入图片描述
Sobel算子结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42872907/article/details/107928128