目录
Canny边缘原理
Canny边缘检测器
Canny-Matlab实战
Canny边缘原理
既然我们知道了如何计算光滑导数和梯度,我们就可以回到如何找到边的问题上。
基本上这是一个多步骤的过程,对吧?
1.你要创建平滑的导数来抑制一些噪声我们要计算一些主要的梯度。
2.我们要对梯度进行阈值以找到一些重要的变化区域。
3.我们将这些领域,我们要做所谓的变薄。
(下面所示的一个例子,我们将进一步讨论,这样脂肪边缘变成一个轮廓,然后说这就是优势)
4.最后,我们要以某种方式连接这些像素的,如果你真的想要一个连接轮廓。
所以我想说的边缘算子是John Canny做的,实际上是他的硕士论文,当我还在那里上学的时候,
他在他的博士论文中继续做了一些很酷的东西,但是大家都知道因为它被称为Canny边缘算子。
Canny算子的工作原理是这样的:
1.首先你用高斯函数的导数对图像进行过滤;
2.找出幅度和方向;
3.进行非极大值抑制,也就是这种细化,我们等下会讲到;
4.有一个连接操作,在这里您将不仅要定义一个阈值,还要定义两个阈值,并且您将使用高的阈值开始边缘化;
但是您将使用更低的阈值来继续;(我们将详细讨论这个,这是真正的酷的洞察力)
顺便说一下,MATLAB会处理Canny边缘,所以你可以通过调用边缘函数来获取Canny边缘。
我鼓励你看MATLAB的相关边缘文档。
MATLAB中图像处理工具箱的文档,帮助你学习MATLAB中的所有边缘检测,它实际上是图像处理信息的主要来源。
Canny边缘检测器
为了说明这个有趣的边缘探测器,我要用Lena的图片:
有个人,他剪掉了1972年男性杂志的顶部照片,那是Lena Soderberg,我想是她的名字。
这是她最近的照片:
所以我们都变了。
我们还是使用最上面那张用于图像处理的图片。
如果我们取梯度的大小,我们得到的值是这样的:
你看它接近边缘,但实际上,你和我都看到了边缘,对吧?
它只是一个梯度图像,对吧?
然后我们就可以阈值梯度:
现在你可以看到这些东西都消失了,所以任何梯度不高的东西都被去掉了。
然后我们做一个调整叫图像细化, 稍后我们会详细讨论这个。
这个奇特的名字叫非极大抑制。
基本上就是说,如果我有一些点在局部超过阈值,让我只取出超过它最多的点。
我们马上会学习到。
当你这样做的时候,你会得到这样的结果:
两张对比,你可以看到这是它的细化版本:
简单说明一下,为什么要细化?
我们来看看这个小区域:
你可以看到有一个厚的部分超过了临界值。
我们想说的是中间有一条边:
你想想,如果你来到这里,你可能会看到一个轮廓线从低到高,对吧?
如果你对它求导,你会发现这个区域的导数高于这个阈值:
这就得到了这条粗边:
我们想把它变成一条细边。
因此,非最大抑制的方式,细化是在canny算子中完成的,如下所示:
你不需要实施这个,我只是想让你知道发生了什么。
基本上它会找到高梯度的区域,它会沿着梯度的方向看过去,它只会找到那里的峰值:
然后这里也是一样,你会在这里找到峰值:
这里的梯度是这个方向,所以会找到峰值:
有时候,有时候你需要插值,这就是这张图显示:
你找到梯度,你说:Ok,我认为它在两个像素之间,所以你可以得到亚像素(sub-pixel)精度。
但关键是,它看起来垂直于梯度向量,为了找到最大值。
这个细化的部分,这就是怎么做的,现在有一个非常聪明的细节要看。
如果你看一下下巴下面的这个点,你会看到一些像素没有通过阈值:
这是一个问题,你可以说我们的阀值设置的太高了。
然后会出现一大堆我们并不关心的东西。
问题是如何处理这个问题:
1.我们做的第一件事是应用高阈值来检测边缘,强边缘像素。阈值会拉出一些像素。
2.我们要做的就是把这些强边像素连接起来形成强边。
3.我们现在使用一个低阈值来找到弱的,但可能的边缘像素。
4.接着我们沿着弱像素点扩展强边。
这意味着如果一条边上只有弱像素,它就不会被发现是一条边。
只有当某些像素是强边缘像素时,才能找到边缘。这里的假设是,我关心的所有边都有一些强像素。
然后,我可能不得不继续连接一个阀值较低的区域,但边缘是由高阀值像素的检测开创的。
Canny-Matlab实战
我有两个图片给你,曲发和轿车。
>> pkg load image;
>>
>> frizzy = imread('frizzy.png');
>> froomer = imread('froomer.png');
>> imshow(frizzy);
>> imshow(froomer);
>>
>> % TODO: Find edges in frizzy and froomer images
>>
>> % TODO: Display common edge pixels
代码运行,显示两张图片:
我希望您在这些图像中找到边缘,然后显示两者之间共有的边缘像素。
如果你能做也不错,我们来一起做做吧:
现在我们来看看是怎么得到这个的。
首先,将图像从颜色转换为灰度,使用rgb2gray()函数:
然后使用边缘函数分别计算每个图像的边缘。请注意,我明确地使用了'canny'。默认是我认为索贝尔,它不起作用。
Canny接受了附加参数、滞后性值和平滑sigma值。随意玩他们。
>> pkg load image;
>>
>> frizzy = imread('frizzy.png');
>> froomer = imread('froomer.png');
>> imshow(frizzy);
>> imshow(froomer);
>>
>> % TODO: Find edges in frizzy and froomer images
>> frizzy_gray = rgb2gray(frizzy);
>> froomer_gray = rgb2gray(froomer);
>>
>> frizzy_edges = edge(frizzy_gray, 'canny');
>> froomer_edges = edge(froomer_gray, 'canny');
>> imshow(frizzy_edges);
>> imshow(froomer_edges);
>>
>> % TODO: Display common edge pixels
代码运行如下:
这是frizzy的边缘。这几乎是完美的。
注意在嘴巴和鼻子周围,我们有很厚的轮廓,我们有双重边缘。
这是预期的。
这是froomer的边缘,也很好。
好的,现在怎么办呢?
注意,边缘图像是二进制图像。
这意味着你可以和它们一起找到共同的边缘像素。
>> pkg load image;
>>
>> frizzy = imread('frizzy.png');
>> froomer = imread('froomer.png');
>> imshow(frizzy);
>> imshow(froomer);
>>
>> % TODO: Find edges in frizzy and froomer images
>> frizzy_gray = rgb2gray(frizzy);
>> froomer_gray = rgb2gray(froomer);
>>
>> frizzy_edges = edge(frizzy_gray, 'canny');
>> froomer_edges = edge(froomer_gray, 'canny');
>> imshow(frizzy_edges);
>> imshow(froomer_edges);
>>
>> % TODO: Display common edge pixels
>> imshow(frizzy_edges & froomer_edges); % binary AND
代码运行,结果:
OK。
你永远不知道一个或两个图像中隐藏着什么。
——学会编写自己的代码,才能练出真功夫。