26 void AlignUtils::align_umeyama(
const std::vector<Eigen::Matrix<double, 3, 1>> &data,
const std::vector<Eigen::Matrix<double, 3, 1>> &model,
27 Eigen::Matrix<double, 3, 3> &R, Eigen::Matrix<double, 3, 1> &t,
double &s,
bool known_scale,
bool yaw_only) {
29 assert(model.size() == data.size());
32 Eigen::Matrix<double, 3, 1> mu_M =
get_mean(model);
33 Eigen::Matrix<double, 3, 1> mu_D =
get_mean(data);
34 std::vector<Eigen::Matrix<double, 3, 1>> model_zerocentered, data_zerocentered;
35 for (
size_t i = 0; i < model.size(); i++) {
36 model_zerocentered.push_back(model[i] - mu_M);
37 data_zerocentered.push_back(data[i] - mu_D);
41 double n = model.size();
42 Eigen::Matrix<double, 3, 3> C = Eigen::Matrix<double, 3, 3>::Zero();
43 for (
size_t i = 0; i < model_zerocentered.size(); i++) {
44 C.noalias() += model_zerocentered[i] * data_zerocentered[i].transpose();
50 for (
size_t i = 0; i < data_zerocentered.size(); i++) {
51 sigma2 += data_zerocentered[i].dot(data_zerocentered[i]);
56 Eigen::JacobiSVD<Eigen::Matrix<double, 3, 3>> svd(C, Eigen::ComputeFullV | Eigen::ComputeFullU);
58 Eigen::Matrix<double, 3, 3> U_svd = svd.matrixU();
59 Eigen::Matrix<double, 3, 1> D_svd = svd.singularValues();
60 Eigen::Matrix<double, 3, 3> V_svd = svd.matrixV();
62 Eigen::Matrix<double, 3, 3> S = Eigen::Matrix<double, 3, 3>::Identity();
63 if (U_svd.determinant() * V_svd.determinant() < 0) {
70 Eigen::Matrix<double, 3, 3> rot_C = n * C.transpose();
74 R.noalias() = U_svd * S * V_svd.transpose();
82 s = 1.0 / sigma2 * (D_svd.asDiagonal() * S).trace();
86 t.noalias() = mu_M - s * R * mu_D;
96 std::vector<Eigen::Matrix<double, 7, 1>> &est_poses,
97 std::vector<Eigen::Matrix<double, 7, 1>> >_poses) {
98 std::vector<Eigen::Matrix3d> est_covori, est_covpos, gt_covori, gt_covpos;
104 std::vector<Eigen::Matrix<double, 7, 1>> &est_poses,
105 std::vector<Eigen::Matrix<double, 7, 1>> >_poses, std::vector<Eigen::Matrix3d> &est_covori,
106 std::vector<Eigen::Matrix3d> &est_covpos, std::vector<Eigen::Matrix3d> >_covori,
107 std::vector<Eigen::Matrix3d> >_covpos) {
110 std::vector<double> est_times_temp, gt_times_temp;
111 std::vector<Eigen::Matrix<double, 7, 1>> est_poses_temp, gt_poses_temp;
112 std::vector<Eigen::Matrix3d> est_covori_temp, est_covpos_temp, gt_covori_temp, gt_covpos_temp;
115 size_t gt_pointer = 0;
118 for (
size_t i = 0; i < est_times.size(); i++) {
121 double best_diff = max_difference;
122 int best_gt_idx = -1;
125 while (gt_pointer < gt_times.size() && gt_times.at(gt_pointer) < (est_times.at(i) + offset) &&
126 std::abs(gt_times.at(gt_pointer) - (est_times.at(i) + offset)) > max_difference) {
131 while (gt_pointer < gt_times.size() && std::abs(gt_times.at(gt_pointer) - (est_times.at(i) + offset)) <= max_difference) {
133 if (std::abs(gt_times.at(gt_pointer) - (est_times.at(i) + offset)) >= best_diff) {
137 best_diff = std::abs(gt_times.at(gt_pointer) - (est_times.at(i) + offset));
138 best_gt_idx = gt_pointer;
143 if (best_gt_idx != -1) {
146 est_times_temp.push_back(gt_times.at(best_gt_idx));
147 est_poses_temp.push_back(est_poses.at(i));
148 gt_times_temp.push_back(gt_times.at(best_gt_idx));
149 gt_poses_temp.push_back(gt_poses.at(best_gt_idx));
153 if (!est_covori.empty()) {
154 assert(est_covori.size() == est_covpos.size());
155 est_covori_temp.push_back(est_covori.at(i));
156 est_covpos_temp.push_back(est_covpos.at(i));
157 if (gt_covori.empty()) {
158 gt_covori_temp.push_back(Eigen::Matrix3d::Zero());
159 gt_covpos_temp.push_back(Eigen::Matrix3d::Zero());
161 assert(gt_covori.size() == gt_covpos.size());
162 gt_covori_temp.push_back(gt_covori.at(best_gt_idx));
163 gt_covpos_temp.push_back(gt_covpos.at(best_gt_idx));
170 if (est_times.size() < 3) {
171 PRINT_ERROR(
RED "[ALIGN]: Was unable to associate groundtruth and estimate trajectories\n" RESET);
172 PRINT_ERROR(
RED "[ALIGN]: %d total matches....\n" RESET, (
int)est_times.size());
173 PRINT_ERROR(
RED "[ALIGN]: Do the time of the files match??\n" RESET);
176 assert(est_times_temp.size() == gt_times_temp.size());
181 est_times = est_times_temp;
182 est_poses = est_poses_temp;
183 est_covori = est_covori_temp;
184 est_covpos = est_covpos_temp;
185 gt_times = gt_times_temp;
186 gt_poses = gt_poses_temp;
187 gt_covori = gt_covori_temp;
188 gt_covpos = gt_covpos_temp;
static void perform_association(double offset, double max_difference, std::vector< double > &est_times, std::vector< double > >_times, std::vector< Eigen::Matrix< double, 7, 1 >> &est_poses, std::vector< Eigen::Matrix< double, 7, 1 >> >_poses)
Will intersect our loaded data so that we have common timestamps.
Evaluation and recording utilities.
static Eigen::Matrix< double, 3, 1 > get_mean(const std::vector< Eigen::Matrix< double, 3, 1 >> &data)
Gets mean of the vector of data.
static void align_umeyama(const std::vector< Eigen::Matrix< double, 3, 1 >> &data, const std::vector< Eigen::Matrix< double, 3, 1 >> &model, Eigen::Matrix< double, 3, 3 > &R, Eigen::Matrix< double, 3, 1 > &t, double &s, bool known_scale, bool yaw_only)
Given a set of points in a model frame and a set of points in a data frame, finds best transform betw...
#define PRINT_ERROR(x...)
static double get_best_yaw(const Eigen::Matrix< double, 3, 3 > &C)
Gets best yaw from Frobenius problem. Equation (17)-(18) in Zhang et al. 2018 IROS paper...
Eigen::Matrix< double, 3, 3 > rot_z(double t)