像素约束、三角化与深度不确定性
现在已经有两张图的候选对应与各自相机矩阵,本章求未知世界位置。输入只有像素、相机和匹配记录,不含珠子三维真值。理想情况下两条世界射线相交于同一点;检测噪声下通常不严格相交,需要一个明确的近似目标。我们先求线性齐次三角化,再检查正深度和像素残差,最后讲怎样用几何误差精化。不存在“给两个点便必定有可信深度”的无条件定理。
令未知齐次三维点为四维向量,左相机三行记为 P 的行向量,右相机记为 Q。与 DLT 相同,左像素横坐标乘第三行减第一行、纵坐标乘第三行减第二行,各与未知点点积等于零;右图再贡献两行。四行堆成四乘四矩阵 A,寻找单位长度的近似零空间向量,再用第四分量除前三分量,得到欧氏位置。若第四分量接近零,点可能趋于无穷远或几何退化,不能直接除出巨大数字冒称成功。
奇异值分解给最小代数残差方向,作用与上一章相机 DLT 相似,但这次未知是一个点而不是相机。对每个点求出位置后,重新投影到左右相机,计算两个二维像素残差平方和的一半再开根号,作为每视角二维 RMS。项目门槛是一像素。门槛是固定规则,不是后验地调到所有输出都通过;超过门槛的候选被明确记录为拒绝。
正深度检查独立于残差。某个三维点可以在数学上投影到两个像素,却位于一台相机背后,不能解释正常针孔可见观测。项目投影函数遇到非正深度直接拒绝。因此正常轨迹须同时满足描述子、极线、有限齐次位置、正深度与重投影。即便这些条件全过,也仍可能是一个外观重复、几何自洽的错物体,所以输出保留原始观测与匹配距离,不把门槛提升为身份证明。
算例一:平行双目的米制深度
先看容易手算的特殊情况,两相机同姿态、内参相同、右相机中心横移基线 B。左归一化横坐标是 X 除 Z,右边是 X 减 B 后除 Z;相减得到 B 除 Z。乘像素焦距 f,视差 d 等于 fB 除 Z,所以 Z 等于 fB 除 d。设焦距一百像素、基线零点二米、视差十像素,深度为二米。若左横像素距主点十五,则 X 为十五乘二除一百,即零点三米。
在同一设置下,视差误差零点二像素的一阶深度误差幅度是二十除一百乘零点二,即零点零四米。若真实深度改为十米,视差只有二像素,同样零点二像素对应约一米误差。图像测量看起来同样精细,远处深度却明显更不稳定。减小基线也会降低视差。误差公式揭示采集几何限制,不能靠在结果表中增加小数位修复。
独立左右横坐标误差若各有方差 s 平方,视差误差方差是二 s 平方;若二者相关,还要减去两倍协方差。深度局部方差近似为深度导数平方乘视差方差。这是小噪声一阶传播,不是所有噪声分布下的精确后验;视差接近零时函数非线性强,可能出现偏斜长尾甚至无效深度。此时更适合报告区间、拒绝或保留射线,而不是把线性标准差当完整可信范围。
算例二:低重投影误差与错误绝对尺度
假设两个相机中心和所有真实点共同放大十倍,旋转与内参保持原值。每个相机中的相对位置也放大十倍,透视除法全部抵消,因此重投影误差可以仍为零;但输出单位若继续声称米,真实尺寸错十倍。这一失败不靠更多图像残差就能发现,需要已知标靶尺寸、基线或独立长度检查。项目用米制非共面靶给相机尺度,因此三维 RMS 才具有米单位含义。
项目从前两张训练图片提取十二条匹配,按一般旋转相机矩阵重建。评价阶段才读取真值,对颜色身份建立参照,三角化位置 RMS 实测约零点零零二九零八米。该数值使用有限受控场景,没有遮挡与真实镜头畸变,不能外推为自然场景毫米级能力。逐点误差也保存,最大点与平均不同,任何看似精确的整体均值都不能替代逐点检查。
若要几何精化,可以直接最小化各视角像素残差平方和。设位置增量为三维向量,投影在当前点附近以雅可比 J 线性化,残差变成 r 加 J 乘增量。展开平方并对增量求导,正规方程为转置 J 乘 J 再乘增量,等于负转置 J 乘 r。求解后更新位置并重新检查真实目标;过大步长可能离开局部线性范围,需要阻尼或回溯,不能假定一次线性解就是最优。
若同时优化相机与所有点,就得到束调整问题。它的目标来自同一重投影残差,但引入共同坐标变换与尺度自由度,必须固定一个参考相机和尺度或其他约束。相机旋转还要用合法参数更新,不能把九个矩阵元素当自由数而任其失去正交。当前项目不运行完整束调整,而在固定标定相机下拟合小型发光 Gaussian 场景;这两种优化目标和参数范围必须区分。
残差通过后再问:哪些方向仍没有足够信息
将基线改为0.0001米、焦距95像素,真点(0.1,0.1,4)在平行双目中的视差只有.002375像素。若右图横坐标增加.002像素,剩余视差为.000375,重算深度95×.0001/.000375=25.3333米。两个射线仍能精确相交,因此重投影RMS可接近零。这是“找到一个几何自洽点”与“精确知道深度”的区别,不应被成功布尔值抹掉。
一般旋转时不依赖平行视差公式,直接对四个像素预测关于三维位置求雅可比J。它为4×3矩阵,第i个相机的某一坐标导数是(P行前三项−该像素坐标×P第三行前三项)/深度。若局部像素误差独立、同方差s²,并暂把相机当已知,线性化最小二乘的协方差近似为s²(JᵀJ)逆。J的最小奇异值越小,最弱三维方向越难确定;最大位置标准差为s除最小奇异值。
现在主重建报告中每条轨迹包含geometry_diagnostics:基线、两条射线夹角、基线/距离比、J的奇异值、假设像素噪声及最大位置标准差。默认假设s=.1像素,并把最大位置标准差/到相机中点距离超过.25的轨迹标为weak_geometry;否则只称locally_constrained,不称真值可信。阈值与噪声均作为参数显式记录。弱几何仍可作为待补观测点保留,但不能与充分约束轨迹同等无条件解读;有实际应用容差时,应由容差制定拒绝策略。
这个诊断没有加入相机标定误差、非高斯离群点和身份错配,也没有在强非线性小视差处把线性近似升级为精确后验。它提供可检查的局部信息量,不是安全保证。当前主场景无需重训即可重新输出诊断;旧180步拟合报告和检查点作为原冻结实验保留,新增诊断与回归另存,避免把新源码散列冒充旧实验原始来源。
import numpy as np
from vision3d.core import triangulate
K=np.array([[95.,0,48],[0,95,40],[0,0,1]])
P=K@np.c_[np.eye(3),np.zeros(3)]
Q=K@np.c_[np.eye(3),np.array([-.0001,0,0])]
x=np.array([.1,.1,4.,1.])
def pixel(M):
y=M@x
return y[:2]/y[2]
u,v=pixel(P),pixel(Q);v[0]+=.002
point,error,_,diagnostic=triangulate(u,v,P,Q,return_diagnostics=True)
assert abs(point[2]-25.3333333333)<1e-6 and error<1e-9
assert diagnostic['geometry_status']=='weak_geometry'
print('depth',point[2],'rms',error,'uncertainty',diagnostic)
噪声、错配和弱基线需要不同处理。噪声可通过重复观测和合理权重减少,错配适合鲁棒损失或离群拒绝,弱基线需要增加视点几何信息。把所有残差统一乘很小的权重会让报告看似好看,却不会恢复缺失信息。鲁棒损失也可能忽略真正复杂区域,因此需保留被降权的观测与理由。当前一像素门槛只作教学可检查版本,不宣称统计最优。
输出点云还必须说明哪些东西没有重建。这里只有能在至少两图中被检测和正确匹配的亮斑中心,不包含珠子背面纹理、场景表面、隐藏物体和任意实心体积。点之间连线不自动成为网格边,点的凸包也不自动代表真实物体外壳。下一章讨论表示时会将这种几何中心信息与渲染假设分开,避免从稀疏点凭空推断连续表面。
可以用已知精确投影建立独立的算法正向控制:任取一般旋转的两个相机与一个前方点,用前向函数生成无噪声像素,再三角化检查位置。这个测试只证明数值公式与投影约定匹配。另一个删除真值文件仍能重建的测试证明信息边界;真实 PNG 的几何 RMS 则测整个观测链。三种证据回答不同问题,不能把最容易的精确投影测试包装成实际图像管线质量。
对多于两视角的点,可把每视角两行约束继续堆叠,求同一个近似零空间向量。多观测可能改善抗噪声,但新增错配也会拖偏全部结果。合理方案先检查每视角残差,保留可见性与匹配置信信息,再进行鲁棒重估;不能因为方程数量增加就保证质量提升。当前项目三角化明确只用前两图,因此第三图的光度拟合是新的约束,而非把未使用的多视角线性重建写成既成事实。
f,B,d=100.,.2,10.
Z=f*B/d
linear=-(f*B/d**2)*.2
exact=f*B/(d+.2)-Z
assert Z==2.0
print({'depth_m':Z,'linear_delta_m':linear,'exact_delta_m':exact})TRY IT YOURSELF
练习一:基线改变
焦距一百像素、深度五米,基线从零点二米变成零点零二米。视差各多少?同为零点一像素误差时深度一阶误差各多少?
提示 1
提示 2
对照参考解答
TRY IT YOURSELF
练习二:几何残差单位
左右二维像素残差长度分别三与四。项目定义的每视角 RMS 是多少?若按四个坐标平均再开根号又是多少,为什么不能混用?
提示 1
提示 2
对照参考解答
TRY IT YOURSELF
练习三:纯旋转
两个相机中心相同、姿态不同,为什么通常不能靠两个观测恢复射线上的深度?低重投影误差能否解决?