NumPy实现Canny算法

步骤

1.平滑:模糊削弱噪声。

2. 计算梯度,用Sobel算子计算像素的梯度,计算得到垂直梯度和水平梯度,即为Gx和Gy, 像素的总梯度是

3. 细化边缘:用非极大值抑制,局部最大值保留为边缘。参考坐标如下:

4. 双阈值抑制:根据大小两个阈值(由编码者给定),如果某点的像素高于大阈值的确定为边缘,保留。低于小阈值的不是边缘,置为0。小阈值<某点的像素<=大阈值,遍历这个像素相邻的8个像素,如果8个中有一个的像素>大阈值,则说明,某点的像素与强边缘相连,则保留某点的像素。

代码实现:

import cv2 as cv
import  matplotlib.pyplot as plt
import numpy as np

def showImage(name,img):
    plt.imshow(img,cmap="gray")
    plt.title(name)
    plt.show()

# 检测轮廓
def canny(img,th1,th2):
    #平滑
    img2=cv.GaussianBlur(img,(5,5),2)
    #计算梯度
    gradx=cv.Sobel(img,cv.CV_64F,1,0)
    grady=cv.Sobel(img,cv.CV_64F,0,1)

    # 计算每个像素的总梯度
    R=np.sqrt((gradx)**2+(grady)**2)
    # 计算梯度的方向 (gradx+1e-3)防止分母为0
    T=np.arctan(grady/(gradx+1e-3))

    #细化边缘
    (h,w)=R.shape
    img_thin=np.zeros_like(R)
    # 细化边缘按照梯度方向,非极大值抑制
    for i in range(1, h - 1):
        for j in range(1, w - 1):
            thetha = T[i, j]
            # 像素和左右的比较
            if -np.pi / 8 <= thetha < np.pi / 8:
                if R[i, j] == np.max([R[i, j], R[i][j - 1], R[i][j + 1]]):
                    img_thin[i, j] = R[i, j]
            # 像素和右上角和左下角比价
            elif -3 * np.pi / 8 <= thetha < -np.pi / 8:
                if R[i, j] == np.max([R[i, j], R[i + 1][j - 1], R[i - 1][j + 1]]):
                    img_thin[i, j] = R[i, j]
            # 像素和右下角、左上角比较
            elif np.pi / 8 <= thetha < 3 * np.pi / 8:
                if R[i, j] == np.max([R[i, j], R[i + 1][j + 1], R[i - 1][j - 1]]):
                    img_thin[i, j] = R[i, j]
            # 像素和上下比较
            else:
                if R[i, j] == np.max([R[i, j], R[i - 1][j], R[i + 1][j]]):
                    img_thin[i, j] = R[i, j]

    (h,w)=img_thin.shape
    #细化边缘,双边阈值
    edge=np.zeros_like(img_thin,dtype=np.uint8)
    for i in range(1,h-1):
        for j in range(1,w-1):
            #大于th2是强边缘,保留
            if img_thin[i,j]>=th2:
                edge[i,j]=255
            #th1<像素<=th2,周围8像素有强边缘的话,保留,没有默认0
            elif img_thin[i,j]>th1:
                around=img_thin[i-1:i+2,j-1:j+2]
                if around.max()>=th2:
                    edge[i,j]=255

    return edge;
if __name__=="__main__":
    img=cv.imread("../image/goldpig.jpg",0)
    edge1=canny(img,75,200)
    showImage("goldpig",img)
    showImage("goldpig2",edge1)

原图和轮廓图对比:

   

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Canny边缘检测是一种经典的图像边缘检测算法,下面是Python实现代码: ```python import cv2 import numpy as np # 读取图片 img = cv2.imread('image.jpg') # 灰度化处理 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 高斯平滑滤波 gaussian = cv2.GaussianBlur(gray, (5, 5), 0) # 计算梯度 sobelx = cv2.Sobel(gaussian, cv2.CV_64F, 1, 0, ksize=3) sobely = cv2.Sobel(gaussian, cv2.CV_64F, 0, 1, ksize=3) mag = np.sqrt(sobelx**2 + sobely**2) mag = np.uint8(mag) # 非极大值抑制 height, width = mag.shape non_max = np.zeros((height, width), dtype=np.uint8) for i in range(1, height - 1): for j in range(1, width - 1): if sobelx[i, j] == 0: tangent = 1e5 else: tangent = sobely[i, j] / sobelx[i, j] if mag[i, j] >= mag[i-1, j-1] * tangent and mag[i, j] >= mag[i+1, j+1] * tangent: non_max[i, j] = 255 elif mag[i, j] >= mag[i-1, j] and mag[i, j] >= mag[i+1, j]: non_max[i, j] = 255 elif mag[i, j] >= mag[i, j-1] * tangent and mag[i, j] >= mag[i, j+1] * tangent: non_max[i, j] = 255 elif mag[i, j] >= mag[i, j-1] and mag[i, j] >= mag[i, j+1]: non_max[i, j] = 255 # 双阈值和连接边缘 weak = 75 strong = 255 result = np.zeros((height, width), dtype=np.uint8) result[mag > weak] = 1 result[mag > strong] = 255 for i in range(1, height - 1): for j in range(1, width - 1): if result[i, j] == 1: if result[i-1, j-1] == 255 or result[i-1, j] == 255 or result[i-1, j+1] == 255 or result[i, j-1] == 255 or result[i, j+1] == 255 or result[i+1, j-1] == 255 or result[i+1, j] == 255 or result[i+1, j+1] == 255: result[i, j] = 255 else: result[i, j] = 0 # 显示图片 cv2.imshow('Canny Edge Detection', result) cv2.waitKey(0) cv2.destroyAllWindows() ``` 以上代码中使用了OpenCV库实现Canny边缘检测算法,其中包括灰度化处理、高斯平滑滤波、计算梯度、非极大值抑制、双阈值和连接边缘等步骤,最终结果显示在窗口中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值