三角化:Triangulation: Why Optimize?

Reference:

  1. GitHub:openMVG
  2. Triangulation: Why Optimize?

1. 预备知识

在这里插入图片描述

  • 向量 v \mathbf{v} v 的欧几里得范数: ∥ v ∥ \| \mathbf{v}\| v
  • 单位向量: v ^ = v / ∥ v ∥ \hat{\mathbf{v}} =\mathbf{v}/ \| \mathbf{v}\| v^=v/∥v
  • 两条线 L 0 \mathbf{L_0} L0 L 1 \mathbf{L_1} L1 间角度: ∠ ( L 0 , L 1 ) ∈ [ 0 , π / 2 ] \angle(\mathbf{L}_0,\mathbf{L}_1)\in[0,\pi/2] (L0,L1)[0,π/2]
  • 定义 x 0 = [ x 0 , y 0 , z 0 ] T \mathbf{x_0}=[x_0, y_0, z_0]^T x0=[x0,y0,z0]T x 1 = [ x 1 , y 1 , z 1 ] T \mathbf{x_1}=[x_1, y_1, z_1]^T x1=[x1,y1,z1]T 分别为相机参考系 C 0 C_0 C0 C 1 C_1 C1 的三维坐标;
  • R \mathbf{R} R t \mathbf{t} t 为两相机间的旋转和位移,则 x 1 = R x 0 + t \mathbf{x}_1=\mathbf{R}\mathbf{x}_0+\mathbf{t} x1=Rx0+t
  • 相机标定矩阵: K \mathbf{K} K
  • 每帧点观测到的其次像素坐标: u 0 = ( u 0 , v 0 , 1 ) ⊺ \mathbf{u}_{0}=(u_{0},v_{0},1)^{\intercal} u0=(u0,v0,1) u 1 = ( u 1 , v 1 , 1 ) ⊺ \mathbf{u}_{1}=(u_{1},v_{1},1)^{\intercal} u1=(u1,v1,1)
  • 归一化图像坐标: f 0 = [ x 0 / z 0 , y 0 / z 0 , 1 ] T \mathbf{f_{0}}=\left[x_{0}/z_{0},y_{0}/z_{0},1\right]^{T} f0=[x0/z0,y0/z0,1]T f 1 = [ x 1 / z 1 , y 1 / z 1 , 1 ] T \mathbf{f_{1}}=\left[x_{1}/z_{1},y_{1}/z_{1},1\right]^{T} f1=[x1/z1,y1/z1,1]T,分别由 f 0 = K − 1 u 0 \mathbf{f}_0=\mathbf{K}^{-1}\mathbf{u}_0 f0=K1u0 f 1 = K − 1 u 1 \mathbf{f}_1=\mathbf{K}^{-1}\mathbf{u}_1 f1=K1u1 得到;
  • 在 Fig.1a 的理想情况下,两个反向投影的光线相交,满足对极约束: f 1 ⋅ ( t × R f 0 ) = 0 \mathbf{f}_1\cdot(\mathbf{t}\times\mathbf{Rf}_0)=0 f1(t×Rf0)=0(SLAM十四讲 P167, x 2 T t ∧ R x 1 = 0 \mathbf{x_2}^Tt^{\wedge}\mathbf{R}\mathbf{x_1}=0 x2TtRx1=0);
  • 给定上图的深度标量 λ 0 \lambda_0 λ0 λ 1 \lambda_1 λ1,交点 x 1 \mathbf{x_1} x1 的公式为: x 1 = λ 0 R f 0 ^ + t \begin{aligned}\mathbf{x}_{1}& =\lambda_0\mathbf{R}\mathbf{\hat{f_0}}+\mathbf{t} \end{aligned} x1=λ0Rf0^+t x 1 = λ 1 f 1 ^ \begin{aligned}\mathbf{x}_{1}& =\lambda_1\mathbf{\hat{f_1}}\end{aligned} x1=λ1f1^。( f 0 ^ \mathbf{\hat{f_0}} f0^ f 1 ^ \mathbf{\hat{f_1}} f1^ 为理想值,由于图像测量和相机模型的不准确,这种情况很少发生。要从两条倾斜的光线推断三维点,就引出了下面的方法);

1.1 评估 3D 点准确性

一旦使用某种三角测量方法获得 3D 点 x 1 ′ \mathbf{x}_{1}' x1 的估计,就可以以多种方式评估其准确性:

  1. 计算 3D 误差,即: e 3 D = ∥ x 1 ′ − x t r u e ∥ e_{3D}=\|\mathbf{x}_1^\prime-\mathbf{x}_{\mathrm{true}}\| e3D=x1xtrue(见 Fig.1b);
  2. 计算 2D 误差,也就是重投影误差:
    d i = ∥ K ( f i − f i ′ ) ∥ = ∥ K ( f i − ( [ 0   0   1 ] x i ′ ) − 1 x i ′ ) ∥ for i = 0 , 1 ( 1 ) d_i=\|\mathbf{K}\left(\mathbf{f}_i-\mathbf{f}_i'\right)\|=\left\|\mathbf{K}\left(\mathbf{f}_i-\left(\left[\mathbf{0}\text{ }\mathbf{0}\text{ }\mathbf{1}\right]\mathbf{x}_i'\right)^{-1}\mathbf{x}_i'\right)\right\|\quad\text{for}\quad i=0,1 \quad(1) di=K(fifi)= K(fi([0 0 1]xi)1xi) fori=0,1(1)其中 x 0 ′ = R ⊺ ( x 1 ′ − t ) \mathbf{x}'_0=\mathbf{R}^\intercal(\mathbf{x}'_1-\mathbf{t}) x0=R(x1t)。这里 ( [ 0   0   1 ] x i ′ ) − 1 \left(\left[\mathbf{0}\text{ }\mathbf{0}\text{ }\mathbf{1}\right]\mathbf{x}_i'\right)^{-1} ([0 0 1]xi)1 求的是 z z z 轴坐标的逆,再乘上 x 1 ′ \mathbf{x}'_1 x1 可得归一化平面坐标(见 Fig.1b);
    2D 误差表示与测量的偏差,而 3D 误差表示与真实值的偏差。与 3D 误差不同,3D 点的 2D 误差可以在不同范数下评估,如:
    • L 1 L_1 L1 范数: d 0 + d 1 d_0+d_1 d0+d1
    • L 2 L_2 L2 范数: d 0 2 + d 1 2 \sqrt{d_0^2+d_1^2} d02+d12
    • L ∞ L_\infty L 范数: max ⁡ ( d 0 , d 1 ) \max(d_0,d_1) max(d0,d1)
  3. 除了 2D 和 3D 精度外,还可以评估得到的视差角精度(见 Fig.1c),视差误差定义如下(这里的表示感觉有点迷, x t r u e \mathbf{x}_{\mathrm{true}} xtrue 说的应该是 C 1 C_1 C1 x t r u e \mathbf{x}_{\mathrm{true}} xtrue 的直线,而 x t r u e − t \mathbf{x}_{\mathrm{true}}-\mathbf{t} xtruet C 0 C_0 C0 x t r u e \mathbf{x}_{\mathrm{true}} xtrue 的直线):
    e β = ∣ β t r u e − β ′ ∣ = ∣ ∠ ( x t r u e , x t r u e − t ) − ∠ ( x 1 ′ , x 1 ′ − t ) ∣ ( 2 ) e_{\beta}=|\beta_{\mathrm{true}}-\beta'|=|\angle\left(\mathbf{x}_{\mathrm{true}},\mathbf{x}_{\mathrm{true}}-\mathbf{t}\right)-\angle\left(\mathbf{x}'_1,\mathbf{x}'_1-\mathbf{t}\right)| \quad(2) eβ=βtrueβ=∣∠(xtrue,xtruet)(x1,x1t)(2)将“原始视差”定义为原始反投影光线之间的角度:
    β r a w = ∠ ( R f 0 , f 1 ) . ( 3 ) \beta_{\mathrm{raw}}=\angle\left(\mathbf{Rf}_0,\mathbf{f}_1\right). \quad(3) βraw=(Rf0,f1).(3)这给出了独立于平移和三角化方法的视差角粗略估计。

2. 提出的方法

2.1 广义加权中点法

广义加权中点法 Generalized Weighted Midpoint (GWM) 包含以下三个步骤:

  1. 给定对应于同一点的两个反向投影光线,使用一些方法估计两条光线 ( λ 0 , λ 1 ) (\lambda_0, \lambda_1) (λ0,λ1) 的深度;
  2. 计算这两条深度为 λ 0 \lambda_0 λ0 λ 1 \lambda_1 λ1 的光线的 3D 点,也就是在 C 1 C_1 C1 帧的 t + λ 0 R f 0 ^ \mathbf{t} + \lambda_0\mathbf{R}\mathbf{\hat{f_0}} t+λ0Rf0^ λ 1 f 1 ^ \lambda_1\mathbf{\hat{f_1}} λ1f1^
  3. 通过计算它们的加权平均来获得 3D 点的最终估计。

以前经典的中点方法是,每条光线的两个点是有着相同权重的最接近点对。而下图展示了广义加权中点的另一个可能的示例:
在这里插入图片描述

2.2 可选的中点法

这里提出一种属于 GWM 的可选中点法。首先考虑两个反向投影碰巧相交的情况,如 Fig.1a。在这种情况下,最合理的解决方案是交点,可以使用正弦规则获得沿射线的对应深度:
λ 0 = sin ⁡ ( ∠ ( f 1 , t ) ) sin ⁡ ( ∠ ( R f 0 , f 1 , ) ) ∥ t ∥ = ∥ f ^ 1 × t ∥ ∥ R f ^ 0 × f ^ 1 ∥ , λ 1 = sin ⁡ ( ∠ ( R f 0 , t ) ) sin ⁡ ( ∠ ( R f 0 , f 1 , ) ) ∥ t ∥ = ∥ R f ^ 0 × t ∥ ∥ R f ^ 0 × f ^ 1 ∥ . ( 4 ) \lambda_0=\frac{\sin\left(\angle\left(\mathbf{f}_1,\mathbf{t}\right)\right)}{\sin\left(\angle\left(\mathbf{R}\mathbf{f}_0,\mathbf{f}_1,\right)\right)}\|\mathbf{t}\|=\frac{\|\hat{\mathbf{f}}_1\times\mathbf{t}\|}{\|\mathbf{R}\hat{\mathbf{f}}_0\times\hat{\mathbf{f}}_1\|},\quad\lambda_1=\frac{\sin\left(\angle\left(\mathbf{R}\mathbf{f}_0,\mathbf{t}\right)\right)}{\sin\left(\angle\left(\mathbf{R}\mathbf{f}_0,\mathbf{f}_1,\right)\right)}\|\mathbf{t}\|=\frac{\|\mathbf{R}\hat{\mathbf{f}}_0\times\mathbf{t}\|}{\|\mathbf{R}\hat{\mathbf{f}}_0\times\hat{\mathbf{f}}_1\|}. \quad(4) λ0=sin((Rf0,f1,))sin((f1,t))t=Rf^0×f^1f^1×t,λ1=sin((Rf0,f1,))sin((Rf0,t))t=Rf^0×f^1Rf^0×t.(4)在两条光线是倾斜的时候,也使用该公式估计深度。分别计算 3D 点在每条光线上的深度 λ 0 \lambda_0 λ0 λ 1 \lambda_1 λ1,得:
t + λ 0 R f ^ 0 = t + ∥ f 1 × t ∥ ∥ R f 0 × f 1 ∥ R f 0 and λ 1 f 1 ^ = ∥ R f 0 × t ∥ ∥ R f 0 × f 1 ∥ f 1 ( 5 ) \mathbf{t}+\lambda_0\mathbf{R}\hat{\mathbf{f}}_0=\mathbf{t}+\frac{\|\mathbf{f}_1\times\mathbf{t}\|}{\|\mathbf{Rf}_0\times\mathbf{f}_1\|}\mathbf{Rf}_0\quad\text{and}\quad\lambda_1\hat{\mathbf{f_1}}=\frac{\|\mathbf{Rf}_0\times\mathbf{t}\|}{\|\mathbf{Rf}_0\times\mathbf{f}_1\|}\mathbf{f}_1 \quad(5) t+λ0Rf^0=t+Rf0×f1f1×tRf0andλ1f1^=Rf0×f1Rf0×tf1(5)取这两个点的中点有:
x 1 ′ = 1 2 ( t + ∥ f 1 × t ∥ ∥ R f 0 × f 1 ∥ R f 0 + ∥ R f 0 × t ∥ ∥ R f 0 × f 1 ∥ f 1 ) . ( 6 ) \mathbf{x}_1'=\frac{1}{2}\left(\mathbf{t}+\frac{\|\mathbf{f}_1\times\mathbf{t}\|}{\|\mathbf{R}\mathbf{f}_0\times\mathbf{f}_1\|}\mathbf{R}\mathbf{f}_0+\frac{\|\mathbf{R}\mathbf{f}_0\times\mathbf{t}\|}{\|\mathbf{R}\mathbf{f}_0\times\mathbf{f}_1\|}\mathbf{f}_1\right). \quad(6) x1=21(t+Rf0×f1f1×tRf0+Rf0×f1Rf0×tf1).(6) p = R f ^ 0 × f ^ 1 \mathbf p=\mathbf R\hat{\mathbf f}_0\times\hat{\mathbf f}_1 p=Rf^0×f^1 q = R f ^ 0 × t \mathbf q=\mathbf R\hat{\mathbf f}_0\times\mathbf t q=Rf^0×t 以及 r = f ^ 1 × t \mathbf r=\hat{\mathbf f}_1\times\mathbf t r=f^1×t,深度公式可替换为:
λ 0 = ∣ ∣ r ∣ ∣ ∣ ∣ p ∣ ∣ , λ 1 = ∣ ∣ q ∣ ∣ ∣ ∣ p ∣ ∣ ( 7 ) \lambda_{0}={\frac{||\mathbf{r}||}{||\mathbf{p}||}},\quad\lambda_{1}={\frac{||\mathbf{q}||}{||\mathbf{p}||}} \quad(7) λ0=∣∣p∣∣∣∣r∣∣,λ1=∣∣p∣∣∣∣q∣∣(7)这些形式类似于以前经典的中点法给出的深度:
λ mid 0 = p ^ ⋅ r ∥ p ∥ , λ mid 1 = p ^ ⋅ q ∥ p ∥ . ( 8 ) \lambda_{\text{mid}0}=\frac{\hat{\mathbf{p}}\cdot\mathbf{r}}{\|\mathbf{p}\|},\quad\lambda_{\text{mid}1}=\frac{\hat{\mathbf{p}}\cdot\mathbf{q}}{\|\mathbf{p}\|}. \quad(8) λmid0=pp^r,λmid1=pp^q.(8)这两种公式的不同之处在于分子,equ.7 有大小 r \mathbf{r} r q \mathbf{q} q,而 equ.8 将它们投影到 p \mathbf{p} p 上。因此,我们总是得到 λ 0 ≥ λ mid 0 \lambda_0\geq \lambda_{\text{mid}0} λ0λmid0 λ 1 ≥ λ mid 1 \lambda_1\geq \lambda_{\text{mid}1} λ1λmid1。在大多数情况下,这意味着该方法得到的中点会比经典中点更远。在 Fig.2 描述的例子里,当我们估计一个远离相机的点时,通常(传统三角化方法)会导致估计的视差角较小。

2.3 Cheirality(多视图几何中代表着3D点的正景深约束)

在这里插入图片描述当三角化的点有负深度时,违反了 3D 点的正景深约束。这可能有很多原因产生,如点对的关联错了或极点附近的图像点有噪声。通常它不会造成严重的问题,因为可以很轻易检查每个点的正景深并抛弃坏点。对于经典的中点方法,可以通过检查 equ.8 给出的深度符号确认。但对于该文中给出的方法是不能这样确认的,因为给出的深度总为正。上图说明了两种方法间的差异。因此在该方法中,仅靠深度不能说明三角测量的结果是否可靠。

这时需要使用其他方法来测试该点是否为坏点(满足以下不等式即为坏点):如果将至少一个深度的符号改为负会导致光线上两点间距变小,则抛弃这个点的对应关系:
∥ t + λ 0 R f 0 ^ − λ 1 f ^ 1 ∥ 2 ≥ min ⁡ ( ∥ t + λ 0 R f 0 ^ + λ 1 f 1 ^ ∥ 2 , ∥ t − λ 0 R f 0 ^ − λ 1 f ^ 1 ∥ 2 , ∥ t − λ 0 R f 0 ^ + λ 1 f 1 ^ ∥ 2 ) ( 9 ) \|\mathbf{t}+\lambda_0\mathbf{R}\hat{\mathbf{f_0}}-\lambda_1\hat{\mathbf{f}}_1\|^2\geq\min\left(\|\mathbf{t}+\lambda_0\mathbf{R}\hat{\mathbf{f_0}}+\lambda_1\hat{\mathbf{f_1}}\|^2,\|\mathbf{t}-\lambda_0\mathbf{R}\hat{\mathbf{f_0}}-\lambda_1\hat{\mathbf{f}}_1\|^2,\|\mathbf{t}-\lambda_0\mathbf{R}\hat{\mathbf{f_0}}+\lambda_1\hat{\mathbf{f_1}}\|^2\right)\quad(9) t+λ0Rf0^λ1f^12min(t+λ0Rf0^+λ1f1^2,tλ0Rf0^λ1f^12,tλ0Rf0^+λ1f1^2)(9)对于经典的中点法,令 λ 0 = ∣ λ m i d 0 ∣ \lambda_0=|\lambda_{mid0}| λ0=λmid0 λ 1 = ∣ λ m i d 1 ∣ \lambda_1=|\lambda_{mid1}| λ1=λmid1 可以有效得到与检验正景深约束相同的结果(显而易见,都是验证这个数是不是大于零的)。而现方法在 equ.9 在 Fig.3a 成立,是因为当 λ 0 = − ∣ λ m i d 0 ∣ \lambda_0=-|\lambda_{mid0}| λ0=λmid0 λ 1 = − ∣ λ m i d 1 ∣ \lambda_1=-|\lambda_{mid1}| λ1=λmid1 时两点最接近。

2.4 逆深度加权中点-Inverse Depth Weighted(IDW) Midpoint

equ.6 给出的为加权中点通常会导致两幅图像不成比例的重投影误差,Fig.3c 给出了一个例子。注意具有较小深度的光线往往会产生较大的重投影误差。为了补偿这种不平衡,文中建议使用逆深度作为权重:
x 1 ′ = λ 0 − 1 ( t + λ 0 R f 0 ^ ) + λ 1 − 1 ( λ 1 k 1 ^ ) λ 0 − 1 + λ 1 − 1 = ∥ q ∥ ∥ q ∥ + ∥ r ∥ ( t + ∥ r ∥ ∥ p ∥ ( k f 0 ^ + f 1 ^ ) ) ( 10 ) \mathbf{x}_1'=\frac{\lambda_0^{-1}\left(\mathbf{t}+\lambda_0\mathbf{R}\hat{\mathbf{f_0}}\right)+\lambda_1^{-1}\left(\lambda_1\hat{\mathbf{k_1}}\right)}{\lambda_0^{-1}+\lambda_1^{-1}}=\frac{\|\mathbf{q}\|}{\|\mathbf{q}\|+\|\mathbf{r}\|}\left(\mathbf{t}+\frac{\|\mathbf{r}\|}{\|\mathbf{p}\|}\left(\mathbf{k}\hat{\mathbf{f_0}}+\hat{\mathbf{f_1}}\right)\right)\quad(10) x1=λ01+λ11λ01(t+λ0Rf0^)+λ11(λ1k1^)=q+rq(t+pr(kf0^+f1^))(10)

扫描二维码关注公众号,回复: 15218750 查看本文章

3. 实现代码

// Helper function
// Compute Relative motion between two absolute poses parameterized by Rt
// Rotate one bearing vector according to the relative motion
inline void AbsoluteToRelative(const Mat3 &R0, const Vec3 &t0, const Mat3 &R1, const Vec3 &t1, const Vec3 &x0, Mat3 &R, Vec3 &t, Vec3 &Rx0)
{
    
    
  R = R1 * R0.transpose();
  t = t1 - R * t0;
  Rx0 = R * x0;
}

bool TriangulateIDWMidpoint(const Mat3 & R0, const Vec3 & t0, const Vec3 & x0, const Mat3 & R1, const Vec3 & t1, const Vec3 & x1, Vec3* X_euclidean)
{
    
    
  // absolute to relative
  Mat3 R;
  Vec3 t, Rx0;
  AbsoluteToRelative(R0, t0, R1, t1, x0, R, t, Rx0);

  const double p_norm = Rx0.cross(x1).norm();
  const double q_norm = Rx0.cross(t).norm();
  const double r_norm = x1.cross(t).norm();

  // Eq. (10)
  const auto xprime1 = ( q_norm / (q_norm + r_norm) )
    * ( t + (r_norm / p_norm) * (Rx0 + x1) );

  // relative to absolute
  *X_euclidean = R1.transpose() * (xprime1 - t1);

  // Eq. (7)
  const Vec3 lambda0_Rx0 = (r_norm / p_norm) * Rx0;
  const Vec3 lambda1_x1 = (q_norm / p_norm) * x1;

  // Eq. (9) - test adequation
  return (t + lambda0_Rx0 - lambda1_x1).squaredNorm()
    <
    std::min(std::min(
      (t + lambda0_Rx0 + lambda1_x1).squaredNorm(),
      (t - lambda0_Rx0 - lambda1_x1).squaredNorm()),
      (t - lambda0_Rx0 + lambda1_x1).squaredNorm());
}

猜你喜欢

转载自blog.csdn.net/qq_28087491/article/details/130834660
今日推荐