单位
您正在对函数进行一些近似导数。如果函数是f(x),那么请记住,您正在查看f 中的change,而不是x 中的change。假设函数是基于时间的位置r(t),那么导数的单位是位置差(距离)与时间差(时间)。那么图像的单位是什么?嗯,它们是某些位置的光度值。光度值的变化只是光度值,位置的变化是距离。所以导数的单位是光度/距离。
梯度幅度
由于我们处理的是图像,因此最小距离是一个像素,而最大的变化可能是从白色到黑色(反之亦然),因此它们对应于最大的渐变。但 Sobel 可以处理最小值和最大值可能远远超出 0 到 1 或 0 到 255 的任意矩阵。
请注意,您可能会得到斜率的负值:以像素为单位的距离始终为正,但从白色到黑色以及从黑色到白色的变化具有相反的符号。在 Sobel 计算出这些导数之后,您将分别计算 magnitude 和 angle。您可以根据每个方向的梯度强度对x和y方向进行加权来计算角度,并且它需要符号返回0到360之间的任意角度。
如果您想要所有边的大小为正值,而非边的大小为 0,您可以采用 L1-norm,即abs(x) + abs(y),或采用 Euclidean 或 L2-norm 与 the magnitude function 即 sqrt(G(x)^2 + G(y)^2),就像您要计算三角形的斜边一样。直接添加意味着一些渐变是正的,一些是负的,给你留下一个显示黑白边缘的灰色图像。
Sobel 算子的值
Sobel 算子只是计算像素邻域中的导数,不仅比较两个像素,而是比较六个像素,然后对它们进行加权,将它们全部相加——因此它可能比图像中的值高一点。而且,浮点图像不会在 0 或 1 处被截断,因此您可以发送具有更大值的图像并获得更大的值。除了数据类型可以容纳的最大值之外,运算符没有虚拟最大值。 Sobel 算子在梯度计算之前也会做一些平滑以去除小边缘,但平滑算子不会缩放值。
OpenCV docs for Sobel 显示操作员将图像乘以的值。具体来说,对于x 方向,每个 3x3 像素邻域按元素乘以
-1 0 1
-2 0 2
-1 0 1
并求和。如果图像类型的最大可能值为M,最小值为m,则渐变中最大的正值是
(1+2+1)*M - (1+2+1)*m = 4*M - 4*m
同样最大的负值是
-(1+2+1)*M + (1+2+1)*m = -4*M + 4*m
这对于每个方向的渐变都是相同的。因此,从Sobel 开始的每个方向的渐变范围将是[-4M+4m, 4M-4m]。
规范化操作符
您将以某种方式将这些量级中的两个加在一起,无论是使用 L1 范数还是 L2 范数。假设您坚持使用 L2 范数,则根据 L2 范数定义,组合幅度的最大值将简单地为
MAX = sqrt((4*M - 4*m)**2 + (4*M - 4*m)**2)
= sqrt(2 * (4*M - 4*m)**2)
= sqrt(2 * 16 * (M - m)**2)
= sqrt(32) * (M - m)
由于 L1 或 L2 范数将正值和负值视为相等(它们与 0 的距离很重要),因此 Sobel 算子中的最小值在组合幅度上的响应与最大值的响应相同。当然,您的响应中的某些点可能为 0,这给出了 Sobel 响应,因此总和也为 0,因此 0 将是最小值。
编辑:正如another answer 中提到的这个问题,我们实际上不能同时在 X 和 Y 方向上达到最大值,如果你计算出最大值实际上可以是多少,它最终会更小一些:
sqrt(20) * (M - n)
因此,您可以将梯度标准化为具体介于 0 和 1 w.r.t 之间。您的图像类型除以最大值。这将允许您比较多个图像的边缘强度。
或者您可以只使用normalize 函数,但最终值将取决于您的图像,因此您无法比较图像之间的相等值。