目录
计算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);
——学会编写自己的代码,才能练出真功夫。