自学内容网 自学内容网

C++,Python 论文复现:使用单位四元数求解对齐轨迹的 Sim3

参考文献: Closed-form solution of absolute orientation using unit quaternions

在 SLAM 中, 轨迹会因为因为起始位姿、尺度设定的不同而不同

在轨迹形状大致相同时, 可以求取一个相似变换使得两个轨迹尽可能重合

给定两个分别具有 n n n 个空间点的轨迹, 分别定义为:
r l ∈ R n × 3 , r r ∈ R n × 3 r_l \in \mathbb{R}^{n \times 3}, r_r \in \mathbb{R}^{n \times 3} rlRn×3,rrRn×3

有相似变换 Sim3 ( s R , t ) \text{Sim3}(sR, t) Sim3(sR,t) 使得下式的和方差最小, 并使轨迹两个轨迹对齐:
SSE = ∑ i = 1 n ∣ ∣ s R ( r l , i ) + t − r r , i ∣ ∣ 2 \text{SSE} = \sum_{i=1}^n||sR(r_{l, i}) + t - r_{r, i}||^2 SSE=i=1n∣∣sR(rl,i)+trr,i2

平移向量

首先,计算两个轨迹的质心,并分别对两个轨迹零均值化:
r l ′ = r l − r l ˉ , r l ˉ ∈ R 3 r r ′ = r r − r r ˉ , r r ˉ ∈ R 3 t ′ = t + s R ( r l ˉ ) − r r ˉ SSE = ∑ i = 1 n ∣ ∣ s R ( r l , i ′ ) + t ′ − r r , i ′ ∣ ∣ 2 = ∑ i = 1 n ∣ ∣ s R ( r l , i ′ ) − r r , i ′ ∣ ∣ 2 + 2 t ′ ∑ i = 1 n ( s R ( r l , i ′ ) − r r , i ′ ) + n ∣ ∣ t ′ ∣ ∣ 2 r'_l = r_l - \bar{r_l}, \bar{r_l} \in \mathbb{R}^{3} \\ r'_r = r_r - \bar{r_r}, \bar{r_r} \in \mathbb{R}^{3} \\ t'= t + sR(\bar{r_l}) - \bar{r_r} \\ \text{SSE} = \sum_{i=1}^n||sR(r'_{l, i}) + t' - r'_{r, i}||^2 \\ = \sum_{i=1}^n ||sR(r'_{l, i}) - r'_{r, i}||^2 + 2t'\sum_{i=1}^n(sR(r'_{l, i}) - r'_{r, i}) + n||t'||^2 rl=rlrlˉ,rlˉR3rr=rrrrˉ,rrˉR3t=t+sR(rlˉ)rrˉSSE=i=1n∣∣sR(rl,i)+trr,i2=i=1n∣∣sR(rl,i)rr,i2+2ti=1n(sR(rl,i)rr,i)+n∣∣t2

零均值点经过线性变换后,其均值依然为零,即 ∑ i = 1 n s R ( r l , i ′ ) = 0 \sum_{i=1}^n sR(r'_{l, i}) = 0 i=1nsR(rl,i)=0, 所以第二项为 0:
SSE = ∑ i = 1 n ∣ ∣ s R ( r l , i ′ ) − r r , i ′ ∣ ∣ 2 + n ∣ ∣ t ′ ∣ ∣ 2 \text{SSE} = \sum_{i=1}^n ||sR(r'_{l, i}) - r'_{r, i}||^2 + n||t'||^2 SSE=i=1n∣∣sR(rl,i)rr,i2+n∣∣t2

第一项只与 s , R s, R s,R 有关, 第二项只与 t ′ t' t 有关。令第二项为 0, 解得平移向量:
t = r r ˉ − s R ( r l ˉ ) t = \bar{r_r} - sR(\bar{r_l}) t=rrˉsR(rlˉ)

其中只有 s , R s, R s,R 是未知量, 后续代入数值即可

尺度因子

接上文, 继续对 SSE \text{SSE} SSE 进行简化和分解 (点经旋转后模长不变, 即 ∣ ∣ R ( r ) ∣ ∣ 2 = ∣ ∣ r ∣ ∣ 2 ||R(r)||^2 = ||r||^2 ∣∣R(r)2=∣∣r2):
S l = ∑ i = 1 n ∣ ∣ R ( r l , i ′ ) ∣ ∣ 2 = ∑ i = 1 n ∣ ∣ r l , i ′ ∣ ∣ 2 S r = ∑ i = 1 n ∣ ∣ r r , i ′ ∣ ∣ 2 D = ∑ i = 1 n r r , i ′ ⋅ R ( r l , i ′ ) SSE = ∑ i = 1 n ∣ ∣ s R ( r l , i ′ ) − r r , i ′ ∣ ∣ 2 = s 2 S l − 2 s D + S r = s ( s S l − 2 D + 1 s S r ) = s ( s S l − 1 s S r ) 2 + 2 s ( S l S r − D ) S_l = \sum_{i=1}^n||R(r'_{l, i})||^2 = \sum_{i=1}^n||r'_{l, i}||^2 \\ S_r = \sum_{i=1}^n||r'_{r, i}||^2 \\ D = \sum_{i=1}^n r'_{r, i} \cdot R(r'_{l, i}) \\ \text{SSE} = \sum_{i=1}^n ||sR(r'_{l, i}) - r'_{r, i}||^2 = s^2 S_l - 2sD + S_r \\ = s(s S_l - 2D + \frac{1}{s} S_r) = s(\sqrt{s S_l} - \sqrt{\frac{1}{s} S_r})^2 + 2s(\sqrt{S_l S_r} - D) Sl=i=1n∣∣R(rl,i)2=i=1n∣∣rl,i2Sr=i=1n∣∣rr,i2D=i=1nrr,iR(rl,i)SSE=i=1n∣∣sR(rl,i)rr,i2=s2Sl2sD+Sr=s(sSl2D+s1Sr)=s(sSl s1Sr )2+2s(SlSr D)

令第一项 s S l − 1 s S r = 0 \sqrt{s S_l} - \sqrt{\frac{1}{s} S_r} = 0 sSl s1Sr =0, 可解得尺度因子 (表达式中所有数值均为已知量):
s = S r S l = ∑ i = 1 n ∣ ∣ r r , i ′ ∣ ∣ 2 ∑ i = 1 n ∣ ∣ r l , i ′ ∣ ∣ 2 s = \sqrt{\frac{S_r}{S_l}} = \sqrt{\frac{\sum_{i=1}^n||r'_{r, i}||^2}{\sum_{i=1}^n||r'_{l, i}||^2}} s=SlSr =i=1n∣∣rl,i2i=1n∣∣rr,i2

单位四元数

由于 S l , S r S_l, S_r Sl,Sr 已知为定值, 最小化 SSE \text{SSE} SSE 等价于最大化 D D D:
maximize : D = ∑ i = 1 n r r , i ′ ⋅ R ( r l , i ′ ) \text{maximize}: D = \sum_{i=1}^n r'_{r, i} \cdot R(r'_{l, i}) maximize:D=i=1nrr,iR(rl,i)

为了解决这个问题, 引入四元数进行化简, 首先利用 q ˙ , r ˙ ∈ R 4 × 1 \dot{q}, \dot{r} \in \mathbb{R}^{4 \times 1} q˙,r˙R4×1 对部分性质进行说明:
q ˙ = [ w x y z ] q ˙ ∗ = [ w − x − y − z ] \dot{q} = \left[ \begin{matrix} w & x & y & z \end{matrix} \right] \\ \dot{q}^* = \left[ \begin{matrix} w & -x & -y & -z \end{matrix} \right] q˙=[wxyz]q˙=[wxyz]

两个四元数之间的相乘, 可以等价为一个 4×4 矩阵和一个长度为 4 的向量之间的叉乘:
q ˙ r ˙ = Q r ˙ = [ w − x − y − z x w − z y y z w − x z − y x w ] r ˙ r ˙ q ˙ = Q ˉ r ˙ = [ w − x − y − z x w z − y y − z w x z y − x w ] r ˙ \dot{q} \dot{r} = Q\dot{r} = \left[ \begin{matrix} w & -x & -y & -z \\ x & w & -z & y \\ y & z & w & -x \\ z & -y & x & w \end{matrix} \right] \dot{r}\\ \dot{r} \dot{q} = \bar{Q} \dot{r} = \left[ \begin{matrix} w & -x & -y & -z \\ x & w & z & -y \\ y & -z & w & x \\ z & y & -x & w \end{matrix} \right] \dot{r} q˙r˙=Qr˙= wxyzxwzyyzwxzyxw r˙r˙q˙=Qˉr˙= wxyzxwzyyzwxzyxw r˙

Q , Q ˉ Q, \bar{Q} Q,Qˉ 为正交矩阵, 四元数 q ˙ \dot{q} q˙ 的共轭 q ˙ ∗ \dot{q}^* q˙ 则分别对应 Q T , Q ˉ T Q^T, \bar{Q}^T QT,QˉT:
q ˙ r ˙ q ˙ ∗ = ( Q r ˙ ) q ˙ ∗ = Q ˉ T Q r ˙ = [ A 11 A 22 A 23 A 24 A 32 A 33 A 34 A 42 A 43 A 44 ] r ˙ \dot{q} \dot{r} \dot{q}^* = (Q \dot{r}) \dot{q}^* = \bar{Q}^TQ \dot{r} = \left[ \begin{matrix} A_{11} \\ & A_{22} & A_{23} & A_{24} \\ & A_{32} & A_{33} & A_{34} \\ & A_{42} & A_{43} & A_{44} \end{matrix} \right] \dot{r} q˙r˙q˙=(Qr˙)q˙=QˉTQr˙= A11A22A32A42A23A33A43A24A34A44 r˙

如果四元数 r ˙ \dot{r} r˙ 为纯虚数 (即 w = 0 w=0 w=0, 看作空间点), 则 q ˙ r ˙ q ˙ ∗ \dot{q} \dot{r} \dot{q}^* q˙r˙q˙ 也为纯虚数 (看作旋转), 将 D D D 等价为:
maximize : D = ∑ i = 1 n q ˙ r ˙ l , i q ˙ ∗ ⋅ r ˙ r , i = ∑ i = 1 n ( Q ˉ T Q r ˙ l , i ) T r ˙ r , i = ∑ i = 1 n ( r ˙ l , i T Q T ) ( Q ˉ r ˙ r , i ) = ∑ i = 1 n ( R ˉ l , i q ˙ ) T ( R r , i q ˙ ) = q ˙ T ( ∑ i = 1 n R ˉ l , i T R r , i ) q ˙ = q ˙ T N q ˙ \text{maximize}: D = \sum_{i=1}^n \dot{q} \dot{r}_{l, i} \dot{q}^* \cdot \dot{r}_{r, i} = \sum_{i=1}^n (\bar{Q}^T Q \dot{r}_{l, i})^T \dot{r}_{r, i} \\ = \sum_{i=1}^n (\dot{r}_{l, i}^T Q^T) (\bar{Q} \dot{r}_{r, i}) = \sum_{i=1}^n (\bar{R}_{l, i} \dot{q})^T (R_{r, i} \dot{q}) \\ = \dot{q}^T (\sum_{i=1}^n \bar{R}_{l, i}^T R_{r, i}) \dot{q} = \dot{q}^T N \dot{q} maximize:D=i=1nq˙r˙l,iq˙r˙r,i=i=1n(QˉTQr˙l,i)Tr˙r,i=i=1n(r˙l,iTQT)(Qˉr˙r,i)=i=1n(Rˉl,iq˙)T(Rr,iq˙)=q˙T(i=1nRˉl,iTRr,i)q˙=q˙TNq˙

为了更快地计算 N N N, 定义查找表:
LUT = [ S x x S x y S x z S y x S y y S y z S z x S z y S z z ] S x x = ∑ i = 1 n x l , i ′ x r , i ′ , S x y = ∑ i = 1 n x l , i ′ y r , i ′ N = ∑ i = 1 n R ˉ l , i T R r , i = [ S x x + S y y + S z z S y z − S z y S z x − S x z S x y − S y x S y z − S z y S x x − S y y − S z z S x y + S y x S z x + S x z S z x − S x z S x y + S y x − S x x + S y y − S z z S y z + S z y S x y − S y x S z x + S x z S y z + S z y − S x x − S y y + S z z ] \text{LUT} = \left[ \begin{matrix} S_{xx} & S_{xy} & S_{xz} \\ S_{yx} & S_{yy} & S_{yz} \\ S_{zx} & S_{zy} & S_{zz} \end{matrix} \right] \\ S_{xx} = \sum_{i=1}^n x'_{l, i} x'_{r, i}, S_{xy} = \sum_{i=1}^n x'_{l, i} y'_{r, i} \\ N = \sum_{i=1}^n \bar{R}_{l, i}^T R_{r, i} = \left[ \begin{matrix} S_{xx} + S_{yy} + S_{zz} & S_{yz} - S_{zy} & S_{zx} - S_{xz} & S_{xy} - S_{yx} \\ S_{yz} - S_{zy} & S_{xx} - S_{yy} - S_{zz} & S_{xy} + S_{yx} & S_{zx} + S_{xz} \\ S_{zx} - S_{xz} & S_{xy} + S_{yx} & -S_{xx} + S_{yy} - S_{zz} & S_{yz} + S_{zy} \\ S_{xy} - S_{yx} & S_{zx} + S_{xz} & S_{yz} + S_{zy} & -S_{xx} - S_{yy} + S_{zz} \end{matrix} \right] LUT= SxxSyxSzxSxySyySzySxzSyzSzz Sxx=i=1nxl,ixr,i,Sxy=i=1nxl,iyr,iN=i=1nRˉl,iTRr,i= Sxx+Syy+SzzSyzSzySzxSxzSxySyxSyzSzySxxSyySzzSxy+SyxSzx+SxzSzxSxzSxy+SyxSxx+SyySzzSyz+SzySxySyxSzx+SxzSyz+SzySxxSyy+Szz

N N N 是个对称阵, 在特征值分解后可以得到 4 个特征向量 (单位向量), 而且:
x T N x = λ x^T N x = \lambda xTNx=λ

所以, 最大特征值所对应的特征向量即为使 D D D 最大的单位四元数 q ˙ \dot{q} q˙, 根据以下公式可求得旋转矩阵:
R = ( Q ˉ T Q ) 2 : 4 , 2 : 4 R = (\bar{Q}^TQ)_{2:4, 2:4} R=(QˉTQ)2:4,2:4

C++ 实现

Sophus::Sim3f align_trajectory(const std::vector<Eigen::Vector3f> &pts1,
                               const std::vector<Eigen::Vector3f> &pts2) {
  assert(pts1.size() == pts2.size());
  int n = pts1.size();
  // 计算质心
  Eigen::Vector3d centroid1 = Eigen::Vector3d::Zero(), centroid2 = Eigen::Vector3d::Zero();
  for (int i = 0; i < n; ++i) {
    Eigen::Vector3d p1 = pts1[i].cast<double>(), p2 = pts2[i].cast<double>();
    centroid1 += p1;
    centroid2 += p2;
  }
  centroid1 /= n;
  centroid2 /= n;
  // 零均值化, 计算尺度因子、lut
  Eigen::Matrix3<long double> lut = Eigen::Matrix3<long double>::Zero();
  long double Sl = 0, Sr = 0;
  for (int i = 0; i < n; ++i) {
    Eigen::Vector3d p1 = pts1[i].cast<double>() - centroid1, p2 = pts2[i].cast<double>() - centroid2;
    // 如果 pts 数值较大, 可能会溢出
    lut += (p1 * p2.transpose()).cast<long double>();
    Sl += p1.squaredNorm();
    Sr += p2.squaredNorm();
  }
  lut /= n;
  double Sxx = lut(0, 0), Sxy = lut(0, 1), Sxz = lut(0, 2),
      Syx = lut(1, 0), Syy = lut(1, 1), Syz = lut(1, 2),
      Szx = lut(2, 0), Szy = lut(2, 1), Szz = lut(2, 2);
  double s = std::sqrt(Sr / Sl);
  // 单位四元数
  Eigen::Matrix4d N;
  N << (Sxx + Syy + Szz) / 2, Syz - Szy, Szx - Sxz, Sxy - Syx,
      0, (Sxx - Syy - Szz) / 2, Syx + Sxy, Szx + Sxz,
      0, 0, (-Sxx + Syy - Szz) / 2, Szy + Syz,
      0, 0, 0, (-Sxx - Syy + Szz) / 2;
  N += N.transpose().eval();
  Eigen::SelfAdjointEigenSolver<Eigen::Matrix4d> eig(N);
  Eigen::Vector4d q = eig.eigenvectors().col(3);
  // 代入数值
  float w = q[0], x = q[1], y = q[2], z = q[3];
  Eigen::Matrix3f R;
  R << w * w + x * x - y * y - z * z, -2 * w * z + 2 * x * y, 2 * w * y + 2 * x * z,
      2 * w * z + 2 * x * y, w * w - x * x + y * y - z * z, -2 * w * x + 2 * y * z,
      -2 * w * y + 2 * x * z, 2 * w * x + 2 * y * z, w * w - x * x - y * y + z * z;
  Eigen::Vector3f t = centroid2.cast<float>() - s * R * centroid1.cast<float>();
  return Sophus::Sim3f(s, Eigen::Quaternionf(R), t);
}

Python 实现

import numpy as np
from scipy.spatial import transform

SO3 = transform.Rotation  # 特殊正交群


def align_trajectory(pts1: np.ndarray, pts2: np.ndarray):
    """ Closed-form solution of absolute orientation using unit quaternions """
    assert pts1.ndim == 2 and pts1.shape[1] == 3 and pts1.shape == pts2.shape
    pts1, pts2 = map(np.float64, (pts1, pts2))
    # 尺度因子
    centroid1, centroid2 = pts1.mean(axis=0), pts2.mean(axis=0)
    pts1, pts2 = pts1 - centroid1, pts2 - centroid2
    s = np.sqrt(np.square(pts2).sum() / np.square(pts1).sum())
    # 单位四元数
    Sxx, Sxy, Sxz, Syx, Syy, Syz, Szx, Szy, Szz = (pts1.T @ pts2).flatten()
    sumn = np.array([[(Sxx + Syy + Szz) / 2, Syz - Szy, Szx - Sxz, Sxy - Syx],
                     [0, (Sxx - Syy - Szz) / 2, Syx + Sxy, Szx + Sxz],
                     [0, 0, (- Sxx + Syy - Szz) / 2, Szy + Syz],
                     [0, 0, 0, (- Sxx - Syy + Szz) / 2]])
    sumn += sumn.T
    eig_val, eig_vec = np.linalg.eig(sumn)
    w, x, y, z = eig_vec[:, eig_val.argmax()]
    # 代入数值
    R = SO3.from_matrix(
        [[w ** 2 + x ** 2 - y ** 2 - z ** 2, -2 * w * z + 2 * x * y, 2 * w * y + 2 * x * z],
         [2 * w * z + 2 * x * y, w ** 2 - x ** 2 + y ** 2 - z ** 2, -2 * w * x + 2 * y * z],
         [-2 * w * y + 2 * x * z, 2 * w * x + 2 * y * z, w ** 2 - x ** 2 - y ** 2 + z ** 2]]
    )
    t = centroid2 - s * R.as_matrix() @ centroid1
    return s, R, t


if __name__ == "__main__":
    s = 2.5
    R = SO3.from_quat([0.8006, 0.1601, 0.3202, 0.4804]).as_matrix()
    t = np.array([0.1, 0.2, 0.3])

    pts1 = np.random.uniform(-1, 1, (100, 3))
    pts2 = (s * R @ pts1.T).T + t
    s, R, t = align_trajectory(pts1, pts2)

    e = (s * R.as_matrix() @ pts1.T).T + t - pts2
    print(np.square(e).sum())
    print(s, R.as_quat(), t)

原文地址:https://blog.csdn.net/qq_55745968/article/details/140648817

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!