和Sobel算子一样用作图像求导,卷积核结构和Sobel一致,但是调整了权重,使得平滑化后的图像存在旋转不变性,形如:
$$G_x = \begin{bmatrix} -3 & 0 & 3 \\ -10 & 0 & 10 \\ -3 & 0 & 3 \end{bmatrix}, \quad G_y = \begin{bmatrix} -3 & -10 & -3 \\ 0 & 0 & 0 \\ 3 & 10 & 3 \end{bmatrix}$$
为什么Scharr算子更好
- 旋转对称性
- Sobel 核在旋转 45 度时,响应会失真。
- Scharr 核的设计使得它在旋转时响应更均匀,边缘检测更准确。
- 精度
- Scharr 核的权重(3, 10, 3)是通过优化得到的,使得一阶导数的近似更精确。
- 在 OpenCV 中,
cv::Scharr()专门用于3×3窗口,而cv::Sobel()在3×3时精度不如 Scharr。
- 计算量
- Scharr 和 Sobel 都是3×3卷积,计算量相同。
- 但 Scharr 的精度更高,所以“性价比”更好。
一个关键数字:增益 = 32
Scharr 模板对单位斜坡的增益是 32。验证一下:设图像是水平斜坡,斜率 $s$(灰度级/像素),则
$$G_x = 3\times 4s + 10\times 2s = 12s + 20s = 32s$$
(上排 $\pm 3$ 与下排合并贡献 $3\times 4s$,中排 $\pm 10$ 贡献 $10\times 2s$。)
这个 32 正是本项目代码里那个常数的来历:$\texttt{constexpr double kGradientGain = 32.0;}$
源码注释原文:「Scharr 模板对单位斜坡的增益是 32,解出的步长乘它才是像素位移。」
因为梯度图被除以 255 归一化到 $[0,1]$,解出来的 LK 步长会比真值小 32 倍,必须乘回来。它不是调参常数,是单位换算。
