对齐两段不同坐标系的轨迹

对齐两段不同坐标系的轨迹,实际就是已知两两3D点的对应关系,求取它们之间的R,T。这实际就是简化的ICP算法(省去了寻找点的对应关系这一步)。
设一段轨迹的3d点为pt, 一段为ps,那么它们之间的关系为:
s ∗ p t = R ∗ p s + T s*p_t = R*p_s + T spt=Rps+T
假设两段轨迹的尺度是一样的,则s=1.
将R,T去耦合,我们知道点云的平均值也是满足旋转关系的,即
p t ˉ = R ∗ p s ˉ + T \bar{p_t} = R * \bar{p_s} +T ptˉ=Rpsˉ+T
故:
p t − p t ˉ = R ∗ ( p s − p s ˉ ) p_t -\bar{p_t} = R*(p_s - \bar{p_s}) ptptˉ=R(pspsˉ)
简写为:
q t = R ∗ q s q_t = R * q_s qt=Rqs
对于所有的点
s u m = ∑ i N ∣ ∣ q t i − R q s i ∣ ∣ 2 sum = \sum^{N}_i{||q_t^i - Rq^i_s||^2} sum=iNqtiRqsi2
即求R使得sum最小。
s u m = ∑ i N ( q t i − R q s i ) T ( q t i − R q s i ) = ∑ i N ( q t i T ∗ q t i + q s i T ∗ q s i − q t i T ∗ R ∗ q s i − q s i T R t ∗ q t i ) sum = \sum^N_i(q_t^i-Rq_s^i)^T(q_t^i-Rq_s^i) \\ = \sum^N_i({q_t^i}^T*q_t^i + {q_s^i}^T*q_s^i - {q_t^i}^T*R*q_s^i - {q_s^i}^TR^t*q_t^i) sum=iN(qtiRqsi)T(qtiRqsi)=iN(qtiTqti+qsiTqsiqtiTRqsiqsiTRtqti)
R是单位对称矩阵,有:
R = R T a T ∗ R ∗ b = b T ∗ R ∗ a R = R^T \\ a^T*R*b = b^T*R*a R=RTaTRb=bTRa
故上面可以简化为:
∑ i N ( q t i T ∗ q t i + q s i T ∗ q s i − 2 q t i T ∗ R ∗ q s i \sum^N_i({q_t^i}^T*q_t^i + {q_s^i}^T*q_s^i - 2{q_t^i}^T*R*q_s^i iN(qtiTqti+qsiTqsi2qtiTRqsi
即求R使得F最大
F = ∑ i N q t i T ∗ R ∗ q s i = T r a c e ( ∑ i N R q s i q t i T ) = T r a c e ( R H ) H = ∑ i N ( q s i q t i T ) F = \sum^N_i{q_t^i}^T*R*q_s^i \\ =Trace(\sum^N_i{Rq_s^i{q_t^i}^T}) \\ =Trace(RH) \\ H = \sum^N_i({q_s^i{q_t^i}^T}) F=iNqtiTRqsi=Trace(iNRqsiqtiT)=Trace(RH)H=iN(qsiqtiT)
上面转换是由于 T r a c e ( A B ) = T r a c e ( B A ) Trace(AB) = Trace(BA) Trace(AB)=Trace(BA)

在这里插入图片描述
当det(X) = -1 时,
在这里插入图片描述
因此我们最终的结果:
i f d e t ( V U T ) = 1 R = V U T i f d e t ( V U T ) = − 1 R = V ′ U T V ′ = [ v 1 , v 2 , − v 3 ] T = p t ˉ − R ∗ p s ˉ if det(VU^T) = 1 \\ R = VU^T \\ if det(VU^T) = -1 \\ R = V'U^T \\ V' = [v1,v2,-v3] \\ T = \bar{p_t} - R * \bar{p_s} ifdet(VUT)=1R=VUTifdet(VUT)=1R=VUTV=[v1,v2,v3]T=ptˉRpsˉ
补充一点线性知识:
1.Trace迹,是矩阵主对角线的和。
对于方阵A, A = Q − 1 Λ Q A = Q^{-1} \Lambda Q A=Q1ΛQ
t r a c e ( A ) = λ 1 + λ 2 + . . . d e t ( A ) = λ 1 ∗ λ 2 ∗ . . . trace(A) = \lambda_1 + \lambda_2 +... \\ det(A) = \lambda_1 * \lambda_2 *... trace(A)=λ1+λ2+...det(A)=λ1λ2...
如果A和B是相似矩阵 B = P − 1 A P B = P^{-1} AP B=P1AP
那么
trace(A) = trace(B)
det(A) = det(B)
实际是因为A和B的特征值是一样的。

A可以看做是imu坐标系的旋转矩阵,B可以看做是wheel坐标系下的旋转矩阵
B= R_wheel2b.transpose() * A * R_wheel2b
哈哈,就是我们代码里常用的公式了

参考论文:Least-Squares Fitting of Two 3-D Point Sets

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个问题需要解决以下几个步骤: 1. 读取两条轨迹的数据,可以用文件或输入流来读取。 2. 对于每条轨迹,计算出其质心和协方差矩阵,然后通过特征值分解求出其主轴方向。 3. 通过两条轨迹的主轴方向,计算它们之间的旋转矩阵。 4. 计算两条轨迹的缩放比例,可以用两条轨迹的主轴长度比来计算。 5. 将两条轨迹按照旋转矩阵和缩放比例进行变换,然后在同一坐标系中显示。 下面是一个简单的C++程序示例: ```cpp #include <iostream> #include <fstream> #include <vector> #include <Eigen/Dense> using namespace std; using namespace Eigen; // 读取轨迹数据 void readTrajectory(const char* filename, vector<Vector2d>& traj) { ifstream fin(filename); double x, y; while (fin >> x >> y) { traj.push_back(Vector2d(x, y)); } } // 计算轨迹的质心和协方差矩阵 void computeCovariance(const vector<Vector2d>& traj, Vector2d& center, Matrix2d& cov) { center.setZero(); for (const auto& p : traj) { center += p; } center /= traj.size(); cov.setZero(); for (const auto& p : traj) { Vector2d d = p - center; cov += d * d.transpose(); } cov /= traj.size(); } // 计算特征值分解,返回主轴方向 Vector2d computePCA(const Matrix2d& cov) { EigenSolver<Matrix2d> es(cov); Vector2d eigvals = es.eigenvalues().real(); Matrix2d eigvecs = es.eigenvectors().real(); if (eigvals(0) > eigvals(1)) { return eigvecs.col(0); } else { return eigvecs.col(1); } } // 计算旋转矩阵和缩放比例 void computeTransform(const vector<Vector2d>& traj1, const vector<Vector2d>& traj2, Matrix2d& R, double& s) { Vector2d c1, c2; Matrix2d cov1, cov2; computeCovariance(traj1, c1, cov1); computeCovariance(traj2, c2, cov2); Vector2d pca1 = computePCA(cov1); Vector2d pca2 = computePCA(cov2); R = pca2 * pca1.transpose(); s = pca2.norm() / pca1.norm(); } // 变换轨迹 void transformTrajectory(const vector<Vector2d>& traj, const Matrix2d& R, double s, vector<Vector2d>& transformed) { transformed.clear(); transformed.reserve(traj.size()); for (const auto& p : traj) { transformed.push_back(s * R * p); } } int main() { vector<Vector2d> traj1, traj2; readTrajectory("trajectory1.txt", traj1); readTrajectory("trajectory2.txt", traj2); Matrix2d R; double s; computeTransform(traj1, traj2, R, s); vector<Vector2d> transformed1, transformed2; transformTrajectory(traj1, R, s, transformed1); transformTrajectory(traj2, Matrix2d::Identity(), 1.0 / s * R.transpose(), transformed2); // 在同一坐标系中显示轨迹 // ... return 0; } ``` 这个程序用到了Eigen库来进行矩阵计算。注意,这个程序假设两条轨迹已经对齐了,如果需要进行刚性配准的话,还需要计算平移向量,并将其加到变换后的轨迹上。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值