7.边缘检测:2D运算——Canny边缘原理、Canny边缘检测器、Canny-Matlab实战_2

目录

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。

你永远不知道一个或两个图像中隐藏着什么。


——学会编写自己的代码,才能练出真功夫。

猜你喜欢

转载自blog.csdn.net/sw3300255/article/details/82560424