世界坐标、相机坐标与针孔投影
第一章得到的是像素位置,本章建立它与三维位置的函数关系。模型输入是世界点 X、相机内参 K、旋转 R 和平移 t,输出横纵像素。世界坐标单位为米,世界轴约定横向右、纵向下、深度向前。相机也用右、下、前的右手坐标;这是约定而非每个图形软件的默认值。三维向量先写成列向量,代码批量保存为行时要在乘法中转置,不能凭数组形状相容判断几何正确。
相机中心 C 是世界中的位置,旋转 R 的三行分别表示相机右、下、前方向在世界中的分量。世界点相对中心的位移先减 C,再由 R 取各轴投影。因此相机坐标是 R 乘 X 减 C,若写成 R X 加 t,则 t 等于负 R C。t 不是一般意义下的相机中心,把二者混用会在相机转动时产生错误。已知 R、t 的逆关系是 C 等于负转置 R 乘 t。
合法旋转保持长度和朝向。其转置乘自身应为单位阵,行列式为正一;行列式负一的正交阵包含镜像,不是纯旋转。逆旋转用转置,原因是正交条件给出它与原阵乘积等于单位阵。一个向量绕不同轴旋转时,矩阵乘法顺序决定先后;绕世界轴转与绕随物体运动的局部轴转也不是同一个操作。项目直接建立相机基,不在旋转参数名称上猜约定。
look_at 构造首先把目标减中心得到前向单位向量,再把世界向下方向与前向叉乘并归一化得到右向;前向叉乘右向得到相机下向。叉乘顺序使右叉下等于前,从而维持右手性。若前向与预选向下方向平行,第一步叉乘为零,必须选另一个参考轴或报错。项目的五个相机避开这个退化,但通用实现仍需知道该边界,不能把归一化零向量的非有限值静默传下去。
针孔模型是本课采用的理想成像假设,不是从所有镜头的物理定律直接得出的精确结论。在相机前方放一张数学成像平面,令深度为焦距;相似三角形给归一化坐标为相机横坐标除深度、纵坐标除深度。再乘像素焦距并加主点。主点是光轴与图像平面交点,未必等于图片中心;本合成器把它设在宽高一半。焦距用像素,不与世界坐标的米混单位。
矩阵 P 为三乘四,合并内参与外参。齐次像素是三维向量,最终必须除第三分量;把它当普通三维位置会丢失透视除法。由于齐次向量乘任意非零标量表示同一像素,P 整体乘常数不会改变投影。相反,深度正负具有可见性含义:Z 等于零时投影奇异,负值位于相机背后。本项目拒绝背后点,不把其数学像素位置当有效图像观测。
算例一:投影与整体尺度歧义
设相机没有旋转,中心为原点,两个像素焦距都是九十五,主点为四十八与四十。世界点一、零点五、五的相机深度为五,所以横像素四十八加十九等于六十七,纵像素四十加九点五等于四十九点五。把点的三个坐标同时乘二,归一化比值不变,得到完全相同像素。单个视角不能据像素独自决定点在射线上的距离;低图像误差也不保证米制尺寸正确。
若相机中心横向移动零点五,姿态仍不变,原点相对相机横坐标降为零点五,横像素变为五十七点五,而纵像素不变。这次只动相机,世界点不动,所以投影改变。若把所有世界点和所有相机中心一同乘二,二者差向量也整体乘二,像素又保持不变。这就是仅靠未知尺度的图像重建会有的整体尺度自由度;已知米制标定靶或基线才能固定它。
算例二:旋转不是平移的别名
考虑绕相机纵轴九十度的矩阵,三行分别是零零一、零一零、负一零零。它把世界向量一零零变为零零负一,把零零一变为一零零;长度均保持,行列式正一。相机中心若为一零零,则 t 等于零零一,而不是负一零零。世界点二零二减中心给一零二,再旋转成二零负一,位于背后,必须拒绝投影。忽略姿态直接套水平视差公式会错得有条不紊。
投影对位置的敏感性可以直接求导。横像素对相机横坐标的导数为焦距除深度,对深度的导数为负焦距乘横坐标除深度平方;纵向同理。把这两行组成二乘三雅可比 J,再乘 R 就得到对世界位置的导数。小扰动时像素变化近似 J 乘位置变化,误差是扰动的二阶量;深度接近零时导数很大,小位置误差可能被强烈放大,所以正深度还不等于数值安全。
在真实镜头中,理想归一化坐标还会经过畸变。最小径向模型把横纵坐标同时乘一加 k 乘半径平方,半径平方是归一化横纵坐标平方和。它使边缘误差通常大于中心误差。畸变参数不是平移参数,不能总靠移动三维点吸收。这里生成器明确设畸变为零,项目不声称完成现实镜头的完整标定;换入相机照片必须增加畸变估计或先校正,并验证残差的空间分布。
改变图片分辨率也会影响内参。把图像横纵都放大两倍,像素焦距与主点也要乘二,世界点和相机米制位置不变。只放大图片却复用旧 K,会得到系统性投影误差。若非等比例缩放,两个方向分别更新焦距和主点。裁剪则改变主点偏移。这样的预处理应写入图像清单,否则后续可能把一个数据处理问题错误诊断成三维模型不足。
本项目先利用已知非共面标定靶估一般 P,再三角化未知珠子,没有将所有相机假定为平行双目。渲染阶段使用已知焦距像素尺度和标定 P 的深度归一化;这是一项公开的标定条件,不是无标定结构恢复。相机矩阵的正交性、中心零点、已知投影及背后点拒绝形成不同检查,任何单项都不能替代整组检查。下一章将明确 P 怎样从带误差的像素对应估出。
旋转组合可用两个轴的九十度实例检查非交换性。先把向右单位向量绕纵轴转到负前向,再绕横轴转,会落在另一方向;调换顺序时第一步横轴旋转不改变向右向量,第二步仍把它转成负前向,结果不同。代码里矩阵乘积最右侧先作用于列向量,因此书写顺序与自然语言的先后需要对应。相机多层坐标变换应在每个矩阵上标明输入与输出坐标系,维度相同并不足以允许任意相乘。
从像素恢复一条世界射线时,先以 K 的逆作用于齐次像素得到相机方向,再乘 R 的转置回到世界方向,射线原点为 C。方向可归一化,不改变射线集合;距离参数必须为正才在相机前方。把这个方向重新代入投影,无论沿射线走多少正距离都应回到同一像素。该往返检查既核对转置方向,也再次展示单视角缺少深度,后续两视角不是重复同一条信息。
from vision3d.core import look_at,project
import numpy as np
P,R=look_at([0,0,0])
u,z=project([[1,.5,5]],P)
np.testing.assert_allclose(u,[[67,49.5]])
np.testing.assert_allclose(R@R.T,np.eye(3))
print(u,z)TRY IT YOURSELF
练习一:恢复相机中心
已知旋转矩阵是绕纵轴九十度的上述矩阵,平移为零、零、一。求世界中心并验证中心投到齐次零向量。
提示 1
提示 2
对照参考解答
TRY IT YOURSELF
练习二:深度敏感性
焦距一百像素、相机横坐标一米、深度五米。深度增加零点零一米时横像素的一阶变化多少?精确比值可怎样检查?
提示 1
提示 2
对照参考解答
TRY IT YOURSELF
练习三:图像缩放
原焦距九十五,主点四十八与四十,图像先各向放大两倍,再从左侧裁掉十像素、上方裁掉六像素。新内参是什么,三维尺度是否变化?