如何利用Python 进行边缘检测


Posted in Python onOctober 14, 2020

为何检测边缘?

我们首先应该了解的问题是:“为什么要费尽心思去做边缘检测?”除了它的效果很酷外,为什么边缘检测还是一种实用的技术?为了更好地解答这个问题,请仔细思考并对比下面的风车图片和它的“仅含边缘的图”:

如何利用Python 进行边缘检测

可以看到,左边的原始图像有着各种各样的色彩、阴影,而右边的“仅含边缘的图”是黑白的。如果有人问,哪一张图片需要更多的存储空间,你肯定会告诉他原始图像会占用更多空间。这就是边缘检测的意义:通过对图片进行边缘检测,丢弃大多数的细节,从而得到“更轻量化”的图片。

因此,在无须保存图像的所有复杂细节,而 “只关心图像的整体形状” 的情况下,边缘检测会非常有用。

如何进行边缘检测 —— 数学

在讨论代码实现前,让我们先快速浏览一下边缘检测背后的数学原理。作为人类,我们非常擅长识别图像中的“边”,那如何让计算机做到同样的事呢?

首先,假设有一张很简单的图片,在白色背景上有一个黑色的正方形:

如何利用Python 进行边缘检测

在这个例子中,由于处理的是黑白图片,因此我们可以考虑将图中的每个像素的值都用 0(黑色) 或 1(白色) 来表示。除了黑白图片,同样的理论也完全适用于彩色图像。

现在,我们需要判断上图中绿色高亮的像素是不是这个图像边缘的一部分。作为人类,我们当然可以认出它是图像的边缘;但如何让计算机利用相邻的像素来得到同样的结果呢?

我们以绿色高亮的像素为中心,设定一个 3 x 3 像素大小的小框,在图中以红色示意。接着,对这个小方框“应用”一个过滤器(filter):

如何利用Python 进行边缘检测

上图展示了我们将要“应用”的过滤器。乍一看上去很神秘,让我们仔细研究它做的事情:当我们说 “将过滤器应用于一小块局部像素块” 时,具体是指红色框中的每个像素与过滤器中与之位置对应的像素进行相乘。因此,红色框中左上角像素值为 1,而过滤器中左上角像素值为 -1,它们相乘得到 -1,这也就是结果图中左上角像素显示的值。结果图中的每个像素都是用这种方式得到的。

下一步是对过滤结果中的所有像素值求和,得到 -4。请注意,-4 其实是我们应用这个过滤器可获得的“最小”值(因为原始图片中的像素值只能在 0 到 1 之间)。因此,当获得 -4 这个最小值的时候,我们就能知道,对应的像素点是图像中正方形顶部竖直方向边缘的一部分。

为了更好地掌握这种变换,我们可以看看将此过滤器应用于图中正方形底边上的一个像素会发生什么:

如何利用Python 进行边缘检测

可以看到,我们得到了与前文相似的结果,相加之后得到的结果是 4,这是应用此过滤器能得到的最大值。因此,由于我们得到了 4 这一最大值,可以知道这个像素是图像中正方形底部竖直方向边缘的一部分。

为了把这些值映射到 0-1 的范围内,我们可以简单地给其加上 4 再除以 8,这样就能把 -4 映射成 0(黑色),把 4 映射成 1(白色)。因此,我们将这种过滤器称为纵向 Sobel 过滤器,可以用它轻松检测图像中垂直方向的边缘。

那如何检测水平方向的边缘呢?只需简单地将纵向过滤器进行转置(按照其数值矩阵的对角线进行翻转)就能得到一个新的过滤器,可以用于检测水平方向的边缘。

如果需要同时检测水平方向、垂直方向以及介于两者之间的边缘,我们可以把纵向过滤器得分和横向过滤器得分进行结合,这个步骤在后面的代码中将有所体现。

希望上文已经讲清楚了这些理论!下面看一看代码是如何实现的。

如何进行边缘检测 —— 代码

首先进行一些设置:

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
# 定义纵向过滤器
vertical_filter = [[-1,-2,-1], [0,0,0], [1,2,1]]
# 定义横向过滤器
horizontal_filter = [[-1,0,1], [-2,0,2], [-1,0,1]]

# 读取纸风车的示例图片“pinwheel.jpg”
img = plt.imread('pinwheel.jpg')

# 得到图片的维数
n,m,d = img.shape

# 初始化边缘图像
edges_img = img.copy()

你可以把代码中的“pinwheel.jpg”替换成其它你想要找出边缘的图片文件!需要确保此文件和代码在同一工作目录中。

接着编写边缘检测代码本身:

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
# 定义纵向过滤器
vertical_filter = [[-1,-2,-1], [0,0,0], [1,2,1]]
# 定义横向过滤器
horizontal_filter = [[-1,0,1], [-2,0,2], [-1,0,1]]
# 读取纸风车的示例图片“pinwheel.jpg”
img = plt.imread('pinwheel.jpg')
# 得到图片的维数
n,m,d = img.shape
# 初始化边缘图像
edges_img = img.copy()
# 循环遍历图片的全部像素
for row in range(3, n-2):
for col in range(3, m-2):

# 在当前位置创建一个 3x3 的小方框
local_pixels = img[row-1:row+2, col-1:col+2, 0]

# 应用纵向过滤器
vertical_transformed_pixels = vertical_filter*local_pixels
# 计算纵向边缘得分
vertical_score = vertical_transformed_pixels.sum()/4

# 应用横向过滤器
horizontal_transformed_pixels = horizontal_filter*local_pixels
# 计算横向边缘得分
horizontal_score = horizontal_transformed_pixels.sum()/4

# 将纵向得分与横向得分结合,得到此像素总的边缘得分
edge_score = (vertical_score**2 + horizontal_score**2)**.5

# 将边缘得分插入边缘图像中
edges_img[row, col] = [edge_score]*3
# 对边缘图像中的得分值归一化,防止得分超出 0-1 的范围
edges_img = edges_img/edges_img.max()

有几点需要注意:

在图片的边界像素上,我们无法创建完整的 3 x 3 小方框,因此在图片的四周会有一个细边框。

既然是同时检测水平方向和垂直方向的边缘,我们可以直接将原始的纵向得分与横向得分分别除以 4(而不像前文描述的分别加 4 再除以 8)。这个改动无伤大雅,反而可以更好地突出图像的边缘。

将纵向得分与横向得分结合起来时,有可能会导致最终的边缘得分超出 0-1 的范围,因此最后还需要重新对最终得分进行标准化。

在更复杂的图片上运行上述代码:

如何利用Python 进行边缘检测

得到边缘检测的结果:

如何利用Python 进行边缘检测

以上就是本文的全部内容了!希望你了解到了一点新知识

到此这篇关于如何利用Python 进行边缘检测的文章就介绍到这了,更多相关python 边缘检测内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python使用xauth方式登录饭否网然后发消息
Apr 11 Python
Python中使用 Selenium 实现网页截图实例
Jul 18 Python
python服务器端收发请求的实现代码
Sep 29 Python
python轻松查到删除自己的微信好友
Jan 10 Python
python 把数据 json格式输出的实例代码
Oct 31 Python
python select.select模块通信全过程解析
Sep 20 Python
Python实现扩展内置类型的方法分析
Oct 16 Python
Python将图片转换为字符画的方法
Jun 16 Python
pycharm: 恢复(reset) 误删文件的方法
Oct 22 Python
Python实现将多个空格换为一个空格.md的方法
Dec 20 Python
Django使用redis缓存服务器的实现代码示例
Apr 28 Python
python析构函数用法及注意事项
Jun 22 Python
python从Oracle读取数据生成图表
Oct 14 #Python
python获取linux系统信息的三种方法
Oct 14 #Python
Python通过队列来实现进程间通信的示例
Oct 14 #Python
python利用xlsxwriter模块 操作 Excel
Oct 14 #Python
如何解决python多种版本冲突问题
Oct 13 #Python
Django配置Bootstrap, js实现过程详解
Oct 13 #Python
Python文件操作及内置函数flush原理解析
Oct 13 #Python
You might like
php懒人函数 自动添加数据
2011/06/28 PHP
如何使用FireFox插件FirePHP调试PHP
2013/07/23 PHP
phpmailer在服务器上不能正常发送邮件的解决办法
2014/07/08 PHP
Sublime里直接运行PHP配置方法
2014/11/28 PHP
php实现CSV文件导入和导出
2015/10/24 PHP
CI框架(ajax分页,全选,反选,不选,批量删除)完整代码详解
2016/11/01 PHP
PHP中include和require的区别实例分析
2017/05/07 PHP
laravel 如何实现引入自己的函数或类库
2019/10/15 PHP
JavaScript延迟加载
2021/03/09 Javascript
ExtJs Excel导出并下载IIS服务器端遇到的问题
2011/09/16 Javascript
IE下使用cloneNode注意事项分享
2012/11/22 Javascript
表单的焦点顺序tabindex和对应enter键提交
2013/01/04 Javascript
fixedBox固定div漂浮代码支持ie6以上大部分主流浏览器
2014/06/26 Javascript
JS实现在页面随时自定义背景颜色的方法
2015/02/27 Javascript
JQuery中DOM事件绑定用法详解
2015/06/13 Javascript
javascript省市区三级联动下拉框菜单实例演示
2015/11/29 Javascript
图文详解JavaScript的原型对象及原型链
2016/08/02 Javascript
react.js 获取真实的DOM节点实例(必看)
2017/04/17 Javascript
Vue form 表单提交+ajax异步请求+分页效果
2017/04/22 Javascript
Angular移动端页面input无法输入的解决方法
2017/11/14 Javascript
微信小程序遍历Echarts图表实现多个饼图
2019/04/25 Javascript
vue视图不更新情况详解
2019/05/16 Javascript
Vue的自定义组件不能使用click方法的解决
2020/07/28 Javascript
Django admin美化插件suit使用示例
2017/12/12 Python
对django中render()与render_to_response()的区别详解
2018/10/16 Python
Pycharm如何打断点的方法步骤
2019/06/13 Python
python正则表达式匹配IP代码实例
2019/12/28 Python
基于Python生成个性二维码过程详解
2020/03/05 Python
Django前后端分离csrf token获取方式
2020/12/25 Python
One.com挪威:北欧成长最快的网络托管公司
2016/11/19 全球购物
Under Armour西班牙官网:美国知名的高端功能性运动品牌
2018/12/12 全球购物
环境保护标语
2014/06/20 职场文书
国际商务专业毕业生自我鉴定2014
2014/09/27 职场文书
教师党员自我剖析材料
2014/09/29 职场文书
物业保洁员管理制度
2015/08/05 职场文书
孕妇病假条怎么写
2015/08/17 职场文书