1. 实验目的
熟悉opencv读入图片,显示图像,了解canny边缘检测的用途及原理.
2.实验设备
安装了python和pychrm的电脑一台。
3.实验内容
包含图片的导入、canay边缘检测
4.实验原理
什么是边缘?
边缘一般是指图像在某一局部强度剧烈变化的区域。强度变化一般有两种情况:阶跃变化和屋顶变化。
1.阶跃变化
灰度变化图像如下图所示(横轴表示空间变化,纵轴表示灰度变化,虚线表示边缘):
图1.1.1 像素值阶跃变化
此图对应的是向亮渐变的过程。
2.屋顶变化
灰度变化图像如下图所示(横轴表示空间变化,纵轴表示灰度变化,虚线表示边缘):
图1.1.2 像素值屋顶变化
此图对应得实由暗到亮再变暗的过程。而边缘检测的任务:找到具有阶跃变化或者屋顶变化的像素点的集合。
边缘检测基本原理:
既然边缘是灰度变化最剧烈的位置,最直观的想法就是求微分。对于第一种情况:一阶微分的峰值为边缘点,二阶微分的零点为边缘点。对于第二种情况:一阶微分的零点为边缘点,二阶微分的峰值为边缘点。
OpenCV提供了许多边缘检测滤波春数,包括Laplacian()、Sobel()以及Scharr()等。这些滤波函数都会将非边缘区域转为黑色,将边缘区域转为白色或其他饱和的颜色。但是,这些函数都很容易将噪声错误地识别为边缘。缓解这个问题的方法是在找到边缘之前对图像进行模糊处理。OpenCV也提供了许多模糊滤波函数,包括blur()(简单的算术平均)、medianBlur()以及GaussianBlur()。边缘检测滤波函数和模糊滤波丽数的参数有很多,但总会有一个ksize(滤波核尺寸)参数,它是一个奇数,表示滤波核的宽和高。
Canny边缘检测,它对受白噪声影响的阶跃型边缘是最优的,canny检测子的最优性与以下三个标准有关:
检测标准:不丢失重要的边缘,不应有虚假的边缘
定位标准:实际边缘与检测到的边缘位置之间的偏差最小
单响应标准:将多个响应降低为单个边缘响应。这一点被第一个标准部分地覆盖了,因为当有两个响应对应于单个边缘时,其中之一应该被认为是虚假的。这第三个标准解决受噪声影响的边缘问题,起抵制非平滑边缘检测子的作用。
Canny 的目标是找到一个最优的边缘检测算法,是一种先平滑再求导的方法,最优边缘检测的含义是:
好的检测:算法能够尽可能多地标识出图像中的实际边缘。
好的定位:标识出的边缘要尽可能与实际图像中的实际边缘尽可能接近。
最小响应:图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘。
Canny边缘检测算法可以描述为:
(1)读入要处理的图像
(2)创建一个一维高斯掩模G用于对I进行卷积运算。这个高斯函数的标准偏差是传
入边缘检测器的一个参数。
(3)在x和y方向上创建高斯函数的一阶导数作为一维掩模,分别称为
和。s值和步骤(2)中使用的一样。
(4)沿着行利用G对图像I做卷积运算得到x分量图像,沿着列利用G对图像I做卷 积运算得到y分量图像
。
(5)利用对
进行卷积运算得到
,即利用高斯函数的导数对I的x分量进行卷积运算,然后利用
对
进行卷积运算得到
。
(6)结合x分量和y分量计算边缘响应的强度(即,是否希望在这一点看到结果)。
高斯平滑:
为了尽可能减少噪声对边缘检测结果的影响,所以必须滤除噪声以防止由噪声引起的错误检测。为了平滑图像,使用高斯滤波器与图像进行卷积,该步骤将平滑图像,以减少边缘检测器上明显的噪声影响。
若图像中一个3x3的窗口为A,要滤波的像素点为e,则经过高斯滤波之后,像素点e的亮度值为:
其中*为卷积符号,sum表示矩阵中所有元素相加求和。
重要的是需要理解,高斯卷积核大小的选择将影响Canny检测器的性能。尺寸越大,检测器对噪声的敏感度越低,但是边缘检测的定位误差也将略有增加。一般5x5是一个比较不错的。
计算梯度强度和方向:
图像中的边缘可以指向各个方向,因此Canny算法使用四个算子来检测图像中的水平、垂直和对角边缘。边缘检测的算子(如Roberts,Prewitt,Sobel等)返回水平Gx和垂直Gy方向的一阶导数值,由此便可以确定像素点的梯度G和方向theta 。
其中G为梯度强度, theta表示梯度方向,arctan为反正切函数。
非最大值抑制:
Canay边缘检测器的最后一步是非最大抑制
非极大值抑制是一种边缘稀疏技术,非极大值抑制的作用在于“瘦”边。对图像进行梯度计算后,仅仅基于梯度值提取的边缘仍然很模糊。对于标准3,对边缘有且应当只有一个准确的响应。而非极大值抑制则可以帮助将局部最大值之外的所有梯度值抑制为0,对梯度图像中每个像素进行非极大值抑制的算法是:
-
将当前像素的梯度强度与沿正负梯度方向上的两个像素进行比较。
-
如果当前像素的梯度强度与另外两个像素相比最大,则该像素点保留为边缘点,否则该像素点将被抑制。
通常为了更加精确的计算,在跨越梯度方向的两个相邻像素之间使用线性插值来得到要比较的像素梯度,现举例如下:
图1.1.3 梯度方向
如上图所示,将梯度分为8个方向,分别为E、NE、N、NW、W、SW、S、SE,其中0代表00~45o,1代表450~90o,2代表-900~-45o,3代表-450~0o。像素点P的梯度方向为theta,则像素点P1和P2的梯度线性插值为:
因此非极大值抑制的伪代码描写如下:
需要注意的是,如何标志方向并不重要,重要的是梯度方向的计算要和梯度算子的选取保持一致。
双阈值检测:
在施加非极大值抑制之后,剩余的像素可以更准确地表示图像中的实际边缘。然而,仍然存在由于噪声和颜色变化引起的一些边缘像素。为了解决这些杂散响应,必须用弱梯度值过滤边缘像素,并保留具有高梯度值的边缘像素,可以通过选择高低阈值来实现。如果边缘像素的梯度值高于高阈值,则将其标记为强边缘像素;如果边缘像素的梯度值小于高阈值并且大于低阈值,则将其标记为弱边缘像素;如果边缘像素的梯度值小于低阈值,则会被抑制。阈值的选择取决于给定输入图像的内容。
双阈值检测的伪代码描写如下:
辅助理解:
图1.1.4 阈值范围
5.实验步骤
打开pycharm。
我们右击相应的文件目录,选择new--->点击Python File,然后输入新建的文件名,点击确定,相应的.py文件就建好了,可以进行编写代码了。
import cv2
读取图片。
img = cv2.imread("..\images\aifos.png")
转换为灰度图像。
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
与灰度图像进行卷积实现高斯滤波去燥,核大小为3*3。
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
调用opencv的Canny函数进行边缘检测,后两个参数的数值越大,检测到的边缘越少 。
canay=cv2.Canny(gray,200,300)
显示图像。
cv2.imshow("img", img) cv2.imshow("canay ", canay)
cv2.waitKey()
运行代码,原图和canny边缘检测效果如下图所示。
图1.1.5 运行结果