你的计算是正确的,但强烈建议你不要使用atan(y/x)的定义,因为这种计算不知道梯度角所在的象限。对于你的分量进行atan(y/x)会错误地报告角度为-45度,而这并不正确。相反,你应该使用atan2。
现在,imgradient的内部非常直接。我想指出的是,imgradient报告的角度假定y坐标从下到上递增。此外,imgradient应该报告指向最大变化率的方向的方向角。在图像的情况下,这指向我们从暗像素到亮像素的进展方向。
首先调用imgradientxy,如果你给imgradient提供sobel标志,则调用fspecial('sobel')。事实上,记住imgradientxy的这部分内容很重要(从第75行开始:MATLAB R2015a)。
case 'sobel'
h = -fspecial('sobel');
Gx = imfilter(I,h','replicate');
if nargout > 1
Gy = imfilter(I,h,'replicate');
end
请注意,
fspecial
输出的
负数会被执行,同时还提供了该行的注释。这是为了确保检测水平边缘的掩模(即
Gy
)是
向下的(在计算机图形学中通常如此)。具体来说,图像的原点位于左上角而不是左下角。
以下是坐标系在
y-down中的图示表示:
![](https://upload.wikimedia.org/wikipedia/commons/d/d2/Clockwise_rotation.png)
来源:
维基百科 - 旋转矩阵
因此,在查找方向时,还有一个额外的要求,即梯度方向的角度是相对于我们习惯的
y-up坐标系的。因此,在计算角度之前,需要对
y
坐标进行
取反,以便角度符合标准约定。
寻找您所需的梯度定义是
y
坐标从底部到顶部增加的常规系统。需要进行取反操作,实际上,如果您检查
imgradient
的源代码,则会在代码的第127行(版本R2015a)执行此操作。
Gdir = atan2(-Gy,Gx)*180/pi; %// Radians to degrees
你可能会问为什么需要在找到方向后否定掩码并再次否定
y
坐标。原因是,修改后的掩码需要正确捕获梯度的大小,所以我们将掩码取反一次并找到梯度大小,然后否定
y
坐标,以便我们可以根据传统坐标系找到角度。
在你的情况下,假设
Gx = 765
和
Gy = -765
,将这些值代入上述方程式得到:
>> Gy = 765
>> Gx = -765
>> Gdir = atan2(-Gy,Gx)*180/pi
Gdir =
-135
这是有道理的,因为梯度方向对应着变化率最大的方向。-135度意味着我们指向西南方向,这很合理,因为我们正在从暗像素向亮像素前进。
现在,如果您查看第三个示例图像,
imgradient
报告的角度确实是正确的。只需从暗区域到光区域绘制一条线,并查看它与
x
轴所成的角度,其中该轴与列向右增加对齐。第一个+90度的角度是合理的,因为我们正在从底部向上跟随暗区域和光区域。这类似于图像翻转的情况。第三种情况是我们之前见过的,第四种情况只是将第三种情况旋转了180度,因此从暗到光的方向角现在是+45度,而不是先前的-135度。
gx=[-1 0 1; -2 0 2; -1 0 1]
和gy=[-1 -2 -1;0 0 0;1 2 1]
时,所有答案都与imgradient匹配,但我无法解释结果。例如,对于情况1:我得到了Gdir = 90
,这是一条位于y轴上(向下)的线,我认为这显示了强度变化。同样地,对于情况2:Gdir = -90
,显示向上的强度变化,但在情况3中:Gdir = -135
,这是边缘存在的角度。问题出在哪里? - Navdeep Sonyimgradient
进行了更深入的调查。我现在知道发生了什么。通过执行atan2(-Gy,Gx)
,可以确保角度相对于y
向上。我将不得不更改我的帖子,因为在imgradient
中,他们确实使用了你指定的那些掩模,而这些掩模本身是y
向下的。因此,-135 度的角度现在是有意义的,这使得梯度指向西南方向,并且这个方向指向最大变化率(即从黑色到白色)。我将更新我的帖子以反映这一点。 - rayryengh = -fspecial('sobel'); %// Align mask correctly along the x- and y- axes
。你怎么知道它是“向下的”?如果我们使用h = fspecial('sobel');
,那么只使用Gdir = atan2(Gy,Gx)*180/pi
而不是Gdir = atan2(-Gy,Gx)*180/pi
是否可以? - Navdeep Sony