OpenCV-Python -- Canny Edge Detection

学习目标

  1. Canny边界检测的概念
  2. 学习函数:cv2.Canny().

理论

Canny是广泛使用的边界检测算法,发明于1986 John. Canny。Canny是多阶段算法,也是目前较为优秀的边缘检测算法。下面将逐步了解每个阶段的内容。

坎尼算法要达到的基本目标:

  1. 低错误率。所有的边缘都应被找到,并且没有伪响应,也就是检测的边缘都是真实的。
  2. 边缘定位准确。已定位的边缘尽可能真实,也就是由检测器标记为边缘的点和真是边缘的中心之间距离应该最小。
  3. 单一边缘相应。对于真实的边缘点,检测器应该返回一个点,也就是真是边缘周围的局部最大数应该最小。这意味着仅存在单一的边缘点。

1. Noise Reduction

由于边界检测算法易受噪声影响,首先使用5x5的高斯滤波器去除噪声。前面已经介绍过高斯平滑滤波器。

2. Finding Intensity Gradient of the Image(图像幅度值)

平滑图像之后,我们使用水平方向和垂直方向的Sobel卷积核,得到水平方向的梯度( G x G_x Gx)和垂直方向的梯度( G y G_y Gy)。基于上述2张图像,我们得到每个像素位置的边界梯度和方向:
E d g e _ G r a d i e n t ( G ) = G x 2 + G y 2 A n g l e ( θ ) = tan ⁡ − 1 ( G y G x ) Edge\_Gradient(G) = \sqrt{G^2_x+G^2_y}\\ Angle(\theta) = \tan^{-1}(\frac{G_y}{G_x}) Edge_Gradient(G)=Gx2+Gy2 Angle(θ)=tan1(GxGy)
梯度方向通常垂直于边界,将其取整则代表垂直、水平和两个对角四个方向之一。

3. Non-maximum Suppression(非极大值抑制)

当得到梯度的大小和方向,那么需要扫描整幅图像,移除任何可能不是边界的像素。每个像素,检查该像素的梯度方向的邻域内是否是局部最大值,过程如下:

在这里插入图片描述
点A在垂直方向的边界上,梯度方向是边界的法向量。点B和C均在A的梯度方向上。所以需要检查A是否是B和C的局部最大值。如果是,进入下一个阶段,否则抑制为零。最终得到一个二值图像,不为零的地方就是边界。

4. Hysteresis Thresholding(滞后阈值)

这一阶段主要确定哪些是真正的边界,哪些不是。因此,我们需要2个阈值,minValmaxVal。高于maxVal的是边界,低于minVal的不是边界,被重新置为零。介于两者之间的值,根据连通性确认是否为边界。如果与真的边界连接,那么是边界,否则不是边界,置为零。见下图:

在这里插入图片描述

示例代码

edges = cv2.Canny(img,100,200)

def Canny(image, threshold1, threshold2, edges=None, apertureSize=None, L2gradient=None): 
    """
       @brief Finds edges in an image using the Canny algorithm @cite Canny86 .
       
       The function finds edges in the input image and marks them in the output map edges using the
       Canny algorithm. The smallest value between threshold1 and threshold2 is used for edge linking. The
       largest value is used to find initial segments of strong edges. See
       <http://en.wikipedia.org/wiki/Canny_edge_detector>
       
       @param image 8-bit input image.
       @param edges output edge map; single channels 8-bit image, which has the same size as image .
       @param threshold1 first threshold for the hysteresis procedure.
       @param threshold2 second threshold for the hysteresis procedure.
       @param apertureSize aperture size for the Sobel operator.
       @param L2gradient a flag, indicating whether a more accurate \f$L_2\f$ norm
       \f$=\sqrt{(dI/dx)^2 + (dI/dy)^2}\f$ should be used to calculate the image gradient magnitude (
       L2gradient=true ), or whether the default \f$L_1\f$ norm \f$=|dI/dx|+|dI/dy|\f$ is enough (
       L2gradient=false ).
    
   	   Canny(dx, dy, threshold1, threshold2[, edges[, L2gradient]]) -> edges
       
       Finds edges in an image using the Canny algorithm with custom image gradient.
       
       @param dx 16-bit x derivative of input image (CV_16SC1 or CV_16SC3).
       @param dy 16-bit y derivative of input image (same type as dx).
       @param edges output edge map; single channels 8-bit image, which has the same size as image .
       @param threshold1 first threshold for the hysteresis procedure.
       @param threshold2 second threshold for the hysteresis procedure.
       @param L2gradient a flag, indicating whether a more accurate \f$L_2\f$ norm
       \f$=\sqrt{(dI/dx)^2 + (dI/dy)^2}\f$ should be used to calculate the image gradient magnitude (
       L2gradient=true ), or whether the default \f$L_1\f$ norm \f$=|dI/dx|+|dI/dy|\f$ is enough (
       L2gradient=false ).
    """

示例代码如下:

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('messi5.jpg',0)
edges = cv2.Canny(img,100,200)

plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])

plt.show()

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值