我是一名初学者,如果你发现文中有错误,请留言告诉我,谢谢


如果需要检测到图像里面的边缘,首先我们需要知道边缘处具有什么特征。

对于一幅灰度图像来说,边缘两边的灰度值肯定不相同,这样我们才能分辨出哪里是边缘,哪里不是。

因此,如果我们需要检测一个灰度图像的边缘,我们需要找出哪里的灰度变化最大。显然,灰度变化越大,对比度越强,边缘就越明显。

那么问题来了,我们怎么知道哪里灰度变化大,哪里灰度变化小呢?


导数,梯度,边缘信息

在数学中,与变化率有关的就是导数。

如果灰度图像的像素是连续的(实际不是),那么我们可以分别原图像G对x方向和y方向求导数

获得x方向的导数图像Gx和y方向的导数图像Gy。Gx和Gy分别隐含了x和y方向的灰度变化信息,也就隐含了边缘信息。

如果要在同一图像上包含两个方向的边缘信息,我们可以用到梯度。(梯度是一个向量)

原图像的梯度向量Gxy为(Gx,Gy),梯度向量的大小和方向可以用下面两个式子计算

角度值好像需要根据向量所在象限不同适当+pi或者-pi。

梯度向量大小就包含了x方向和y方向的边缘信息。


图像导数

实际上,图像矩阵是离散的。

连续函数求变化率用的是导数,而离散函数求变化率用的是差分。

差分的概念很容易理解,就是用相邻两个数的差来表示变化率。

下面公式是向后差分

x方向的差分:Gx(n,y) = G(n,y)-G(n-1,y)

y方向的差分:Gy(x,n) = G(x,n)-G(x,n-1)

实际计算图像导数时,我们是通过原图像和一个算子进行卷积来完成的(这种方法是求图像的近似导数)。

最简单的求图像导数的算子是 Prewitt算子 :

x方向的Prewitt算子为

y方向的Prewitt算子为

---------------------------------------------

原图像和一个算子进行卷积的大概过程如下

如果图像矩阵中一块区域为

那么x5处的x方向的导数是,将x方向算子的中心和x5重合,然后对应元素相乘再求和,即

x5处的x方向导数为x3+x6+x9-x1-x4-x7

对矩阵中所有元素进行上述计算,就是卷积的过程。

--------------------------------------------

因此,利用原图像和x方向Prewitt算子进行卷积就可以得到图像的x方向导数矩阵Gx,

利用原图像和y方向Prewitt算子进行卷积就可以得到图像的y方向导数矩阵Gy。

利用公式

就可以得到图像的梯度矩阵Gxy,这个矩阵包含图像x方向和y方向的边缘信息。


Python实现卷积及Prewitt算子的边缘检测

首先我们把图像卷积函数封装在一个名为imconv的函数中  ( 实际上,scipy库中的signal模块含有一个二维卷积的方法convolve2d()  )

import numpy as np
from PIL import Image def imconv(image_array,suanzi):
'''计算卷积
参数
image_array 原灰度图像矩阵
suanzi 算子
返回
原图像与算子卷积后的结果矩阵
'''
image = image_array.copy() # 原图像矩阵的深拷贝 dim1,dim2 = image.shape # 对每个元素与算子进行乘积再求和(忽略最外圈边框像素)
for i in range(1,dim1-1):
for j in range(1,dim2-1):
image[i,j] = (image_array[(i-1):(i+2),(j-1):(j+2)]*suanzi).sum() # 由于卷积后灰度值不一定在0-255之间,统一化成0-255
image = image*(255.0/image.max()) # 返回结果矩阵
return image

然后我们利用Prewitt算子计算x方向导数矩阵Gx,y方向导数矩阵Gy,和梯度矩阵Gxy。

import numpy as np
import matplotlib.pyplot as plt # x方向的Prewitt算子
suanzi_x = np.array([[-1, 0, 1],
[ -1, 0, 1],
[ -1, 0, 1]]) # y方向的Prewitt算子
suanzi_y = np.array([[-1,-1,-1],
[ 0, 0, 0],
[ 1, 1, 1]]) # 打开图像并转化成灰度图像
image = Image.open("pika.jpg").convert("L") # 转化成图像矩阵
image_array = np.array(image) # 得到x方向矩阵
image_x = imconv(image_array,suanzi_x) # 得到y方向矩阵
image_y = imconv(image_array,suanzi_y) # 得到梯度矩阵
image_xy = np.sqrt(image_x**2+image_y**2)
# 梯度矩阵统一到0-255
image_xy = (255.0/image_xy.max())*image_xy # 绘出图像
plt.subplot(2,2,1)
plt.imshow(image_array,cmap=cm.gray)
plt.axis("off")
plt.subplot(2,2,2)
plt.imshow(image_x,cmap=cm.gray)
plt.axis("off")
plt.subplot(2,2,3)
plt.imshow(image_y,cmap=cm.gray)
plt.axis("off")
plt.subplot(2,2,4)
plt.imshow(image_xy,cmap=cm.gray)
plt.axis("off")
plt.show()

Prewitt算子 的结果如下图所示

上方:左图为原图像,右图为x方向导数图像

下方:左图为y方向导数图像,右图为梯度图像

从图中可以看出,Prewitt算子虽然能检测出图像边缘,但是检测结果较为粗糙,还带有大量的噪声。


近似导数的Sobel算子

Sobel算子与Prewitt比较类似,但是它比Prewitt算子要好一些。

x方向的Sobel算子为

y方向的Sobel算子为

python代码只需要将上面代码中的Prewitt算子改成Sobel算子即可。

# x方向的Sobel算子
suanzi_x = np.array([[-1, 0, 1],
[ -2, 0, 2],
[ -1, 0, 1]]) # y方向的Sobel算子
suanzi_y = np.array([[-1,-2,-1],
[ 0, 0, 0],
[ 1, 2, 1]])

Sobel算子 的结果如下图所示

上方:左图为原图像,右图为x方向导数图像

下方:左图为y方向导数图像,右图为梯度图像

从图中看出,比较Prewitt算子和Sobel算子,Sobel算子稍微减少了一点噪声,但噪声还是比较多的。


近似二阶导数的Laplace算子

Laplace算子是一个二阶导数的算子,它实际上是一个x方向二阶导数和y方向二阶导数的和的近似求导算子。

实际上,Laplace算子是通过Sobel算子推导出来的。

Laplace算子为

Laplace还有一种扩展算子为

为了不再重复造轮子,这次我们运用scipy库中signal模块的convolve()方法来计算图像卷积。

convolve()的第一个参数是原图像矩阵,第二个参数为卷积算子,然后指定关键字参数mode="same"(输出矩阵大小和原图像矩阵相同)。

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import scipy.signal as signal # 导入sicpy的signal模块 # Laplace算子
suanzi1 = np.array([[0, 1, 0],
[1,-4, 1],
[0, 1, 0]]) # Laplace扩展算子
suanzi2 = np.array([[1, 1, 1],
[1,-8, 1],
[1, 1, 1]]) # 打开图像并转化成灰度图像
image = Image.open("pika.jpg").convert("L")
image_array = np.array(image) # 利用signal的convolve计算卷积
image_suanzi1 = signal.convolve2d(image_array,suanzi1,mode="same")
image_suanzi2 = signal.convolve2d(image_array,suanzi2,mode="same") # 将卷积结果转化成0~255
image_suanzi1 = (image_suanzi1/float(image_suanzi1.max()))*255
image_suanzi2 = (image_suanzi2/float(image_suanzi2.max()))*255 # 为了使看清边缘检测结果,将大于灰度平均值的灰度变成255(白色)
image_suanzi1[image_suanzi1>image_suanzi1.mean()] = 255
image_suanzi2[image_suanzi2>image_suanzi2.mean()] = 255 # 显示图像
plt.subplot(2,1,1)
plt.imshow(image_array,cmap=cm.gray)
plt.axis("off")
plt.subplot(2,2,3)
plt.imshow(image_suanzi1,cmap=cm.gray)
plt.axis("off")
plt.subplot(2,2,4)
plt.imshow(image_suanzi2,cmap=cm.gray)
plt.axis("off")
plt.show()

结果如下图

其中上方为原图像

下方:左边为Laplace算子结果,右边为Laplace扩展算子结果

从结果可以看出,laplace算子似乎比前面两个算子(prewitt算子和Sobel算子)要好一些,噪声减少了,但还是比较多。

而Laplace扩展算子的结果看上去比Laplace的结果少一些噪声。


降噪后进行边缘检测

为了获得更好的边缘检测效果,可以先对图像进行模糊平滑处理,目的是去除图像中的高频噪声。

python程序如下

首先用标准差为5的5*5高斯算子对图像进行平滑处理,然后利用Laplace的扩展算子对图像进行边缘检测。

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import scipy.signal as signal # 生成高斯算子的函数
def func(x,y,sigma=1):
return 100*(1/(2*np.pi*sigma))*np.exp(-((x-2)**2+(y-2)**2)/(2.0*sigma**2)) # 生成标准差为5的5*5高斯算子
suanzi1 = np.fromfunction(func,(5,5),sigma=5) # Laplace扩展算子
suanzi2 = np.array([[1, 1, 1],
[1,-8, 1],
[1, 1, 1]]) # 打开图像并转化成灰度图像
image = Image.open("pika.jpg").convert("L")
image_array = np.array(image) # 利用生成的高斯算子与原图像进行卷积对图像进行平滑处理
image_blur = signal.convolve2d(image_array, suanzi1, mode="same") # 对平滑后的图像进行边缘检测
image2 = signal.convolve2d(image_blur, suanzi2, mode="same") # 结果转化到0-255
image2 = (image2/float(image2.max()))*255 # 将大于灰度平均值的灰度值变成255(白色),便于观察边缘
image2[image2>image2.mean()] = 255 # 显示图像
plt.subplot(2,1,1)
plt.imshow(image_array,cmap=cm.gray)
plt.axis("off")
plt.subplot(2,1,2)
plt.imshow(image2,cmap=cm.gray)
plt.axis("off")
plt.show()

结果如下图

从图中可以看出,经过降噪处理后,边缘效果较为明显。


参考列表

1. 《python计算机视觉编程》

2. 网络(感谢百度,感觉网络上分享知识的网友)


实际上,一些现成的Python库已经对边缘检测过程进行了封装,效果和效率更为出色。

文中以自己的python代码进行边缘检测,实际上是想对实际过程有更好的认识和了解

python计算机视觉2:图像边缘检测的更多相关文章

  1. 图像边缘检测——几种图像边缘检测算子的学习及python 实现

    本文学习利用python学习边缘检测的滤波器,首先读入的图片代码如下: import cv2 from pylab import * saber = cv2.imread("construc ...

  2. Python实现图像边缘检测算法

    title: "Python实现图像边缘检测算法" date: 2018-06-12T17:06:53+08:00 tags: ["图形学"] categori ...

  3. 计算机视觉中的边缘检测Edge Detection in Computer Vision

    计算机视觉中的边缘检测   边缘检测是计算机视觉中最重要的概念之一.这是一个很直观的概念,在一个图像上运行图像检测应该只输出边缘,与素描比较相似.我的目标不仅是清晰地解释边缘检测是怎样工作的,同时也提 ...

  4. python计算机视觉1:基本操作与直方图

    本文主要内容来源于书籍<python计算机视觉编程> 我是一名初学者,如果你发现文中有错误,请留言告诉我,谢谢 PIL模块 PIL模块全程为Python Imaging Library,是 ...

  5. Python计算机视觉3:模糊,平滑,去噪

    我是一名初学者,如果你发现文中有错误,请留言告诉我,谢谢 图像的模糊和平滑是同一个层面的意思,平滑的过程就是一个模糊的过程. 而图像的去噪可以通过图像的模糊.平滑来实现(图像去噪还有其他的方法) 那么 ...

  6. 《Python计算机视觉编程》

    <Python计算机视觉编程> 基本信息 作者: (美)Jan Erik Solem 译者: 朱文涛 袁勇 丛书名: 图灵程序设计丛书 出版社:人民邮电出版社 ISBN:978711535 ...

  7. CSharpGL(24)用ComputeShader实现一个简单的图像边缘检测功能

    CSharpGL(24)用ComputeShader实现一个简单的图像边缘检测功能 效果图 这是红宝书里的例子,在这个例子中,下述功能全部登场,因此这个例子可作为使用Compute Shader的典型 ...

  8. 图像边缘检测--OpenCV之cvCanny函数

    图像边缘检测--OpenCV之cvCanny函数 分类: C/C++ void cvCanny( const CvArr* image, CvArr* edges, double threshold1 ...

  9. 【python图像处理】图像的缩放、旋转与翻转

    [python图像处理]图像的缩放.旋转与翻转 图像的几何变换,如缩放.旋转和翻转等,在图像处理中扮演着重要的角色,python中的Image类分别提供了这些操作的接口函数,下面进行逐一介绍. 1.图 ...

随机推荐

  1. 关于HTML在手机端自适应的一个问题

    在写页面的时候 一直以为是自己调节的大小,结果页面跳出来的效果完全不适应手机的尺寸和宽度 其实主要是因为head头中没有放自适应标签导致:下面就让我们来认识一下这款神器吧! 其实主要就是改掉HTML页 ...

  2. #Java编程题-百钱百鸡

    问题: 百钱百鸡问题.用100钱买100只鸡,公鸡一只五钱,母鸡一只三钱,雏鸡三只一钱,编程计算共有几种买法(要求每种鸡至少要买1只). 自己的实现,没有什么数据结构,算法,求大神指点!! packa ...

  3. 自定义Filter服务

    自定义一个用户Email长度超过12个字符后值截取前12个然后添加“...”显示. 例如: index.html <!DOCTYPE html> <html ng-app=" ...

  4. Canvas Path 绘制柱体

    public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceS ...

  5. BZOJ1013 球形空间产生器sphere

    Description 有一个球形空间产生器能够在n维空间中产生一个坚硬的球体.现在,你被困在了这个n维球体中,你只知道球面上n+1个点的坐标,你需要以最快的速度确定这个n维球体的球心坐标,以便于摧毁 ...

  6. 2B相对来说,早期它的成长速度不会像2C那么快

    叶冠泰:今天我们是在场比较少数的2B的公司,你能不能给创业者一些分享,你觉得2B跟2C的差别是什么,我们要怎样发展? 蒋韬:这可能跟性格有关系,我的性格可能更适合去做2B的业务. 对于做2B业务的创业 ...

  7. logstash 防止实际处理时间跟事件产生时间略有偏差

    "message" => " 10.168.255.134 [12/Sep/2016:16:30:40 +0800] \"GET /resources/p ...

  8. 方案:解决 wordpress 中 gravatar 头像被墙问题

    Gravatar头像具有很好的通用性,但是却遭到了无辜的拦截,对于无法加载头像URL,我们在WordPress系统中通过修改默认的URL链接可以达到恢复头像的功能. 修改文件路径为 /wp-inclu ...

  9. 使用itextsharp创建PDF文档——图片集合

    文档管理系统中 ,扫描模块将文档或证件扫描后.为了便于保存多个图片,拟将多个图片生成一个PDF文档进行保存. 这里我们就需要PDF生成工具了.你可以在这里下载.PDFCreator 主要使用了开源工具 ...

  10. 高性能WEB开发(6) - web性能測试工具推荐

    WEB性能測试工具主要分为三种.一种是測试页面资源载入速度的,一种是測试页面载入完成后页面呈现.JS操作速度的,另一种是整体上对页面进行评价分析,以下分别对这些工具进行介绍,假设谁有更好的工具也请一起 ...