【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)


本文免费源代码点击链接即可进入下载页面。


对资源的补充说明:为保证代码能够正常运行,下载的压缩包中自带标准Lena png图像。该算法无法对任意大小、任意格式的图片进行边缘检测。推荐使用尺寸较小的png图像。

为防止环境的不同导致代码无法运行,现将本机环境说明如下:

开发工具:JetBrains PyCharm 2018.3.5 x64

python版本:Python3.7
在这里插入图片描述

所需导入包:( 如果不知如何下载,请自行百度 )
【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第1张图片
经过测试,在没有任何包的情况下,只需安装Pillow、matplotlib、opencv-python(无需考虑版本)即可。如果程序仍无法运行,可能仍有遗漏,请自行查阅。

在做好所有准备后,直接运行即可。

(经笔者反复测试,在本机上100%可运行。如有无法运行情况,麻烦各位自行解决)


对文章内容的说明:感谢您点击进入本文章,笔者所编写的SUSAN算法已经实现了基础效果。在学习SUSAN算法的过程中参考了很多文章,由于SUSAN算法已经比较成熟,在这里就不列举出参考文献了。代码也许实现的比较繁琐,文章的内容也许也有错误,专业名词说的也可能有误,但希望文章的内容能够为您提供帮助。

PS:SUSAN算法不仅能检测出边缘,也能检测出角点。但本文的SUSAN算法主要是针对边缘进行检测,并展现结果。(文章中不含角点检测内容)。


最终运行结果:

代码运行过程耗时较久,请耐心等待。最终会展示两个图,一个是SUSAN算法的边缘检测结果,另一个是采用非极大值抑制的方法对SUSAN算法进行改进的边缘检测结果。
【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第2张图片


Python实现SUSAN算法 + 非极大值抑制改进

  • 前言
  • SUSAN算法的实现原理及其代码实现
    • USAN原理
    • SUSAN边缘检测算法
  • 非极大值抑制的实现原理及其代码实现
    • 问题分析
    • 非极大值抑制的原理


前言

本题目为笔者的毕设题目,且选择使用 Python 来实现SUSAN算法。

在学习研究的过程中发现,网络中大多数都是使用OpenCV、Matlab去实现SUSAN算法,鲜有用Python来实现的,而且大多数都为SUSAN的角点检测。其中,对SUSAN算法原理的描述文章数不胜数,但对其具体的实现代码鲜有文章能够给出解答。为了能对自己这段时间以来对SUSAN算法的了解进行表述,为此,笔者经过总结写下该篇文章,并根据原理以及查阅资料,编写了基于Python的SUSAN边缘检测代码,希望能够给您提供一些帮助。

考虑到查重问题,本文内容将不会对SUSAN算法的基本原理进行过多阐述。


SUSAN算法的实现原理及其代码实现


USAN原理

SUSAN算子与其它经典的边缘检测算子不同,它是一个圆形模板。如下图所示。该圆形模板一定会有一个中心像素(圆心)。在这个圆形模板中,如果圆形模板内其它像素与中心像素的灰度值的差值在一定范围内,那么即认定该其它像素与中心像素的灰度差相似。最终对圆形模板内每个像素的灰度值进行判定,便得到了相似的像素数的总和。这个总和便是USAN区域的面积值。而在SUSAN算法中用来判断边缘的依据是根据USAN区域的面积值。从图中可以发现,当圆形模板处在边缘时,其USAN区域面积值会小于圆形模板面积的一半。

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第3张图片
比如:在经典的直线型边缘时,USAN值为模板面积一半;
在这里插入图片描述

在凸的角点处时,USAN值为模板面积四分之一;
在这里插入图片描述

在凹的角点处时,USAN值为模板面积四分之三,该图中未展现该圆形模板。虽然这么看来其值已经不满足判定条件,但是反过来看白色区域,其值为四分之一,所以最终不会影响边缘检测效果。

在这里插入图片描述

综上所述,USAN 区域的面积值可以用来检测边缘,SUSAN 算法就应用了这个原理。因此,SUSAN算法中最明显的就是不需要计算微分,所以它的一个优势就是对噪声不是很敏感。


SUSAN边缘检测算法

(源码在文章开头已经给出)

根据上述原理,现在考虑将其实现到代码上。

首先对于圆形模板,由于在代码里显然无法准确描绘出圆形,因此应用USAN原理的圆形SUSAN算子只能使用二维数组近似表示。具体如下。

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第4张图片
在代码中就是这样:

# 利用二维数组,近似创建出包含37个像素的 SUSAN 圆形模板。
m = [
[0, 0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 1, 1, 0],
[1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1],
[0, 1, 1, 1, 1, 1, 0],
[0, 0, 1, 1, 1, 0, 0]
]
# 模板中包含像素的个数
count = 37

除此以外,为了判定圆形模板内灰度值的差异,我们还需要把图片转成灰度图。

# 打开图片
oimg = Image.open("pic.png")
# 将图片转换为灰度图
img2 = oimg.convert('L')
# 将图片中每个像素的灰度信息保存成二维数组
pixels2 = img2.load()

准备工作结束。在边缘检测中,SUSAN算法的具体步骤如下:


(1)比较像素灰度值

在算法中,将会用到如下公式:

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第5张图片
在先前的原理中已经说到,我们要做的就是比对像素点的灰度差值。现在的问题就是灰度差值应该小于一个什么值,从而判定模板核和其他非模板核像素点的灰度值相似。这里的T 是自己设定的一个灰度差阈值。当灰度差值满足条件,即记为1。最终对圆形模板内每个像素进行求和处理,便得到了USAN区域面积。

灰度差阈值 T 是个极其关键的数值,因为该值将会直接决定对 USAN 区域面积的判定,从而影响对边缘的检测效果。而灰度差阈值在目前来看,确实无法设定为一个固定值,因为目前图片五花八门,背景、色差各不相同。如果设定值过大,那么边缘检测效果肯定不好;如果设定值过小,那么可能会遗漏很多边缘。


(2)边缘响应公式

在先前的原理中已经提到过,由于边缘或角点的USAN区域面积值相比于其他像素点是个较小的值,且在实际图像中,背景和目标可能会比较复杂,整体外部轮廓可能会比较模糊,也可能会受到噪声的干扰,因此为了凸显出边缘的检测效果,算法设定了一个固定的几何阈值 G。该阈值通常会在 3Smax/4 时得到最优的噪声消除性能,其中 Smax 是所选用模板面积的最大值。因此,初始的边缘响应将会根据下式得到:

在这里插入图片描述

代码效果:

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第6张图片


其实SUSAN算法整体内容比较简单,但是 SUSAN 算法还有一些可以改进的内容。在本文中将只考虑采用非极大值抑制对 SUSAN 算法进行改进。


非极大值抑制的实现原理及其代码实现


问题分析

首先先来表述一下为什么要使用非极大值抑制,非极大值抑制解决了一个什么问题。

比如在边缘检测时,遇到经典的直线型边缘时,会出现如下图所示的情况:

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第7张图片
即边缘两侧所求得的 USAN 区域面积值都是相同的。正因为如此,最终检测结果相比于其它经典边缘检测算法,其整体图像所检测到的边缘像素会比较多(粗)。

非极大值抑制的方法就可以用来解决这个问题。


非极大值抑制的原理

非极大值抑制的步骤如下:

(1)如果要找到这个冗余的边缘点,我们就需要知道该边缘的梯度方向。换句话说,通过寻找边缘区域最长的对称轴就可以发现边缘的梯度方向。这个概念举个简单例子:

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第8张图片

在该像素点上,边缘区域最长的对称轴一定是如图所示的红线。只要能找到这个方向,那么在该像素点的冗余边缘点就可以被去除。

因此,先看一下使用到的的公式:

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第9张图片

公式中,(x0,y0) 是核在图像中的位置坐标;(x,y) 是模板 M(x,y) 中的其它位置;C(x0,y0;x,y) 是 SUSAN 算法的公式中所求出的比较结果;S(x0,y0) 是通过公式所求出的 USAN 区域面积;Fx (x0,y0) 和 Fy (x0,y0) 分别是沿着 x 或 y 方向所求得的灰度差均值。


(2)根据上述公式所求出的灰度差均值就可以通过下面的公式计算出边缘的方向角 θ。
在这里插入图片描述

我们可以依然选择上面的图,来对该公式的使用进行一个简例说明,证明其可行性。

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第10张图片

首先对于比较结果 C,根据先前公式和代码,当灰度值相似时为 1,否则为 0。

def c(r, r0):
	global t
	if (abs(r - r0) > t):
		return 0
	else:
		return 1

此时使用本节的灰度差均值公式,我们就只需要注意那些灰度值相似(结果为 1)的像素点。

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第11张图片

由于处在该位置的圆形模板上,目标(灰色区域)在 x 方向上对称,所以 x 方向上经过公式得到的求和结果必定是 0 (左右两侧像素点 x 坐标和中心像素点的差值,必定带正负,经过求和即为 0),y 方向上将是灰度差均值。此时使用 arctan 去计算其方向角,那么结果为负无穷大的角,就可近似看作 -90°。成功找到了边缘梯度方向。

(公式虽然未加绝对值,得到的角可能有正有负,但是后续公式中将不会受到其影响)


(3)获得了方向角后,就可以实现对图像的非极大值抑制。沿着该方向取得临近该模板中心的前后两个像素点。如果这个中心像素点处在边缘上,那么该像素点的边缘响应值一定是沿该方向的局部极值。换句话说,若中心像素点的边缘响应值不大于其他两个像素点的边缘响应值,则将该像素点的边缘响应值置零。否则,这就是一个局部最大值,将该像素点的边缘响应值保留下来。

再以该图为例:

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第12张图片

注意:右图中的数字是以对应像素点为中心时,所求得的 USAN 区域面积。USAN 区域通常情况下面积越小,越可能是边缘(角点)像素点(噪声点除外)。之前在 SUSAN 中已经提到过,我们使用了边缘响应公式对 USAN 区域面积进行了处理。所以,最后 USAN 区域面积较小的边缘位置,显然处理后会是一个局部极值。

对着该图去验证其可行性,由于冗余边缘点位置(画红圈位置)的两个像素点值相同,不满足上述基本思路的条件,所以会将其中的一点置零。其中的一点置零后,另一个点显然就成了局部极值点,从而被保留了下来。最终实现了剔除冗余点的功能。


(4)该思路中最困难的点是在数字图像中该如何确定前后两个像素点的坐标。因为在多数情况下,即使得到了方向角,最终得到的像素点坐标也大概率包含小数。最终二维数组该选取哪些像素点就成了问题。如下图所示。

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第13张图片
本文选择使用以下公式来近似求得该中心像素前后两个临近像素点的整数坐标。(公式中不是绝对值,而是向上取整)(非官方解决方案,请勿盲目使用)

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第14张图片

在以上公式中,(x0,y0) 是当前中心像素点的位置坐标;θ 就是通过公式所求得的边缘方向角。在近似获取到位置坐标后,比较这三个像素点通过公式所求得的边缘响应值。若中心像素点的边缘响应值不大于其他两个像素点的边缘响应值,则将该像素点的响应值置零。否则就将该像素点保留下来。通过以上步骤就可实现非极大值抑制,除去非最大的边缘值,剔除冗余边缘点。


看一下比对效果:

【边缘检测】Python实现SUSAN算法及使用非极大值抑制进行改进(含免费可用源代码)_第15张图片
通过比较图像可以发现改进后的图像的边缘更加细化,实现了使用该方法所预估的效果。


本文的源代码在文章顶部直接给出。希望本文可以给您提供帮助。

你可能感兴趣的:(Python)