如何利用Python 进行边缘检测

为何检测边缘?

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

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

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

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

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

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

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

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

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

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

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

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

可以看到,我们得到了与前文相似的结果,相加之后得到的结果是 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 边缘检测内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2020-10-12

python Canny边缘检测算法的实现

图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波.我们知道微分运算是求信号的变化率,具有加强高频分量的作用.在空域运算中来说,对图像的锐化就是计算微分.对于数字图像的离散信号,微分运算就变成计算差分或梯度.图像处理中有多种边缘检测(梯度)算子,常用的包括普通一阶差分,Robert算子(交叉差分),Sobel算子等等,是基于寻找梯度强度.拉普拉斯算子(二阶差分)是基于过零点检测.通过计算梯度,设置阀值,得到边缘图像. Canny边缘检测算子是一种多级检测算法.1986年由J

python实现canny边缘检测

canny边缘检测原理 canny边缘检测共有5部分组成,下边我会分别来介绍. 1 高斯模糊(略) 2 计算梯度幅值和方向. 可选用的模板:soble算子.Prewitt算子.Roberts模板等等; 一般采用soble算子,OpenCV也是如此,利用soble水平和垂直算子与输入图像卷积计算dx.dy: 进一步可以得到图像梯度的幅值: 为了简化计算,幅值也可以作如下近似: 角度为: 如下图表示了中心点的梯度向量.方位角以及边缘方向(任一点的边缘与梯度向量正交) : θ = θm = arcta

使用OpenCV-python3实现滑动条更新图像的Canny边缘检测功能

import cv2 from matplotlib import pyplot as plt import numpy as np img= cv2.imread('39.jpg')#加载图片 cv2.namedWindow('Canny edge detect')#设置窗口,cv2.WINDOW_NORMAL表示窗口大小可自动调节 cv2.namedWindow('Original Image',cv2.WINDOW_NORMAL) cv2.namedWindow('Canny edgeIm

python opencv实现图像边缘检测

本文利用python opencv进行图像的边缘检测,一般要经过如下几个步骤: 1.去噪 如cv2.GaussianBlur()等函数: 2.计算图像梯度 图像梯度表达的是各个像素点之间,像素值大小的变化幅度大小,变化较大,则可以认为是出于边缘位置,最多可简化为如下形式: 3.非极大值抑制 在获得梯度的方向和大小之后,应该对整幅图像做一个扫描,去除那些非边界上的点.对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的.如下图所示: 4.滞后阈值 现在要确定那些边界才是真正的

Python Opencv实现图像轮廓识别功能

本文实例为大家分享了python opencv识别图像轮廓的具体代码,供大家参考,具体内容如下 要求:用矩形或者圆形框住图片中的云朵(不要求全部框出) 轮廓检测 Opencv-Python接口中使用cv2.findContours()函数来查找检测物体的轮廓. import cv2 img = cv2.imread('cloud.jpg') # 灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.th

python opencv对图像进行旋转且不裁剪图片的实现方法

最近在做深度学习时需要用到图像处理相关的操作,在度娘上找到的图片旋转方法千篇一律,旋转完成的图片都不是原始大小,很苦恼,于是google到歪果仁的网站扒拉了一个方法,亲测好用,再次嫌弃天下文章一大抄的现象,虽然我也是抄歪果仁的. 废话不多说了,直接贴代码了. def rotate_bound(image, angle): # grab the dimensions of the image and then determine the # center (h, w) = image.shape[

Python+OpenCV实现图像融合的原理及代码

根据导师作业安排,在学习数字图像处理(刚萨雷斯版)第六章 彩色图像处理 中的彩色模型后,导师安排了一个比较有趣的作业: 融合原理为: 1 注意:遥感原RGB图image和灰度图Grayimage为测试用的输入图像: 2 步骤:(1)将RGB转换为HSV空间(H:色调,S:饱和度,V:明度): (2)用Gray图像诶换掉HSV中的V: (3)替换后的HSV转换回RGB空间即可得到结果. 书上只介绍了HSI彩色模型,并没有说到HSV,所以需要网上查找资料. Python代码如下: import cv

Python OpenCV处理图像之滤镜和图像运算

本文实例为大家分享了Python OpenCV处理图像之滤镜和图像运算的具体代码,供大家参考,具体内容如下 0x01. 滤镜 喜欢自拍的人肯定都知道滤镜了,下面代码尝试使用一些简单的滤镜,包括图片的平滑处理.灰度化.二值化等: import cv2.cv as cv image=cv.LoadImage('img/lena.jpg', cv.CV_LOAD_IMAGE_COLOR) #Load the image cv.ShowImage("Original", image) grey

python opencv判断图像是否为空的实例

如下所示: import cv2 im = cv2.imread('2.jpg') if im is None: print("图像为空") # cv2.imshow("ss", im) # cv2.waitKey(0) 以上这篇python opencv判断图像是否为空的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

python Opencv计算图像相似度过程解析

这篇文章主要介绍了python Opencv计算图像相似度过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.相关概念 一般我们人区分谁是谁,给物品分类,都是通过各种特征去辨别的,比如黑长直.大白腿.樱桃唇.瓜子脸.王麻子脸上有麻子,隔壁老王和儿子很像,但是儿子下巴涨了一颗痣和他妈一模一样,让你确定这是你儿子. 还有其他物品.什么桌子带腿.镜子反光能在里面倒影出东西,各种各样的特征,我们通过学习.归纳,自然而然能够很快识别分类出新物品.

Python+OpenCV实现图像的全景拼接

本文实例为大家分享了Python+OpenCV实现图像的全景拼接的具体代码,供大家参考,具体内容如下 环境:python3.5.2 + openCV3.4 1.算法目的 将两张相同场景的场景图片进行全景拼接. 2.算法步骤 本算法基本步骤有以下几步: 步骤1:将图形先进行桶形矫正 没有进行桶形变换的图片效果可能会像以下这样: 图片越多拼接可能就会越夸张. 本算法是将图片进行桶形矫正.目的就是来缩减透视变换(Homography)之后图片产生的变形,从而使拼接图片变得畸形. 步骤2:特征点匹配 本

Python OpenCV处理图像之图像像素点操作

本文实例为大家分享了Python OpenCV图像像素点操作的具体代码,供大家参考,具体内容如下 0x01. 像素 有两种直接操作图片像素点的方法: 第一种办法就是将一张图片看成一个多维的list,例如对于一张图片im,想要操作第四行第四列的像素点就直接 im[3,3] 就可以获取到这个点的RGB值. 第二种就是使用 OpenCV 提供的 Get1D. Get2D 等函数. 推荐使用第一种办法吧,毕竟简单. 0x02. 获取行和列像素 有一下四个函数: cv.GetCol(im, 0): 返回第

Python OpenCV处理图像之图像直方图和反向投影

本文实例为大家分享了Python OpenCV图像直方图和反向投影的具体代码,供大家参考,具体内容如下 当我们想比较两张图片相似度的时候,可以使用这一节提到的技术 直方图对比 反向投影 关于这两种技术的原理可以参考我上面贴的链接,下面是示例的代码: 0x01. 绘制直方图 import cv2.cv as cv def drawGraph(ar,im, size): #Draw the histogram on the image minV, maxV, minloc, maxloc = cv.