ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Kornia 单应矩阵估计数值修复:find_homography_dlt 最小四点系统改用自适应齐次 Gauge 求解

Kornia 单应矩阵估计数值修复:find_homography_dlt 最小四点系统改用自适应齐次 Gauge 求解
  • 计算机视觉
  • 深度学习
  • 图像处理

【免费下载链接】kornia

🐍 Geometric Computer Vision Library for Spatial AI

项目地址:https://gitcode.com/GitHub_Trending/ko/kornia
点击查看免费下载

本篇技术指南聚焦 Kornia 中一次关键的单应矩阵(Homography)估计数值修复:find_homography_dlt(..., solver="lu")对最小四点系统改用自适应齐次 Gauge(adaptive homogeneous gauge)求解,取代了对奇异正规矩阵(normal matrix)的 LU 分解。该变更直接影响RANSAC(model_type="homography")在每一轮最小样本上的估计结果,修复了 Windows + PyTorch 2.14 下的全 NaN 单应矩阵问题,并显著降低了传输残差。读完本文,你将理解 DLT 最小四点系统为何数值上脆弱、新 Gauge 算法如何工作、它对 RANSAC 精度的影响,以及哪些使用路径不受影响。

变更背景:最小四点系统为何是数值"雷区"

DLT(Direct Linear Transform)是估计单应矩阵的经典方法。给定两幅图像间的 N 组点对应(points1, points2),每个对应关系贡献两个线性方程(ax与ay两行),Kornia 在 kornia/geometry/homography.py 中通过拼接构造出形状为(B, 2N, 9)的设计矩阵A:

ax = torch.cat([zeros, zeros, zeros, -x1, -y1, -ones, y2 * x1, y2 * y1, y2], dim=-1) ay = torch.cat([x1, y1, ones, zeros, zeros, zeros, -x2 * x1, -x2 * y1, -x2], dim=-1) A = torch.cat((ax, ay), dim=-1).reshape(ax.shape[0], -1, ax.shape[-1])

欠定问题与奇异正规矩阵

单应矩阵H是 3×3 矩阵、有 9 个参数,但齐次坐标下尺度自由,实际只有 8 个自由度。当样本恰好为 4 个点时,A的形状是(B, 8, 9),8 个方程求解 9 个未知数——这是一个**欠定(underdetermined)**系统,解空间是一维的(即零空间向量,null vector)。

旧实现把所有情况统一处理:先构造成正规方程AᵀA(见 kornia/geometry/homography.py),再对AᵀA(形状(B, 9, 9))做 LU 分解求解。问题在于:四点情形下AᵀA是奇异的(秩至多为 8),对其做 LU 分解在数值上是不稳定的——这正是旧代码在特定平台产出全 NaN 单应矩阵的根源。

固定 h33=1 Gauge 的隐患

齐次坐标下还需要固定一个"规范"(gauge)来消除尺度模糊,最常见的选择是固定h33 = 1。但源码注释明确指出:

A fixed h33=1 gauge is invalid whenever the bottom-right entry is zero.

当真实单应矩阵的右下角元素h33恰好(或数值上)接近 0 时,固定h33=1的约束本身就让求解系统退化。对应测试 tests/geometry/test_homography.py 展示了一个这样的构造:归一化坐标系下的零向量最后一维约为-1.3e-16,此时固定h33=1的 gauge 是奇异的。

Windows + PyTorch 2.14 的全 NaN 复现

find_homography_dlt是RANSAC(model_type="homography")在每个最小样本上都要调用的估计器(见 kornia/geometry/ransac.py)。RANSAC 每轮迭代会从数百上千个点对中抽取一个四点最小样本,只要抽样抽到上述退化配置,旧 LU 路径就可能在特定平台(如 Windows + PyTorch 2.14)上产出全 NaN 的H。而 NaN 会沿 RANSAC 的验证链路静默传播,污染整个估计结果——这正是本次修复要消灭的核心问题。

新求解器:自适应齐次 Gauge

本次修复(PR #4197,见 changelog.d/+migration-097.fixed.md)的关键决策是:四点最小样本不再构造正规方程,而是直接从设计矩阵本身求零向量。源码中的路径判断非常清晰(kornia/geometry/homography.py):

minimal_lu = solver == "lu" and points1.shape[1] == 4 if not minimal_lu: A = A.transpose(-2, -1) @ A if w_full is None else (A.transpose(-2, -1) * w_full) @ A

只有当solver == "lu"且点数恰好为 4 时,才走新的自适应 Gauge 路径;其余情况保持原正规方程公式。新路径的算法步骤(kornia/geometry/homography.py)如下:

第 1 步:完整 QR 求零向量

对转置后的加权设计矩阵执行完整的 QR 分解:

Q, _ = torch.linalg.qr(Aw.detach().to(gauge_dtype).transpose(-2, -1), mode="complete") null = Q[..., -1]

Q的最后一列即Aw的零向量(null vector),它张成最小四点系统的一维解空间。值得注意的是,QR 在float64(若输入是 float64)或float32的gauge_dtype下计算,且带.detach()——该中间过程不参与反向传播,避免奇异中间量污染梯度(这也与测试 tests/geometry/test_homography.py 中"奇异梯度穿过估计单应矩阵"的防护目标一致)。

第 2 步:argmax 选择 Gauge

gauge = null.abs().argmax(dim=-1)

取零向量绝对值最大的分量作为固定位置。这样,gauge 是自适应的:它总能选到一个非零分量来固定,不会像固定h33=1那样在特定配置下失效。每个 batch 样本可以选择不同的 gauge 分量。

第 3 步:求解保留的 8×8 系统

固定第gauge个分量为 1 后,剩下的 8 个未知数组成一个 8×8 系统:

retained = torch.arange(8, device=device).expand(A.shape[0], -1) retained = retained + (retained >= gauge[:, None]).to(retained.dtype) selected = Aw.gather(-1, retained[:, None].expand(-1, 8, -1)) B = -Aw.gather(-1, gauge[:, None, None].expand(-1, 8, 1)).squeeze(-1) sol, _, valid = safe_solve_with_mask(B, selected)

safe_solve_with_mask同时返回valid掩码,用于标记系统是否奇异。

第 4 步:零权重退化回退

当样本中存在权重为 0 的对应关系时,会零化设计矩阵的两行,使保留的 8×8 系统变得奇异。此时代码直接回退到零向量(它仍然有限,且满足幸存的方程),而不是把 NaN 交给调用方:

null = (null / null.gather(-1, gauge[:, None])).to(sol.dtype) sol = torch.where(valid[:, None], sol, null.gather(-1, retained))

第 5 步:组装与反归一化

把解按 gauge 位置插回 9 维,重排为 3×3,再撤销前面的点归一化:

H = safe_inverse_with_mask(transform2)[0] @ (H @ transform1) return H / (H[..., -1:, -1:] + eps)

对 RANSAC(homography) 的精度与行为影响

调用链确认

RANSAC在model_type="homography"时把find_homography_dlt绑定为minimal_solver(kornia/geometry/ransac.py),每一轮随机抽样产生的四点最小样本都会经过新路径,polisher 阶段则使用迭代加权的find_homography_dlt_iterated。因此这次修复的影响面是所有平台上的 homography RANSAC:

homography RANSAC results change on every platform, not only where the old formulation broke down

也就是说,这不仅是修一个崩溃 bug,而是让所有平台的 RANSAC 输出都发生数值变化(变得更准)。

实测残差下降

变更记录给出的量化结果是:在超过 2048 个最小样本的测试集上——

指标修复前修复后
中位传输残差(median transfer residual)2.3e-51.9e-6
最坏情况残差(worst case)4.2e+54.5e+2

中位残差下降约一个数量级,而最坏情况从4.2e+5骤降至4.5e+2(下降近 3 个数量级)——这直接反映了原先奇异系统在退化配置下产生的病态解有多离谱。

行为变化清单

  • 修复 Windows + PyTorch 2.14 上四点样本的全 NaN 单应矩阵;
  • 移除对应的 CPU 半精度(half-precision)已知失败(known failures)条目;
  • 含零权重的四点样本现在返回有限(finite)的单应矩阵而非 NaN;
  • 若项目中已有依赖旧 LU 数值结果的测试基准或管线,需要重新校准。

哪些路径保持不变

本次修复刻意保持了向后兼容的数值边界,源码注释与变更记录都明确:

  1. 五点及以上样本:仍然走正规方程AᵀA公式,且"数值上不变"(numerically unchanged)。加权路径还特意保持了与原实现完全一致的运算顺序(见 kornia/geometry/homography.py),保证带权重结果与修复前逐位一致;
  2. solver="svd"路径:不受影响,仍对设计矩阵(或正规矩阵)做 SVD 取最小奇异值对应的右奇异向量(kornia/geometry/homography.py)。SVD 本身对奇异系统更稳健,但代价是计算开销更大;
  3. 逐点归一化(normalize_points)与反归一化、以及最终的h33归一化(带eps = 1e-8防除零)流程不变。

测试保障:从回归到梯度检查

Kornia 为这次修复配套了密集的测试,可在 tests/geometry/test_homography.py 中查看:

  • test_zero_weight_minimal_lu(tests/geometry/test_homography.py):用[1,1,1,0]、[1,1,0,0]、全零三种权重配置断言结果全部有限,且混合 batch 中健康样本的结果不受退化样本影响——防止 NaN 经 RANSAC 验证链路静默传播;
  • test_scaled_fixed_points(tests/geometry/test_homography.py):目标点放大 100 倍的极端缩放场景,验证lu路径有限且重投影闭环正确;
  • test_projective_fixed_points(tests/geometry/test_homography.py):专门守护自适应 Gauge 本身,覆盖h33 ≈ 0的投影退化配置;
  • test_gradcheck_lu_minimal(tests/geometry/test_homography.py):对最小四点lu路径做梯度检查(gradcheck),保证find_homography_dlt保持可微——这一点对端到端可学习管线至关重要;
  • test_nocrash_lu(tests/geometry/test_homography.py):输入含 NaN 点时不崩溃,保持形状输出。

此外,半精度已知失败清单testing/half_precision_xfails/cpu_bfloat16.txt与cpu_float16.txt中不再包含最小四点lu路径的失败条目,印证了"移除相应 CPU 半精度已知失败"的变更声明。

使用与验证建议

参数说明

find_homography_dlt的签名与参数(kornia/geometry/homography.py):

参数类型默认值说明
points1Tensor(B, N, 2)—第一幅图像的点集,N ≥ 4,否则抛AssertionError
points2Tensor(B, N, 2)—第二幅图像的点集,形状须与points1一致
weightsTensor(B, N)或NoneNone每个点对应的权重;None表示等权
solverstr"lu"可选"svd"或"lu";仅lu且N == 4时走新 Gauge 路径

实操建议

  • 默认solver="lu"即可获得新算法的全部收益:四点最小样本自动走自适应 Gauge 路径,五点以上自动回落正规方程;
  • 若你的应用主要依赖五点以上样本(例如直接调用find_homography_dlt而非 RANSAC),结果与修复前保持一致,无需改动;
  • 若你自定义了基于RANSAC的单应矩阵管线,建议重新跑一遍回归测试并复核精度指标(传输残差、内点率),因为所有平台的最小样本估计结果都有数值变化;
  • 需要更高数值余量时仍可显式选择solver="svd",它在奇异与近奇异配置下同样稳健,但开销更大、且不与新 Gauge 路径共享实现。

本次修复是 Kornia 几何核心层一次典型的"小函数、大影响"变更:find_homography_dlt一个函数的行为调整,通过RANSAC的minimal_solver调用链辐射到所有单应矩阵估计场景,用自适应齐次 Gauge 从根上消除了最小四点系统的奇异数值路径。

  • 计算机视觉
  • 深度学习
  • 图像处理

【免费下载链接】kornia

🐍 Geometric Computer Vision Library for Spatial AI

项目地址:https://gitcode.com/GitHub_Trending/ko/kornia
点击查看免费下载

相关推荐

上一篇:PHPStan new.internalTrait 错误标识符深度解析:实例化 @internal trait 的静态分析与修复方案
下一篇:CephFS Top Utility(cephfs-top)实战指南:Ceph 文件系统实时性能监控完全解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表