边缘提取
图像的边缘是灰度值急剧变化的位置,图像中亮度明显急剧变化的点。从心里学上研究,通常都会图像感知很重要。甚至只考虑图像边缘就可以理解图像的内容。而且边缘对光照的变换就不那么敏感,所以有时候需要通过手段来检查边缘。
为什么要研究边缘
边缘线条会给我们带来大量关于图像信息,线条可以事物之间边界线,也可以事物阴影区域都是线条。边缘检测用于图像分割,提取图像形状的信息,那么边缘检测也就是用二值图表示出图片中边缘信息。所以在图像中,线条相对于颜色和纹理,显得格外重要。能够给我们带来大量的信息。我们无需色彩,仅单色的线条图就可以清楚来表达一些信息,而且这些信息足够反应图像的语义。
- 编码图像中的语义与形状信息
- 相对于像素表示,边缘表示显然更加紧凑
边缘的种类
- 表面法向不连续
- 深度不连续
- 表面颜色不连续
- 光照不连续
Canny 边缘探测
Canny 算子检测出边相对于其他边缘检测检测出边的效果显著不同就是,Canny 检测出的边是比较细且清晰,更加便于接下来进行的分析。
基于 Canny 算子的边缘检测主要有如下几个步骤,依次是高斯滤波、像素梯度计算、非极大值抑制、滞后阈值处理。
- 高斯滤波
- 梯度运算
- 非极大值抑制
- 滞后阈值
梯度计算
对于一个连续函数我们通过对某一点进行求导来计算函数在该点的导数,导数反应了函数(曲线)在该点的变化率。
在二维连续数集上有函数f(x,y),我们也可以通过求导过程,该函数在 x 和 y 分量的偏导数,根据定义有:
对于图像来说,是一个二维的离散型数集,通过推广二维连续型求函数偏导的方法,来求得图像的偏导数,即在 (x,y) 处的最大变化率,也就是这里的梯度
接下里我们就用梯度形式来
对于梯度是由方向和大小的,好那么什么又是梯度的大小、什么又是梯度的方向呢。接下来用公式给大家展示一下,记作幅值
为了减小开销可以将梯度模表示为
方向表示为
非极大值抑制
抑制不是极大值的元素,局部最大搜索,排除干扰。根据梯度运算得出每个像素点的梯度方向和大小归类。中心点与其所属方向上像素点进行幅值比较,是否大于该方向所有像素点梯度幅值。是则为灰度值为幅值否则幅度值为 0。
滞后阈值
有些位置边并不连续,阈值如何设置过高将许多原本是线位置设置,如果将阈值设置过低就会细碎边,我们希望效果是找到清晰物体的轮廓。这些。
经过非极大值抑制后图像检测出边还是有许多灰色而且不算清晰。所以接下来设置双阈值,规定上下阈值,所谓双阈值就是有两个阈值分别是低阈值和高阈值。如果像素点灰度值是大于最大阈值就直接将其更新为 255 。如果像素点的灰度值小于最小阈值就将其灰度值更新为 0。如果像素点灰度值是处于最大阈值到最小阈值之间的值,就看其 8 邻域中是否有大于最大阈值的值,如果有也就将其归为 255。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread("messi5.jpg",0)
titles = ['image']
images = [img]
for i in range(1):
plt.subplot(1,1,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
img = cv.imread("messi5.jpg",0)
canny = cv.Canny(img,100,200,)
titles = ['image','canny']
images = [img,canny]
for i in range(2):
plt.subplot(1,2,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])