一、什么是Canny边缘检测算法?

  Canny边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。更为重要的是 Canny 创立了边缘检测计算理论(Computational theory of edge detection)解释这项技术如何工作。
  通常情况下边缘检测的目的是在保留原有图像属性的情况下,显著减少图像的数据规模。目前有多种算法可以进行边缘检测,虽然Canny算法年代久远,但可以说它是边缘检测的一种标准算法,而且仍在研究中广泛使用。其效果如下图所示:
在这里插入图片描述

二、最优边缘准则是什么?

  1. 最优检测:算法能够尽可能多地标识出图像中的实际边缘,漏检真实边缘的概率和误检非边缘的概率都尽可能小;
  2. 最优定位准则:检测到的边缘点的位置距离实际边缘点的位置最近,或者是由于噪声影响引起检测出的边缘偏离物体的真实边缘的程度最小;
  3. 检测点与边缘点一一对应:算子检测的边缘点与实际边缘点应该是一一对应。为了满足这些要求 Canny 使用了变分法(calculus of variations),这是一种寻找优化特定功能的函数的方法。最优检测使用四个指数函数项表示,但是它非常近似于高斯函数的一阶导数

三、Canny算法实现步骤

  1. 应用高斯滤波来平滑图像,目的是去除噪声;
  2. 计算图像的强度梯度(intensity gradients);
  3. 应用非最大抑制(non-maximum suppression)技术来消除边误检(本来不是但检测出来是);
  4. 应用双阈值的方法来决定可能的(潜在的)边界;
  5. 利用滞后技术来跟踪边界。

具体的实现细节可以查看该链接

四、Canny算法在使用中的问题?

  Canny算法的检测效果很好,得到了广泛的应用。它经常出现在一些算法的预处理阶段,除此之外,很多计算机视觉库中都集成了Canny算,代表性的包括Opencv,cv2.canny(image, lower, upper)是Opencv中的Canny算法的调用接口。**但是大家在调用的过程中都会遇到一个难题-lower和upper参数如何来设置呢?**很多人采取的方法是减少范围不断的去尝试直到找到一个合适的阈值,但是这种方法费时费力,而且鲁棒性较差。**你经常会发现,这个参数适用于这张图片但是当你输入另外一张图片时效果就不好啦!**本文的主要目的就是来解决这个问题的!

五、无参数、自动化Canny算法代码实现

# -*- coding: utf-8 -*-
# 导入一些python包
import numpy as np
import argparse
import glob
import cv2
import os

# 定义auto_canny函数
def auto_canny(image, sigma=0.33):
	# 计算单通道像素强度的中位数
	v = np.median(image)

	# 选择合适的lower和upper值,然后应用它们
	lower = int(max(0, (1.0 - sigma) * v))
	upper = int(min(255, (1.0 + sigma) * v))
	edged = cv2.Canny(image, lower, upper)

	return edged

# 设置一些需要修改的参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--images", required=True, help="path to input dataset of images")
args = vars(ap.parse_args())

# 创建可视化文件夹
file_dir = "vis/"
if not os.path.isdir(file_dir):
    os.makedirs(file_dir)

# 遍历文件夹中的每一张图片
i = 0
img_names = glob.glob(args["images"] + "/*.jpg")
for imagePath in img_names:
   # 读取图片
   image = cv2.imread(imagePath)
   # 灰度化处理
   gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
   # 进行高斯模糊去噪
   blurred = cv2.GaussianBlur(gray, (3, 3), 0)
   
   # 分别使用宽阈值、窄阈值和自动确定的阈值进行测试
   wide = cv2.Canny(blurred, 10, 200)
   tight = cv2.Canny(blurred, 225, 250)
   auto = auto_canny(blurred)
   result = np.hstack([wide, tight, auto])
   i += 1
   
   save_name = "vis/" + str(i) + ".png"
   # 显示并保存结果
   cv2.imshow("Original", image)
   cv2.imshow("Edges", result)
   cv2.imwrite(save_name, result)
   cv2.waitKey(0)

运行方法- python auto_canny.py --image 测试文件夹名称

六、改进算法效果展示

在这里插入图片描述
  上图展示了该算法在多个测试图片上面的检测效果,第1列表示的是原始的输入图片;第2列表示使用宽阈值后的检测效果;第3列表示使用窄阈值后的检测效果;第4列表示使用自适用阈值后的检测效果。我们可以发现,自动阈值的检测效果在宽阈值和窄阈值之间,整体的效果基本满足我们的要求,但是它带来的好处是我们不在需要进行调参工作,哈哈哈。

七、问题探讨

  其实本文的思路很简单,主要是应用图片中的统计信息,使用这些统计数据来消除手动调整阈值以进行Canny边缘检测。这个技巧可以节省你的时间参数调整-而且在应用这个功能之后你仍然可以得到一个很好的canny边缘图。具体的实现如下所示:

def auto_canny(image, sigma=0.33):
	# 计算单通道像素强度的中位数
	v = np.median(image)

	# 选择合适的lower和upper值,然后应用它们
	lower = int(max(0, (1.0 - sigma) * v))
	upper = int(min(255, (1.0 + sigma) * v))
	edged = cv2.Canny(image, lower, upper)

	return edged

参考资料

1、参考链接1
2、参考链接2

注意事项

[1] 如果您对AI、自动驾驶、AR、ChatGPT等技术感兴趣,欢迎关注我的微信公众号“AI产品汇”,有问题可以在公众号中私聊我!
[2] 该博客是本人原创博客,如果您对该博客感兴趣,想要转载该博客,请与我联系(qq邮箱:1575262785@qq.com),我会在第一时间回复大家,谢谢大家的关注。
[3] 由于个人能力有限,该博客可能存在很多的问题,希望大家能够提出改进意见。
[4] 如果您在阅读本博客时遇到不理解的地方,希望您可以联系我,我会及时的回复您,和您交流想法和意见,谢谢。
[5] 本文测试的图片可以通过关注微信公众号AI产品汇之后找我索取!
[6] 本人业余时间承接各种本科毕设设计和各种小项目,包括图像处理(数据挖掘、机器学习、深度学习等)、matlab仿真、python算法及仿真等,有需要的请加QQ:1575262785详聊!!!

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐