opencv14:Canny边缘检测

本文详细介绍了Canny边缘检测算法的工作原理,包括降噪、查找图像强度梯度、非极大值抑制和滞后阈值法四个阶段,并通过OpenCV库展示了其实现过程。Canny算法是一种广泛使用的边缘检测方法,旨在准确地检测图像中的边缘并减少误检。

目标

在本章中,将学习

  • Canny边缘检测的概念
  • 函数: cv2.Canny()

理论

Canny Edge Detection是一种流行的边缘检测算法。它由John F. Canny发明。该算法是一个多阶段算法,下面将介绍经历的每个阶段。

降噪

由于边缘检测容易受到图像中噪声的影响,因此第一步是使用5x5高斯滤波器消除图像中的噪声

import cv2
from matplotlib import pyplot as plt
img = cv2.imread('messi.png', 0)
img_gauss = cv2.GaussianBlur(img, (3, 3), 0)
plt.subplot(1,2,1)
plt.imshow(img, cmap='gray')
plt.title('Original')
plt.xticks([])
plt.yticks([])

plt.subplot(1,2,2)
plt.imshow(img_gauss, cmap='gray')
plt.title('GaussBlur')
plt.xticks([])
plt.yticks([])
plt.show()

在这里插入图片描述

查找图像的强度梯度

使用Sobel核在水平和垂直方向上对平滑的图像进行滤波,以在水平方向(Gx)和垂直方向(Gy)上获得一阶导数。从这两张图片中,可以找到每个像素的边缘渐变和方向,如下所示:

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_x^2 G_y^2} \\ Angle \; (\theta) = \tan^{-1} \bigg(\frac{G_y}{G_x}\bigg) Edge_Gradient(G)=Gx2Gy2 Angle(θ)=tan1(GxGy)

渐变方向始终垂直于边缘。将其舍入为代表垂直,水平和两个对角线方向的四个角度之一。


# 查找图像的强度梯度
sobelx = cv2.Sobel(img_gauss, cv2.CV_64F, 1, 0, ksize=5)
sobely = cv2.Sobel(img_gauss, cv2.CV_64F, 0, 1, ksize=5)
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)
plt.subplot(1,4,1)
plt.imshow(img_gauss, cmap='gray')
plt.title('GaussBlur')
plt.xticks([])
plt.yticks([])

plt.subplot(1,4,2)
plt.imshow(sobelx, cmap='gray')
plt.title('Sobelx')
plt.xticks([])
plt.yticks([])

plt.subplot(1,4,3)
plt.imshow(sobely, cmap='gray')
plt.title('Sobely')
plt.xticks([])
plt.yticks([])

plt.subplot(1,4,4)
plt.imshow(sobelxy, cmap='gray')
plt.title('Sobelxy')
plt.xticks([])
plt.yticks([])

plt.show()

在这里插入图片描述

非极大值抑制

在获得梯度大小和方向后,将对图像进行全面扫描,以去除可能不构成边缘的所有不需要的像素。为此,在每个像素处,检查像素是否是其在梯度方向上附近的局部最大值。查看下面的图片:

点A在边缘(垂直方向)上。渐变方向垂直于边缘。点B和C在梯度方向上。因此,将A点与B点和C点进行检查,看是否形成局部最大值。如果是这样,则考虑将其用于下一阶段,否则将其抑制(置为零)。 简而言之,得到的结果是带有“细边”的二进制图像。

滞后阈值法

该阶段确定哪些边缘全部是真正的边缘,哪些不是。为此,需要两个阈值minValmaxVal。强度梯度大于maxVal的任何边缘必定是边缘,而小于minVal的那些边缘必定是非边缘,因此将其丢弃。
介于这两个阈值之间的对象根据其连通性被分类为边缘或非边缘。如果将它们连接到“边缘”像素,则将它们视为边缘的一部分。否则,它们也将被丢弃。见下图:
在这里插入图片描述
边缘A在maxVal之上,因此被视为“确定边缘”。尽管边C低于maxVal,但它连接到边A,因此也被视为有效边,就得到了完整的曲线。但是边缘B尽管在minVal之上并且与边缘C处于同一区域,但是它没有连接到任何“确保边缘”,因此被丢弃。因此,非常重要的一点是必须相应地选择minValmaxVal以获得正确的结果。

注意:在边缘为长线的假设下,该阶段还消除了小像素噪声。因此,我们最终得到的是图像中的强边缘。

OpenCV中的Canny Edge检测

OpenCV将以上所有内容的实现放在单个函数cv2.Canny()中。下面进行使用。

edges = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]] )
第一个参数:image: 输入图像
第二个和第三个参数分别minVal和maxVal
第三个参数是perture_size。它是用于查找图像渐变的Sobel内核的大小。默认情况下为3。
最后一个参数是L2gradient,它指定用于查找梯度幅度的方程式。如果为True,则使用上面提到的更精确的公式,否则使用以下函数:
E d g e G r a d i e n t ( G ) = ∣ G x ∣ ∣ G y ∣ Edge_Gradient (G) = |Gx| |Gy| EdgeGradient(G)=GxGy。默认情况下,它为False。

 # 使用cv2.canny
import cv2
import numpy as np
img = cv2.imread('messi.png', 0)
edges = cv2.Canny(img, 100, 200)
plt.subplot(1,2,1)
plt.imshow(img, cmap='gray')
plt.title('Original')
plt.xticks([])
plt.yticks([])

plt.subplot(1,2,2)
plt.imshow(edges, cmap='gray')
plt.title('Edges')
plt.xticks([])
plt.yticks([])
plt.show()

在这里插入图片描述

附加资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

uncle_ll

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值