使用OpenCV+Python进行Canny边缘检测

重磅干货,第一时间送达

如果我们环顾房间,我们会看到大量的物体,每一个都很容易区分,并有自己独特的边缘。我们区分物体的先天能力部分来自于我们的视觉系统检测边缘的能力。检测边缘是视觉的一项基本任务,尽管没有它我们不会完全失明,但以前区分物体的简单任务将变得非常具有挑战性。电脑也是类似的,计算机要检测物体,首先需要识别边缘。

接下来让我们进入 Canny 边缘检测器。

Canny 边缘检测器是一种用于识别图像边缘的算法,。它由 John F. Canny 于 1986 年开发,此后一直被广泛使用。今天,我们将在开放的 Python 计算机视觉库(OpenCV-python)的帮助下,详细探讨 Canny 边缘检测器

设置

让我们首先从初始设置开始。

向我们的 python 文件添加两个依赖项:

import cv2 as cvfrom matplotlib import pyplot as plot

第一个导入是 OpenCV python,这是我们将用来生成 Canny 边缘和一些补充图像的库。我们还将使用 matplotlib 来显示我们的图像。

首先,这是我们将要查找的 Canny 边缘的图像:

Canny 边缘算法需要灰度图像才能正常运行,我们可以在 OpenCV 中将 RGB 图像读取为灰度,如下所示:

# helper function to easily display our imagesdef img_show(title, image): plot.title(title) plot.xticks([]) plot.yticks([]) plot.imshow(image, cmap="gray") plot.show()
# read in our original image as grayscaleimg = cv.imread("original@2x.jpg", cv.IMREAD_GRAYSCALE)
# show grayscale image using our helper functionimg_show("Grayscale Image", img)

我们来创建一个非常简单的辅助函数,用于使用 matplotlib 显示我们的图像。使用这个函数,我们可以查看我们的灰度图像:

原始图像的灰度版本

现在我们已经完成了初始设置,接下来让我们深入研究 Canny 边缘算法!

5个基本步骤

Canny边缘检测算法包括五个步骤:

  1. 高斯滤波

  2. 确定强度梯度

  3. 非极大值抑制

  4. 双阈值

  5. 滞后边缘跟踪

我将详细解释每个步骤。

高斯滤波

我们可能听说过正态分布或高斯分布,这种分布在自然界中始终存在,常用于表示实值随机变量。

在图像处理中,可以对图像应用高斯滤波器以减少噪声,模糊的图片可以直观地观察到这个效果。

由于 Canny 边缘算法使用导数来寻找图像的强度梯度,因此非常容易受到噪声的影响。因此,我们通过对图片应用高斯滤波器来去除噪声。如果我们不去除噪声,算法可能会将图像中的噪声块误认为边缘并错误地标记它们。

OpenCV 使用 sigma = 1 的 5x5 高斯核作为降噪步骤。我已经创建了这个内核的 3D 可视化,可以在下面看到。当应用于我们的图像时,还包含了此过滤器的效果。

5x5 高斯核的 3D 可视化,sigma = 1;应用高斯滤波器的原始图像

尽管高斯滤波图像可能与原始灰度图像相同,但仔细观察会发现轻微的模糊,尤其是在棕榈叶的边缘周围。我们不想过多地模糊图像;否则,我们可能会丢失图像的细节。

我们可以使用以下代码轻松生成此图像:

# blurring the image with a 5x5, sigma = 1 Guassian kernelimg_blur = cv.GaussianBlur(img, (5, 5), 1)
确定强度梯度

在对图像进行平滑处理后,Canny 边缘算法的第二步是找到图片的强度梯度。

尽管“强度梯度”这个名词可能听起来很复杂,但它只是指边缘的方向。一条边实际上可以指向任何方向,但该算法只查看四个方向以简化事情。方向是水平、垂直和两个对角线方向。在数学中,我们将其写为 [0 ° , 90 ° , 45 ° , 135 ° ]。

OpenCV 使用 3x3 Sobel 内核来确定水平方向的导数,然后将其转置以确定垂直方向的导数,这些导数可用于在所需的四个方向上找到我们的边缘。

与高斯核一样,我们也可以在 3D 中可视化 Sobel 核。下边还包括了 Sobel 过滤图像。

3x3 水平 Sobel 核的 3D 可视化;双向应用 Sobel 核的高斯模糊图像

在代码中,我们可以按如下方式生成 Sobel 过滤后的图像:

# obtaining a horizontal and vertical Sobel filtering of the imageimg_sobelx = cv.Sobel(img_blur, cv.CV_64F, 1, 0, ksize=3)img_sobely = cv.Sobel(img_blur, cv.CV_64F, 0, 1, ksize=3)
# image with both horizontal and vertical Sobel kernels appliedimg_sobelxy = cv.addWeighted(cv.convertScaleAbs(img_sobelx), 0.5, cv.convertScaleAbs(img_sobely), 0.5, 0)
非极大值抑制

一旦我们找到了强度梯度,我们就可以使用它们来细化我们的边缘。在这一步之后,结果是一个二值图像,这意味着图像将只包含两种颜色,黑色和白色。同样,非最大抑制这个名字听起来很复杂,实际上这是一个简单的操作。

我们通过检查每个像素在其梯度方向上的相邻像素来确定它是否具有最大强度,从而对每个像素应用非最大抑制。如果像素是最大的,那么我们将其值设置为 1。如果不是,这意味着像素的相邻像素具有更高的强度,我们将其值设置为 0(抑制它)。

双阈值

有一个小问题:并非所有边缘都准确地代表了图像的真实边缘。许多假边缘是由噪声和轻微的颜色变化造成的。尽管该算法的第一步是去除噪声,但并非所有噪声都被去除,这是因为选择 5x5 高斯滤波器是一种折中处理。过滤器去除了大部分明显的噪声,但不会去除太多。这就是双重阈值发挥作用的地方。

我们首先选择两个阈值:最小值和最大值。这就是我们所谓的双阈值。接下来,我们将每个边缘的强度梯度与两个阈值进行比较,如果边缘的强度梯度大于最大阈值,则将其标记为强(或确定)边缘;相反,如果边缘的强度梯度小于最小阈值,则将其丢弃。但是,如果边缘的强度梯度介于最小和最大阈值之间,则将其标记为弱边缘。

请参考下图:

阈值区域图

绿色区域是强度梯度高于最大阈值的地方,这意味着该区域内的任何边缘都被归类为强边缘。类似地,可以在蓝色区域内找到弱边缘,因为该区域位于我们的两个阈值之间。红色区域代表梯度低于我们的最小阈值的边缘,因此,该区域内的任何边缘都将被丢弃。

滞后边缘跟踪

到目前为止,我们已经确定了两种类型的边缘:弱边和强弱。我们知道强边缘是我们选择最大阈值的最终结果的一部分,但是,我们不太确定如何处理弱边缘。Canny 边缘算法使用假设来简化事情,它假设连接到强边的弱边本身就是强边,同样,未连接到强边缘的弱边缘是噪声或颜色变化。在阈值化的上下文中,这就是滞后的含义。

现在,让我们在第 4 步的图表中添加两条曲线,每条曲线代表一条边的梯度值。

添加了渐变曲线的阈值区域图

由线段 A 和 C 组成的顶部曲线穿过绿色和蓝色区域,我们知道绿色区域的边缘强,蓝色区域的边缘弱。因此,段A是强边缘,段C是弱边缘。通过应用滞后边缘跟踪,我们将 C 标记为强边缘,因为它连接到 A。

现在让我们来看底部曲线,该曲线由段 B 和 D 组成。由于 B 低于最小阈值,它应该已经被抑制了。然而,D 是一个弱边缘,这意味着它需要进行判断。通过使用滞后边缘跟踪,我们可以看到 D 没有连接到任何通过绿色区域的线段,这意味着它没有连接到任何强边,因此它被丢弃。

这很好,但是算法如何准确地知道弱边是否连接到强边?Canny 边缘算法通过考虑每个弱边缘像素及其周围的 8 个相邻像素来确定这一点。如果其相邻像素中的任何一个是强边缘的一部分,则认为它连接到强边缘。因此,该像素保留在我们的最终结果中。相反,如果相邻像素都不是强边缘,则假定它不是强边缘的一部分,因此被抑制。

把它们绑在一起

对我们来说非常容易的是,我们实际上不需要执行任何这些步骤来生成我们的 Canny 边,OpenCV 将它们捆绑到一个名为 Canny() 的函数中。

通过编写以下代码,我们可以很容易地在图像上调用此函数:

# finally, generate canny edges# extreme examples: high threshold [900, 1000]; low threshold [1, 10]img_edges = cv.Canny(img, 50, 100)

经过一些实验,我们分别选择50和100作为我们的低阈值和高阈值。但是,我们还可以尝试不同的方法,也许会发现其他阈值会产生更好的结果!

我们最后的 Canny 边缘

参考文献:

  • https://en.wikipedia.org/wiki/Canny_edge_detector

  • https://docs.opencv.org/master/da/d22/tutorial_py_canny.html

  • https://scikit-image.org/docs/dev/auto_examples/filters/plot_hysteresis.html

  • https://unsplash.com/photos/Ow-MNAWRBW4

Github代码连接:

https://github.com/SeanDuttonJones/opencv-canny-edge

下载1:OpenCV-Contrib扩展模块中文版教程
(0)

相关推荐

  • 利用边缘检测计算物体面积(内含源码)

    在农业中,通常希望获取不同土地的面积.虽然获取这些土地的面积操作相对容易,但是却涉及高额的费用.另外,如果对于不规则形状的土地,测量土地面积的大小就变得相对困难. 幸运的是,有大量以卫星图像的形式公开 ...

  • 图像处理知多少?准大厂算法工程师30+场秋招后总结的面经问题详解

    作者丨灯会 来源丨极市平台 编辑丨极市平台 极市导读 本篇主要包含了图像滤波.边缘检测相关常考内容等相关面试经验. >>加入极市CV技术交流群,走在计算机视觉的最前沿 系列文章: 深度学习 ...

  • 【OpenCV读取标记点坐标】管道测速

    文章目录 一.项目简介 二.思考步骤 1. 图像二值化 2. 滤波去噪 3. Canny算法检测边缘 4. 查找轮廓并计算 5. 绘制轮廓并表示质心 三.测试结果 四.工程代码 一.项目简介 昨天一个 ...

  • 二值化处理与边缘检测

    问题:我在提取图像边缘的时候,首先对图像进行灰度变换,之后进行二值处理,最后进行边缘检测得到边缘图像. 但是在查阅资料的过程中我经常发现很多人忽略二值化的步骤,直接进行边缘检测:还有很多人在实现某些功 ...

  • 什么是 Canny 边缘检测算法?

    重磅干货,第一时间送达 一.简介 Canny 边缘检测器是一种多步算法,用于检测任何输入图像的边缘.它涉及在检测图像边缘时要遵循的以下步骤. 1. 使用高斯滤波器去除输入图像中的噪声. 2.计算高斯滤 ...

  • opencv python实现图像匹配

    '''基于FLANN的匹配器(FLANN based Matcher)1.FLANN代表近似最近邻居的快速库.它代表一组经过优化的算法,用于大数据集中的快速最近邻搜索以及高维特征.2.对于大型数据集, ...

  • 【从零学习OpenCV 4】Canny算法

    小白学视觉",选择"星标"公众号 重磅干货,第一时间送达 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍<OpenCV 4开发详解>.为 ...

  • 使用OpenCV Python进行人脸识别

    先决条件 对图像分类的基本理解 Python 和深度学习知识 对深度学习中各种模块的概念理解 介绍 在这篇文章中,我们将看看什么是人脸识别?以及它与人脸检测有何不同? 我们先简单了解一下人脸识别的原理 ...

  • opencv python智能车道检测,助力无人驾驶

    近年来,基于人工智能的车道检测算法得到了广泛的研究.与传统的基于特征的方法相比,许多方法表现出了优越的性能.然而,当使用具有挑战性的图像时,其准确率通常仍在低80%或高90%之间,甚至更低. 准确可靠 ...

  • 使用Python OpenCV实现姿态估计

    什么是OpenCV? 计算机视觉是一个能够理解图像和视频如何存储和操作的过程,它还有助于从图像或视频中检索数据.计算机视觉是人工智能的一部分. 计算机视觉在自动驾驶汽车,物体检测,机器人技术,物体跟踪 ...

  • 在OpenCV中基于深度学习的边缘检测

    重磅干货,第一时间送达 本文转自:AI算法与图像处理 导读 分析了Canny的优劣,并给出了OpenCV使用深度学习做边缘检测的流程,文末有代码链接. 在这篇文章中,我们将学习如何在OpenCV中使用 ...

  • opencv和Python有什么不同?基础分析!

    Python不用过多的介绍,大家都比较了解它,它是一门高级的.面向对象的编程语言,那么它与opencv有什么不同呢?它们之间的区别是什么?我想很多人对它们都有所好奇吧,接下来我们一起来了解一下. 首先 ...

  • 对于Python的视觉设计还没整明白?这本书带给你想要的一切-OpenCV官方教程中文版(For Python)【PDF电子书】

    对于Python的视觉设计还没整明白?这本书带给你想要的一切-OpenCV官方教程中文版(For Python)【PDF电子书】