6.边缘检测:梯度——计算梯度Matlab实战_5

目录

计算x,y梯度

梯度方向操作


计算x,y梯度

让我们仔细看看梯度方向,特别是它们如何计算和表示。

% Gradient Direction
>> pkg load image;
>>
% Load and convert image to double type, range[0,1] for convenience
>> img = double(imread('octagon.png'));
>> imshow(img);

我们如何使用具有明确定义边缘和不同角度的图像,代码运行如下所示:

请注意,我们在读取后将图像转换为double类型,并将其缩小到0到1范围。代码如下:

% Load and convert image to double type, range[0, 1] for convenience
>> img = double(imread('octagon.png'))/255;
>> imshow(img); % assums [0, 1] range for double images

这样可以更轻松地追踪可能出现的数字问题。它还使显示更方便,因为imshow假设双倍图像的范围为0到1。

MATLAB和Octave有直接的计算图像梯度的方法。代码如下:

% Computer x,y gradients
>> [gx gy] = imgradientxy(img, 'sobel');
>> imshow(gx);

Imgradientxy是函数,它返回一对矩阵,第一个是x方向的梯度,第二个是y方向的梯度。

我很确定使用的默认过滤器是Sobel,但您也可以明确输入它。让我们尝试可视化梯度图像。

但请注意,imgradientxy函数不会对梯度图像进行标准化,因此我们必须将它们缩放到适当的范围。

>> [gx gy] = imgradientxy(img, 'sobel');
>> imshow((gx + 4)/8);

现在,为什么我们需要加4并除以8?

为了理解这一点,让我们将其视为一个看起来像这样的钟形运算。如图:

现在,当这个过滤器与左边是黑色,右边是白色的图像区域交互时,会发生什么情况呢? 如图:

所有这些负系数,它们乘以0并抵消。

而这些正系数乘以1,同样直到4。因此,该位置的过滤器的总响应为4。如图:

同样,一个图像区域,左边是白色,右边是黑色,会得到 -4。

所以我们的梯度值在 -4 到 4 的范围内:

如果我们为这些值中的每一个加 4,则范围将变为0 到 8:

因此,除以8得到 [0,1] 范围:

数学的应用到这里差不多。

现在运行一下代码,会是什么样的?

正如所料,在 x 梯度图像中,您会看到垂直边缘显示出来。

同样,您可以查看 y 梯度。

% Computer gradient magnitude and direction
>> [gx gy] = imgradientxy(img, 'sobel');
>> imshow((gy + 4)/8);

代码运行如下:

 这次水平边缘显示得更清晰。

请注意,在本地计算机上,您应该能够简单地传递预期范围并让imshow进行缩放。

>> imshow(gx, [-4 4]);

如果省略极限值并传入空向量,则imshow将根据图像中的实际最小值和最大值缩放图像。

>> imshow(gy,[ ]);

这些方法可能会产生略微不同的结果。

例如,发现最小幅度为 -3.5。

这种行为类似于imgsc所做的,虽然它有其他选项来设置颜色映射,等等。

>> imgsc()

好的,既然我们有x和y梯度,我们就有兴趣计算整体梯度的大小和方向。

幸运的是,有一个功能可以一步完成。

梯度大小返回是:梯度在 x 和 y 方向上的欧氏范数。正如我们之前看到的,每个值的绝对值都是4。

因此,总大小的值可以从0到4乘以2的平方根。这是我们以前用来缩放的。

% Obtain gradient magnitude and direction
>> [gmag gdir] = imgradient(gx, gy);
>> imshow(gmag / (4 * sqrt(2))); % gmag = sqrt(gx^2+gy^2), so:[0, (4*sqrt(2))]

这就是梯度大小的样子。代码运行的结果:

边缘像素不是超亮,这表示边缘不那么尖锐,但这没关系,边缘仍然清晰可见。

记住,梯度方向是:用 x梯度值 计算出 y 的tan逆的角度。

返回结果是在以-180到180的范围之内。其中0度对应正x轴,增大角度逆时针旋转。

>> pkg load image;
>>
% Load and convert image to double type, range[0, 1] for convenience
>> img = double(imread('octagon.png'))/255;
>> imshow(img);
>>
% Computer gradient magnitude and direction
>> [gx gy] = imgradientxy(img, 'sobel');
>>
% Obtain gradient magnitude and direction
>> [gmag gdir] = imgradient(gx, gy);
>> imshow((gdir + 180.0) / 360.0); % angle in degrees [-180 , 180] 

代码运行结果,如下:

右边缘的梯度指向0度。

图像的平面区域中的梯度值未定义。

由于它们必须设置为某个数字,因此它们也是0,这就是为什么您无法看到右边缘的梯度值。

正如我前面提到的,角度是逆时针的,所以这是45度,90度,135度,有趣的是,指向左边的梯度是180度,这与-180度相同:

以下是衡量其他角度的好方法:

 现在我想让你编写一个找到具有所需梯度方向的像素的函数。

 该函数应该被称为select_gdir。前几个参数是梯度大小和方向图像。

第三个是我们想要思考的最小范围值。

这是为了滤除可能具有随机梯度方向的噪声像素,但通常是低幅度的。

最后两个参数指定所需的梯度范围,从低到高。

例如,这里我们要看45度角的梯度,加上减去15的边距。

请注意,您需要返回可以使用imshow显示的二进制图像。

下面有一些代码可以帮助您入门。

>> pkg load image;
>>
>>
>> function result = select_gdir(gmag, gdir, mag_min, angle_low, angle_high)
        %TODO
>> endfunction
>>
>>
% Load and convert image to double type, range[0, 1] for convenience
>> img = double(imread('octagon.png'))/255;
>> imshow(img); % assumes [0,1] range for double images
>>
>>
% Computer x, y gradients
>> [gx gy] = imgradientxy(img, 'sobel');
>>
>>
% Obtain gradient magnitude and direction
>> [gmag gdir] = imgradient(gx, gy);
>> imshow((gdir + 180.0) / 360.0); % angle in degrees [-180 , 180] 
>>
>>
% Find pixels with desired gradient direction
>> my_grad = select_gdir(gmag, gdir, 1, -15, 15); % ~0 deg
>> imshow(my_grad);

梯度方向操作

好的,解决方案实际上只需要一行代码。

首先,我们知道我们想要至少具有指定最小幅度的像素。我们可以使用关系运算符直接将矩阵与标量值进行比较。

这基本上是一种阈值操作。

>> function result = select_gdir(gmag, gdir, mag_min, angle_low, angle_high)
        result  = gmag >= mag_min
>> endfunction

接下来,我们使用一对比较来说明gdir应该在angle_low和angle_high之间。

请注意,使用逐元素和运算符组合三个比较的结果。

>> function result = select_gdir(gmag, gdir, mag_min, angle_low, angle_high)
        result  = gmag >= mag_min & angle_low <= gdir & gdir <= angle_high;
>> endfunction

让我们看看哪些像素具有45度的梯度,具体代码如下:

>> pkg load image;
>>
>>
>> function result = select_gdir(gmag, gdir, mag_min, angle_low, angle_high)
        result  = gmag >= mag_min & angle_low <= gdir & gdir <= angle_high;
>> endfunction
>>
>>
% Load and convert image to double type, range[0, 1] for convenience
>> img = double(imread('octagon.png'))/255;
>> imshow(img); % assumes [0,1] range for double images
>>
>>
% Computer x, y gradients
>> [gx gy] = imgradientxy(img, 'sobel');
>>
>>
% Obtain gradient magnitude and direction
>> [gmag gdir] = imgradient(gx, gy);
>> imshow((gdir + 180.0) / 360.0); % angle in degrees [-180 , 180] 
>>
>>
% Find pixels with desired gradient direction
>> my_grad = select_gdir(gmag, gdir, 1, 30, 60); % 45 +/- 15
>> imshow(my_grad);

代码运行结果:

代码按预期进行。请注意,该线比预期的更薄。

并非所有具有45度梯度方向的像素都被包括在内,因为已经滤除了具有低幅度的像素。

同样,我们可以看0度。在select_gdir函数,我们将范围指定为 -15到 15。

下面的代码都是显示负角度的,注意select_gdir函数的低值和高值位置,不要弄错,角度是逆时针的。

180度可能很棘手,你需要进行思考的。

以下是完整的代码:

>> pkg load image;
>>
>>
>> function result = select_gdir(gmag, gdir, mag_min, angle_low, angle_high)
        result  = gmag >= mag_min & angle_low <= gdir & gdir <= angle_high;
>> endfunction
>>
>>
% Load and convert image to double type, range[0, 1] for convenience
>> img = double(imread('octagon.png'))/255;
>> imshow(img); % assumes [0,1] range for double images
>>
>>
% Computer x, y gradients
>> [gx gy] = imgradientxy(img, 'sobel');
>>
>>
% Obtain gradient magnitude and direction
>> [gmag gdir] = imgradient(gx, gy);
>> imshow((gdir + 180.0) / 360.0); % angle in degrees [-180 , 180] 
>>
>>
% Find pixels with desired gradient direction
>> my_grad = select_gdir(gmag, gdir, 1, -150, -120); % -135 deg
>> imshow(my_grad);

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

猜你喜欢

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