python计算机视觉2:图像边缘检测
我是一名初学者,如果你发现文中有错误,请留言告诉我,谢谢
如果需要检测到图像里面的边缘,首先我们需要知道边缘处具有什么特征。
对于一幅灰度图像来说,边缘两边的灰度值肯定不相同,这样我们才能分辨出哪里是边缘,哪里不是。
因此,如果我们需要检测一个灰度图像的边缘,我们需要找出哪里的灰度变化最大。显然,灰度变化越大,对比度越强,边缘就越明显。
那么问题来了,我们怎么知道哪里灰度变化大,哪里灰度变化小呢?
导数,梯度,边缘信息
在数学中,与变化率有关的就是导数。
如果灰度图像的像素是连续的(实际不是),那么我们可以分别原图像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 Imagedef 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-255image = 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代码进行边缘检测,实际上是想对实际过程有更好的认识和了解
转载于:https://www.cnblogs.com/smallpi/p/4555854.html
python计算机视觉2:图像边缘检测相关推荐
- Python计算机视觉——基本图像操作和处理
文章目录 图像基本操作 读取并显示图像 创建图像缩略图 复制和粘贴图像区域 调整尺寸和旋转 绘制图像.点和线 图像轮廓和直方图 图像轮廓 图像直方图 基本原理 绘制方法 灰度变换 直方图均衡化 基本原 ...
- Python计算机视觉编程第三章——图像到图像的映射
Python计算机视觉编程 图像到图像的映射 (一)单应性变换 1.1 直接线性变换算法 1.2 仿射变换 (二)图像扭曲 2.1 图像中的图像 2.2 图像配准 (三)创建全景图 3.1 RANSA ...
- Python计算机视觉编程第六章——图像聚类(K-means聚类,DBSCAN聚类,层次聚类,谱聚类,PCA主成分分析)
Python计算机视觉编程 图像聚类 (一)K-means 聚类 1.1 SciPy 聚类包 1.2 图像聚类 1.1 在主成分上可视化图像 1.1 像素聚类 (二)层次聚类 (三)谱聚类 图像聚类 ...
- Python 计算机视觉(十)—— OpenCV 图像锐化及边缘检测
参考的一些文章以及论文我都会给大家分享出来 -- 链接就贴在原文,论文我上传到资源中去,大家可以免费下载学习,如果当天资源区找不到论文,那就等等,可能正在审核,审核完后就可以下载了.大家一起学习,一起 ...
- python边缘检测画简笔画_python计算机视觉2:图像边缘检测
标签: 我是一名初学者,如果你发现文中有错误,请留言告诉我,谢谢 如果需要检测到图像里面的边缘,首先我们需要知道边缘处具有什么特征. 对于一幅灰度图像来说,边缘两边的灰度值肯定不相同,这样我们才能分辨 ...
- Python计算机视觉——图像到图像的映射
Python计算机视觉--图像到图像的映射 文章目录 Python计算机视觉--图像到图像的映射 写在前面 1 单应性变换 1.1 直接线性变换算法 1.2 仿射变换 2 图像扭曲 2.1 图像中的图 ...
- python图像边缘检测_python opencv实现图像边缘检测
本文利用python opencv进行图像的边缘检测,一般要经过如下几个步骤: 1.去噪 如cv2.GaussianBlur()等函数: 2.计算图像梯度 图像梯度表达的是各个像素点之间,像素值大小的 ...
- python计算机视觉编程——基本的图像操作和处理
python计算机视觉编程--第一章(基本的图像操作和处理) 第1章 基本的图像操作和处理 1.1 PIL:Python图像处理类库 1.1.1 转换图像格式--save()函数 1.1.2 创建缩略 ...
- python计算机视觉编程——立体图像之计算视差图
计算视差图 一.立体图像 1.1概念 1.2关于图像配准算法 二.立体重建之计算视差图 2.1归一化及算法概念 2.2匹配流程 三.实验测试 3.1实验要求 3.2实验代码 3.3实验结果分析 3.4 ...
最新文章
- mysql 主从同步检查_MySQL主从复制一致性检测
- java 判断二叉树是否平衡_剑指Offer - 判断二叉树是否是平衡二叉树
- C++ leetCode 判断一个整数是否为回文数 9. 回文数 判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
- __METHOD__
- Linux内核中makefile有什么作用?深入解析makefile工作过程和原理
- JS获取元素的第一个子节点
- proxytable代理不生效_深圳劳动纠纷律师为你解答劳动合同没有盖章是否生效
- hdu2074java
- Abaqus动力学分析基础
- Base64 | Base32 | Base16编码和解码小结
- python制作电子签名
- 计算机键盘中复制粘贴快捷键,电脑复制粘贴快捷键
- 数据库SQL习题练习Day4
- 三圣花乡享地道农家乐
- 地铁3D可视化,让一切尽在掌握
- 专访黄泽武:顺丰科技是如何应用边缘计算的?
- source 命令的用法(与 sh Filename、./Filename的区别)
- 推荐!非常好用的sql审核平台——Yearning
- LocalDate 计算两个日期相差天数
- 数字三角形 (15 分)
热门文章
- leetcode268. 缺失数字
- C++:40---继承中类成员的变化关系
- 关于valgrind的安装和内存泄露分析
- Git(10)-merge
- 人工智能工程师需具备的技能_2020年软件测试工程师需要具备的技能--需要学什么--面试题有哪些(灵魂拷问)...
- C++primer第八章 IO库 8.2 文件输入输出
- 使用CLion的时候,对于cmake的使用
- 上班族如何当老板 五大模式任你选
- Vector:动态数组的使用和说明
- 防火墙问题 Linux系统 /etc/sysconfig/路径下无iptables文件