写在前面:
本文篇幅较长,用了大量图与公式帮助大家深入理解各种边缘检测算子,希望大家能看完哈,测试编译器为
Matlab
,作为入门
计算机视觉(Computer vision)
领域来说,Matlab是一款非常友好且简单的工具,其中自带各种先进的库函数,实现起来非常快速,偏向于实验性质的应用。好了话不多说,来和笔者一起看一下今天的主题-
边缘检测。
一.前言
首先我们先来简单了解一下
什么是数字图像处理(Digital Image Processing)
,先看一下数字图像主要的两个应用领域:
1.改善图示信息以便人们解释;
2.为存储、传输和表示而对图像数据进行处理,以便于机器自动理解
我们可以简单理解为就将一幅原始图像,使用计算机处理为更为我们所能理解或所需要的形式
,如图1-1所示,为基于边缘检测的免疫细胞图像自动分割过程示意图
图 1-1 克隆细胞图像自动分割过程示意图
让我们再看一个例子,如图1-2 ,为经典的
车牌检测
算法,将原始图像进行
灰度图转换、边缘检测、形态学腐蚀膨胀
等操作,得到车牌区域,随后将车牌区域进行切割(这个是笔者刚入门时做的小demo,还没有用到深度学习模型,用的是knn,因此识别结果很差,各位看官会心一笑就好了哈)
图2 -2 车牌检测
OK,在我们大致了解了数字图像处理之后,接下来介绍数字图像处理一些基本的算法。
二.数字图像处理基础知识与算法
接下来先简单介绍一下一些学习数字图像处理的基础知识与算法
1).数字图像
数字图像指的是现在的图像都是以二维数字表示,每个像素的灰度值均由一个数字表示,范围为0-255(2^8)
2).二值图像、灰度图像、彩色图像
二值图像(Binary Image):
图像中每个像素的灰度值仅可取
0或1
,即不是取黑,就是取白,二值图像可理解为黑白图像
灰度图像(Gray Scale Image):
图像中每个像素可以由
0-255
的灰度值表示,具体表现为从全黑到全白中间有255个介于中间的灰色值可以取
彩色图像(Color Image):
每幅图像是由
三幅灰度图像组合而成
,依次表示红绿蓝三通道的灰度值,即我们熟知的RGB,此时彩色图像要视为
三维
的[height,width, 3]
下面用一张图来感受一下灰度图与彩色图像之间的联系与差别
图2 -1 RGB图像的分解
其中还有一个很重要的公式,即
彩色图像转为灰度图的计算公式
:
G
Gray表示灰度图像,RGB则表示彩色图像的红(red)、绿(green)、蓝(blue)三通道灰度值
3).邻接性、连通性
4邻域:
假设有一点像素p坐标为(x, y),则它的4领域是(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)
D邻域:
假设有一点像素p坐标为(x, y), 则它的D领域是(x + 1, y + 1), ( x + 1, y - 1), (x - 1, y + 1)
(x - 1, y - 1)
8邻域:
将4领域与D领域的集合取并集,即表示为8邻域
图2 - 2 4邻域(左)、 D邻域(中)、 8邻域(右)
4连通:
对于在像素点p的4邻域内的像素均与像素点p形成4连通
8连通:
对于在像素点p的8邻域内的像素均与像素点p形成8连通
4).滤波
滤波的目的主要两个:
1.通过滤波来提取图像特征,简化图像所带的信息作为后续其它的图像处理
2.为适应图像处理的需求,通过滤波消除图像数字化时所混入的噪声
其中第一点就是边缘检测中所使用的基本思想,即简化图像信息,使用边缘线代表图像所携带信息
滤波可理解为滤波器(通常为3*3、5*5矩阵)在图像上进行从上到下,从左到右的遍历,计算滤波器与对应像素的值并根据滤波目的进行数值计算返回值到当前像素点,如图 2-3所示,蓝色块表示滤波器,对图像进行点积运算并赋值到图像
具体公式表示为:
(其中
表示当前像素点,
表示当前像素与滤波器对应值相乘的值,n为滤波器大小,举例来说如若此滤波器值全为1,则此公式计算的是当前像素点的8连通像素点的平均值,因此滤波完后的图像应表现为
模糊
的效果,模糊程度取决于滤波器的大小,滤波器大小(size)越大,模糊效果越明显)
三.边缘检测(Sobel、Prewitt、Roberts、Canny、Marr-Hildreth)
1.基本边缘检测算子
在介绍完滤波的知识后,学习基本边缘检测算法是一件很轻松的事情,因为边缘检测本质上就是一种滤波算法,区别在于
滤波器的选择
,滤波的规则是完全一致的
为了更好理解边缘检测算子,我们引入
梯度(gradient)
这一概念,梯度是
人工智能(artificial intelligence)
非常重要的一个概念,遍布
机器学习
、
深度学习
领域,学过微积分的同学应该知道一维函数的一阶微分基本定义为:
而我们刚才也提到了,图像的滤波一般是
基于灰度图
进行的,因此图像此时是二维的,因此我们在看一下二维函数的微分,即偏微分方程:
由上面的公式我们可以看到,图像梯度即当前所在像素点对于X轴、Y轴的
偏导数
,所以梯度在图像处理领域我们可以也理解为像素灰度值
变化的速度
,下面我们举一个简单的例子:
图 3-1
图中我们可以看到,100与90之间相差的灰度值为10,即当前像素点在X轴方向上的梯度为10,而其它点均为90,则求导后发现梯度全为0,因此我们可以发现在数字图像处理,因其像素性质的特殊性,微积分在图像处理表现的形式为计算当前像素点沿偏微分方向的差值,所以实际的应用是不需要用到求导的,
只需进行简单的加减运算
而另一个概念
梯度的模
则表示f(x, y),在其最大变化率方向上的单位距离所增加的量,即:
在了解完梯度的概念之后呢,下面我们先介绍一下几种基本边缘检测滤波器:
Sobel、Prewitt、Roberts算子
图 3-2 Roberts算子
图 3-2 Prewitt算子
图 3-3 Sobel算子
我们以Sobel为例,其中
分别表示对于X轴、Y轴的边缘检测算子,从
算子结构可以很清楚发现,这个滤波器是计算当前像素点右边与左边8连通像素灰度值的差值,我们先通过一维的概念来理解一下:
如现在有一个一维数组长度为10,值为:
[ 8, 6, 2, 4, 9, 1, 3, 5, 10, 6 ]
此时我们的一维边缘检测算子则表现为[ -1, 0, 1 ],现在我们把边缘检测算子放在数组上面进行点积(即对应点相乘之后的和),得到结果为:
[ 6, -6, -2, 7, -3, -6, 4, 7, 1, -10]
可以发现得到的值出现了负数,但我们之前的定义则声明了像素灰度值
定义域为0-255范围
内,因此这里一般的操作为
将负数截断到0-255以内或者直接取绝对值
,因此现在我们得到的是
[ 6, 6, 2, 7, 3, 6, 4, 7, 1, 10]
其中数字的大小则表示了当前像素点梯度的模大小,即灰度变化的速度有多大,值越大,我们一定程度上就可以确信当前点为我们所要找的边缘点,通过一维的例子我们可以更好理解二维的边缘检测思想,即沿着X轴、Y轴进行两次滤波操作,得到的结果进行平方求和加根号的操作得出当前像素点的
图像梯度
,我们来通过一张图理解一下这个过程:
图 3-4 原图像、沿X轴梯度图像、沿Y轴梯度图像、梯度图像的可视化
图中(a)为原始的灰度图像,(b)和(c)为使用图3-3中Sobel算子的
、
两种形式分别对原始图像进行的滤波结果,即表示为
分别沿X、Y轴的梯度图
,最后将两个图融合在一起则得到了我们所需的梯度图像(d),在给大家一张图来帮助理解Sobel算法
现在我们已经大致了解了边缘检测的基本思想了,看着图 3-4(d)是不是觉得它挺好看的呢,但是好看不一定说明它就是我们所需要的边缘图,直接用基本的边缘算子如Sobel求得的边缘图存在很多问题,如
噪声污染没有被排除、边缘线太过于粗宽
等,因此我们接下来要介绍两个先进的边缘检测算子:
Canny算子和Marr-Hildreth算子
2.较为先进的边缘检测算子
1).Canny算子
Canny算子
是澳洲计算机科学家约翰·坎尼(John F. Canny)于1986年开发出来的一个多级
边缘检测算法,其目标是找到一个最优的边缘,其最优边缘的定义是:
1.
好的检测
--算法能够尽可能多地标示出图像中的实际边缘
2.
好的定位
--标识出的边缘要与实际图像中的实际边缘尽可能接近
3.
最小响应
--图像中的边缘只能标识一次,并且可能存在的图像噪声不应该标识为边缘
所以接下来我们来介绍一下目前流行的Canny算法的具体步骤
(1).高斯(Gaussian)滤波
高斯滤波
目前是最为流行的去噪滤波算法,高斯与我们学的概率论中正态分布中
正态
一词指的是同一个意思,其原理为根据待滤波的像素点及其邻域点的灰度值按照高斯公式生成的参数规则进行
加权平均
,这样可以有效滤去理想图像中叠加的
高频噪声(noise)
二维高斯公式为:
常见的高斯滤波器有:
图 3-5 常见的高斯滤波器
其实高斯滤波器很像一个
金字塔结构
,其滤波器的值大小我们可以理解为
权重(weight)
,值越大对应的像素点权重越大,分量也就越大,因此从高斯滤波器我们可以看出对应当前像素点,距离越远权重越小,对灰度值的贡献也就越小
让我们举个例子来理解一下高斯滤波,如图3-5中左边的高斯滤波器,其中心点4我们可以把它看成是'主人公',其周围的点看成是'邻居',噪声我们把它看成是'坏人',现在我们假设这9个人里面,有一个人是'坏人',我们也知道坏人是肯定会说自己是好人的,但要是我们有投票机制决定一个人是否为'坏人'呢,其中权重(weight)则对应每个人说话的分量,投票机制就为我们所说的加权平均策略,现在我们可以很直观地发现,其实高斯滤波就是一个会考虑其周围像素点的滤波器,即使当前点位为噪声点,高斯滤波器也会通过周围点的灰度值来制约噪声的影响,生成高斯滤波器与滤波的代码如下:
sigma=1; %高斯标准差 % 根据高斯标准差计算滤波器长度 filterExtent = ceil(4*sigma); x = -filterExtent:filterExtent; % 生成一维高斯核 c = 1/(sqrt(2*pi)*sigma); gaussKernel = c * exp(-(x.^2)/(2*sigma^2)); % 标准化 gaussKernel = gaussKernel/sum(gaussKernel); % 对图像进行高斯滤波平滑 aSmooth=imfilter(a,gaussKernel,'conv','replicate'); % 沿着X轴卷积 aSmooth=imfilter(aSmooth,gaussKernel','conv','replicate'); % 沿着Y轴卷积
(其中gaussKernel'表示对gaussKernel进行转置)
(2).计算梯度图像与角度图像
计算梯度图像我们刚才基本也有理解了一下,无非就是用各种边缘检测算子进行梯度的检测,但Canny中使用的梯度检测算子有点高级,是
使用高斯滤波器进行梯度计算得到的滤波器
,得到的结果也类似于Sobel算子,即
距离中心点越近的像素点权重越大
,代码如下:
% 数值梯度函数(Gaussian核的生成1-D导数) derivGaussKernel = gradient(gaussKernel); % 标准化 negVals = derivGaussKernel < 0; posVals = derivGaussKernel > 0; derivGaussKernel(posVals) = derivGaussKernel(posVals)/sum(derivGaussKernel(posVals)); derivGaussKernel(negVals) = derivGaussKernel(negVals)/abs(sum(derivGaussKernel(negVals))); % 计算梯度 dx = imfilter(aSmooth, derivGaussKernel, 'conv','replicate'); dy = imfilter(aSmooth, derivGaussKernel', 'conv','replicate'); mag = hypot(dx,dy); magmax = max(mag(:)); if magmax>0 magGrad = mag / magmax; % 梯度标准化 end
角度图像
的计算则较为简单,其作用为非极大值抑制的方向提供指导,公式如下:
(3).对梯度图像进行非极大值抑制
从上一步得到的梯度图像存在边缘粗宽、弱边缘干扰等众多问题,现在我们可以使用
非极大值抑制
来寻找像素点
局部最大值
,将非极大值所对应的灰度值
置0
,这样可以剔除一大部分非边缘的像素点
如图 3-6所示,C表示为当前非极大值抑制的点,g1-4为它的8连通邻域点,图中蓝色线段表示上一步计算得到的角度图像C点的值,即梯度方向,第一步先判断C灰度值在8值邻域内是否最大,如是则继续检查图中梯度方向交点dTmp1,dTmp2值是否大于C,如C点大于dTmp1,dTmp2点的灰度值,则认定C点为极大值点,置为1,因此最后生成的图像应为一副
二值图像
,边缘理想状态下都为
单像素边缘
图 3-6 非极大值抑制
(其中需要注意的是梯度方向交点并不一定落在8领域所在8个点的位置,因此dTmp1和dTmp2实际应用中是使用相邻两个点的双线性插值所形成的灰度值)
最后在上一张图帮助大家理解,如图3-7所示,其中梯度方向均为垂直向上,经过非极大值抑制后取梯度方向上最大值为边缘点,形成细且准确的单像素边缘
图 3-7
(4).使用双阈值进行边缘连接
经过以上三步之后得到的边缘质量已经很高了,但还是存在很多
伪边缘
,因此Canny算法中所采用的算法为
双阈值法
,具体思路为选取两个阈值,将小于低阈值的点认为是假边缘置0,将大于高阈值的点认为是强边缘置1,介于中间的像素点需进行进一步的检查
根据高阈值图像中把边缘链接成轮廓,当到达轮廓的端点时,该算法会在断点的8邻域点中寻找满足低阈值的点,再根据此点收集新的边缘,直到整个图像闭合,具体代码为:
function nedge=connect1(nedge,y,x,low,high,magGrad) %种子定位后的连通分析 neighbour=[-1 -1;-1 0;-1 1;0 -1;0 1;1 -1;1 0;1 1]; %八连通搜寻 [m n]=size(nedge); for k=1:8 yy=fix(y+neighbour(k,1)); xx=fix(x+neighbour(k,2)); if yy>=1 &&yy<=m &&xx>=1 && xx<=n if magGrad(yy,xx)>=low & nedge(yy,xx)~=255 & magGrad(yy,xx) nedge(yy,xx)=255; %disp('check check'); %nedge=connect1(nedge,yy,xx,low,high,magGrad); end end end end
但由于寻找弱边缘点的计算代价过大,因为使用的是递归思维,且所找寻到的弱边缘点为数不多,因此实际应用中常常舍去这一步骤,取而代之的是基于形态学的
边缘细化
操作,具体思想我们以后还会提到,具体代码为:
H = bwmorph(H, 'thin', 1);
至此,我们已经深度理解了Canny算法的思想与实现手段,实际应用中Canny一般是边缘检测的首选项,其算法思想也非常值得我们学习,接下来我们在简单介绍基于二阶导数法的
Marr-Hildreth边缘检测算子
1).Marr-Hildreth算子
在学习Marr-Hildreth算子之前我们先来理解一下为什么要用
二阶导数法
如图 3-8所示,左边表示的是一副灰度图像,从左到右从黑色(0)慢慢变为白色(255),现在我们来看它的水平灰度剖面,灰度值从小到大平稳上升,其一阶导数表示为在上升区域为不变的值,其中得到的信息是图像灰度值是平稳过渡的,即梯度值相等,接下来在将其求二次导数,得到的图像为在开始过渡的起点为正数,其值为一阶导数在此点的梯度值,结束点也和起点一样,现在重点来了,我们将这两点连起来得到一个与X轴的交叉点,这一点就是我们所认为的边缘点,这就是二阶导数应用在边缘检测领域的奇妙之处(第一次接触的时候觉得巨神奇)
在看一下marr和hildreth的证明结论
:
1.灰度变化与图像尺寸无关,因此他们的检测要求使用不同尺寸的算子
2.灰度的突然变换会在一阶导数中引起波峰或波谷,在二阶导数中等效引起零交叉
图 3-8 零交叉原理
学习了基于二阶导数的马尔哈希算法原理之后,我们来看一下它的思路:
(1).高斯滤波