ResultTrajectory.cpp
Go to the documentation of this file.
1 /*
2  * OpenVINS: An Open Platform for Visual-Inertial Research
3  * Copyright (C) 2018-2023 Patrick Geneva
4  * Copyright (C) 2018-2023 Guoquan Huang
5  * Copyright (C) 2018-2023 OpenVINS Contributors
6  * Copyright (C) 2018-2019 Kevin Eckenhoff
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "ResultTrajectory.h"
23 
24 using namespace ov_eval;
25 
26 ResultTrajectory::ResultTrajectory(std::string path_est, std::string path_gt, std::string alignment_method) {
27 
28  // Load from file
31 
32  // Debug print amount
33  // std::string base_filename1 = path_est.substr(path_est.find_last_of("/\\") + 1);
34  // std::string base_filename2 = path_gt.substr(path_gt.find_last_of("/\\") + 1);
35  // PRINT_DEBUG("[TRAJ]: loaded %d poses from %s\n",(int)est_times.size(),base_filename1.c_str());
36  // PRINT_DEBUG("[TRAJ]: loaded %d poses from %s\n",(int)gt_times.size(),base_filename2.c_str());
39  double ratio = len_est / len_gt;
40  if (ratio > 1.1 || ratio < 0.9) {
41  PRINT_WARNING(YELLOW "[TRAJ]: Trajectory is a bad ratio of %.2f length (est %.2f, gt %.2f)\n", ratio, len_est, len_gt);
42  PRINT_WARNING(YELLOW "[TRAJ]: %s\n", path_est.c_str());
43  }
44 
45  // Intersect timestamps
47 
48  // Return failure if we didn't have any common timestamps
49  if (est_poses.size() < 3) {
50  PRINT_ERROR(RED "[TRAJ]: unable to get enough common timestamps between trajectories.\n" RESET);
51  PRINT_ERROR(RED "[TRAJ]: does the estimated trajectory publish the rosbag timestamps??\n" RESET);
52  std::exit(EXIT_FAILURE);
53  }
54 
55  // Perform alignment of the trajectories
56  Eigen::Matrix3d R_ESTtoGT, R_GTtoEST;
57  Eigen::Vector3d t_ESTinGT, t_GTinEST;
58  double s_ESTtoGT, s_GTtoEST;
59  AlignTrajectory::align_trajectory(est_poses, gt_poses, R_ESTtoGT, t_ESTinGT, s_ESTtoGT, alignment_method);
60  AlignTrajectory::align_trajectory(gt_poses, est_poses, R_GTtoEST, t_GTinEST, s_GTtoEST, alignment_method);
61 
62  // Debug print to the user
63  Eigen::Vector4d q_ESTtoGT = ov_core::rot_2_quat(R_ESTtoGT);
64  Eigen::Vector4d q_GTtoEST = ov_core::rot_2_quat(R_GTtoEST);
65  PRINT_DEBUG("[TRAJ]: q_ESTtoGT = %.3f, %.3f, %.3f, %.3f | p_ESTinGT = %.3f, %.3f, %.3f | s = %.2f\n", q_ESTtoGT(0), q_ESTtoGT(1),
66  q_ESTtoGT(2), q_ESTtoGT(3), t_ESTinGT(0), t_ESTinGT(1), t_ESTinGT(2), s_ESTtoGT);
67  // PRINT_DEBUG("[TRAJ]: q_GTtoEST = %.3f, %.3f, %.3f, %.3f | p_GTinEST = %.3f, %.3f, %.3f | s =
68  // %.2f\n",q_GTtoEST(0),q_GTtoEST(1),q_GTtoEST(2),q_GTtoEST(3),t_GTinEST(0),t_GTinEST(1),t_GTinEST(2),s_GTtoEST);
69 
70  // Finally lets calculate the aligned trajectories
71  for (size_t i = 0; i < gt_times.size(); i++) {
72  Eigen::Matrix<double, 7, 1> pose_ESTinGT, pose_GTinEST;
73  pose_ESTinGT.block(0, 0, 3, 1) = s_ESTtoGT * R_ESTtoGT * est_poses.at(i).block(0, 0, 3, 1) + t_ESTinGT;
74  pose_ESTinGT.block(3, 0, 4, 1) = ov_core::quat_multiply(est_poses.at(i).block(3, 0, 4, 1), ov_core::Inv(q_ESTtoGT));
75  pose_GTinEST.block(0, 0, 3, 1) = s_GTtoEST * R_GTtoEST * gt_poses.at(i).block(0, 0, 3, 1) + t_GTinEST;
76  pose_GTinEST.block(3, 0, 4, 1) = ov_core::quat_multiply(gt_poses.at(i).block(3, 0, 4, 1), ov_core::Inv(q_GTtoEST));
77  est_poses_aignedtoGT.push_back(pose_ESTinGT);
78  gt_poses_aignedtoEST.push_back(pose_GTinEST);
79  }
80 }
81 
83 
84  // Clear any old data
85  error_ori.clear();
86  error_pos.clear();
87 
88  // Calculate the position and orientation error at every timestep
89  for (size_t i = 0; i < est_poses_aignedtoGT.size(); i++) {
90 
91  // Calculate orientation error
92  Eigen::Matrix3d e_R = ov_core::quat_2_Rot(est_poses_aignedtoGT.at(i).block(3, 0, 4, 1)).transpose() *
93  ov_core::quat_2_Rot(gt_poses.at(i).block(3, 0, 4, 1));
94  double ori_err = 180.0 / M_PI * ov_core::log_so3(e_R).norm();
95 
96  // Calculate position error
97  double pos_err = (gt_poses.at(i).block(0, 0, 3, 1) - est_poses_aignedtoGT.at(i).block(0, 0, 3, 1)).norm();
98 
99  // Append this error!
100  error_ori.timestamps.push_back(est_times.at(i));
101  error_ori.values.push_back(ori_err);
102  error_pos.timestamps.push_back(est_times.at(i));
103  error_pos.values.push_back(pos_err);
104  }
105 
106  // Update stat information
107  error_ori.calculate();
108  error_pos.calculate();
109 }
110 
112 
113  // Clear any old data
114  error_ori.clear();
115  error_pos.clear();
116 
117  // Calculate the position and orientation error at every timestep
118  for (size_t i = 0; i < est_poses_aignedtoGT.size(); i++) {
119 
120  // Calculate orientation error
121  Eigen::Matrix3d e_R = ov_core::quat_2_Rot(est_poses_aignedtoGT.at(i).block(3, 0, 4, 1)).transpose() *
122  ov_core::quat_2_Rot(gt_poses.at(i).block(3, 0, 4, 1));
123  double ori_err = 180.0 / M_PI * ov_core::log_so3(e_R)(2);
124 
125  // Calculate position error
126  double pos_err = (gt_poses.at(i).block(0, 0, 2, 1) - est_poses_aignedtoGT.at(i).block(0, 0, 2, 1)).norm();
127 
128  // Append this error!
129  error_ori.timestamps.push_back(est_times.at(i));
130  error_ori.values.push_back(ori_err);
131  error_pos.timestamps.push_back(est_times.at(i));
132  error_pos.values.push_back(pos_err);
133  }
134 
135  // Update stat information
136  error_ori.calculate();
137  error_pos.calculate();
138 }
139 
140 void ResultTrajectory::calculate_rpe(const std::vector<double> &segment_lengths,
141  std::map<double, std::pair<Statistics, Statistics>> &error_rpe) {
142 
143  // Distance at each point along the trajectory
144  double average_pos_difference = 0;
145  std::vector<double> accum_distances(gt_poses.size());
146  accum_distances[0] = 0;
147  for (size_t i = 1; i < gt_poses.size(); i++) {
148  double pos_diff = (gt_poses[i].block(0, 0, 3, 1) - gt_poses[i - 1].block(0, 0, 3, 1)).norm();
149  accum_distances[i] = accum_distances[i - 1] + pos_diff;
150  average_pos_difference += pos_diff;
151  }
152  average_pos_difference /= gt_poses.size();
153 
154  // Warn if large pos difference
155  double max_dist_diff = 0.5;
156  if (average_pos_difference > max_dist_diff) {
157  PRINT_WARNING(YELLOW "[COMP]: average groundtruth position difference %.2f > %.2f is too large\n" RESET, average_pos_difference,
158  max_dist_diff);
159  PRINT_WARNING(YELLOW "[COMP]: this will prevent the RPE from finding valid trajectory segments!!!\n" RESET);
161  "[COMP]: the recommendation is to use a higher frequency groundtruth, or relax this trajectory segment logic...\n" RESET);
162  }
163 
164  // Loop through each segment length
165  for (const double &distance : segment_lengths) {
166 
167  // Our stats for this length
168  Statistics error_ori, error_pos;
169 
170  // Get end of subtrajectories for each possible starting point
171  // NOTE: is there a better way to select which end pos is a valid segments that are of the correct lenght?
172  // NOTE: right now this allows for longer segments to have bigger error in their start-end distance vs the desired segment length
173  // std::vector<int> comparisons = compute_comparison_indices_length(accum_distances, distance, 0.1*distance);
174  std::vector<int> comparisons = compute_comparison_indices_length(accum_distances, distance, max_dist_diff);
175  assert(comparisons.size() == gt_poses.size());
176 
177  // Loop through each relative comparison
178  for (size_t id_start = 0; id_start < comparisons.size(); id_start++) {
179 
180  // Get the end id (skip if we couldn't find an end)
181  int id_end = comparisons[id_start];
182  if (id_end == -1)
183  continue;
184 
185  //===============================================================================
186  // Get T I1 to world EST at beginning of subtrajectory (at state idx)
187  Eigen::Matrix4d T_c1 = Eigen::Matrix4d::Identity();
188  T_c1.block(0, 0, 3, 3) = ov_core::quat_2_Rot(est_poses_aignedtoGT.at(id_start).block(3, 0, 4, 1)).transpose();
189  T_c1.block(0, 3, 3, 1) = est_poses_aignedtoGT.at(id_start).block(0, 0, 3, 1);
190 
191  // Get T I2 to world EST at end of subtrajectory starting (at state comparisons[idx])
192  Eigen::Matrix4d T_c2 = Eigen::Matrix4d::Identity();
193  T_c2.block(0, 0, 3, 3) = ov_core::quat_2_Rot(est_poses_aignedtoGT.at(id_end).block(3, 0, 4, 1)).transpose();
194  T_c2.block(0, 3, 3, 1) = est_poses_aignedtoGT.at(id_end).block(0, 0, 3, 1);
195 
196  // Get T I2 to I1 EST
197  Eigen::Matrix4d T_c1_c2 = ov_core::Inv_se3(T_c1) * T_c2;
198 
199  //===============================================================================
200  // Get T I1 to world GT at beginning of subtrajectory (at state idx)
201  Eigen::Matrix4d T_m1 = Eigen::Matrix4d::Identity();
202  T_m1.block(0, 0, 3, 3) = ov_core::quat_2_Rot(gt_poses.at(id_start).block(3, 0, 4, 1)).transpose();
203  T_m1.block(0, 3, 3, 1) = gt_poses.at(id_start).block(0, 0, 3, 1);
204 
205  // Get T I2 to world GT at end of subtrajectory starting (at state comparisons[idx])
206  Eigen::Matrix4d T_m2 = Eigen::Matrix4d::Identity();
207  T_m2.block(0, 0, 3, 3) = ov_core::quat_2_Rot(gt_poses.at(id_end).block(3, 0, 4, 1)).transpose();
208  T_m2.block(0, 3, 3, 1) = gt_poses.at(id_end).block(0, 0, 3, 1);
209 
210  // Get T I2 to I1 GT
211  Eigen::Matrix4d T_m1_m2 = ov_core::Inv_se3(T_m1) * T_m2;
212 
213  //===============================================================================
214  // Compute error transform between EST and GT start-end transform
215  Eigen::Matrix4d T_error_in_c2 = ov_core::Inv_se3(T_m1_m2) * T_c1_c2;
216 
217  Eigen::Matrix4d T_c2_rot = Eigen::Matrix4d::Identity();
218  T_c2_rot.block(0, 0, 3, 3) = T_c2.block(0, 0, 3, 3);
219 
220  Eigen::Matrix4d T_c2_rot_inv = Eigen::Matrix4d::Identity();
221  T_c2_rot_inv.block(0, 0, 3, 3) = T_c2.block(0, 0, 3, 3).transpose();
222 
223  // Rotate rotation so that rotation error is in the global frame (allows us to look at yaw error)
224  Eigen::Matrix4d T_error_in_w = T_c2_rot * T_error_in_c2 * T_c2_rot_inv;
225 
226  //===============================================================================
227  // Compute error for position
228  error_pos.timestamps.push_back(est_times.at(id_start));
229  error_pos.values.push_back(T_error_in_w.block(0, 3, 3, 1).norm());
230 
231  // Calculate orientation error
232  double ori_err = 180.0 / M_PI * ov_core::log_so3(T_error_in_w.block(0, 0, 3, 3)).norm();
233  error_ori.timestamps.push_back(est_times.at(id_start));
234  error_ori.values.push_back(ori_err);
235  }
236 
237  // Update stat information
238  error_ori.calculate();
239  error_pos.calculate();
240  error_rpe.insert({distance, {error_ori, error_pos}});
241  }
242 }
243 
245 
246  // Check that we have our covariance matrices to normalize with
247  if (est_times.size() != est_covori.size() || est_times.size() != est_covpos.size() || gt_times.size() != gt_covori.size() ||
248  gt_times.size() != gt_covpos.size()) {
249  PRINT_WARNING(YELLOW "[TRAJ]: Normalized Estimation Error Squared called but trajectory does not have any covariances...\n" RESET);
250  PRINT_WARNING(YELLOW "[TRAJ]: Did you record using a Odometry or PoseWithCovarianceStamped????\n" RESET);
251  return;
252  }
253 
254  // Clear any old data
255  nees_ori.clear();
256  nees_pos.clear();
257 
258  // Calculate the position and orientation error at every timestep
259  for (size_t i = 0; i < est_poses.size(); i++) {
260 
261  // Calculate orientation error
262  // NOTE: we define our error as e_R = -Log(R*Rhat^T)
263  Eigen::Matrix3d e_R = ov_core::quat_2_Rot(gt_poses_aignedtoEST.at(i).block(3, 0, 4, 1)) *
264  ov_core::quat_2_Rot(est_poses.at(i).block(3, 0, 4, 1)).transpose();
265  Eigen::Vector3d errori = -ov_core::log_so3(e_R);
266  // Eigen::Vector4d e_q = Math::quat_multiply(gt_poses_aignedtoEST.at(i).block(3,0,4,1),Math::Inv(est_poses.at(i).block(3,0,4,1)));
267  // Eigen::Vector3d errori = 2*e_q.block(0,0,3,1);
268  double ori_nees = errori.transpose() * est_covori.at(i).inverse() * errori;
269 
270  // Calculate nees position error
271  Eigen::Vector3d errpos = gt_poses_aignedtoEST.at(i).block(0, 0, 3, 1) - est_poses.at(i).block(0, 0, 3, 1);
272  double pos_nees = errpos.transpose() * est_covpos.at(i).inverse() * errpos;
273 
274  // Skip if nan error value
275  if (std::isnan(ori_nees) || std::isnan(pos_nees)) {
276  PRINT_WARNING(YELLOW "[TRAJ]: nees calculation had nan number (covariance is wrong?) skipping...\n" RESET);
277  continue;
278  }
279 
280  // Append this error!
281  nees_ori.timestamps.push_back(est_times.at(i));
282  nees_ori.values.push_back(ori_nees);
283  nees_pos.timestamps.push_back(est_times.at(i));
284  nees_pos.values.push_back(pos_nees);
285  }
286 
287  // Update stat information
288  nees_ori.calculate();
289  nees_pos.calculate();
290 }
291 
293  Statistics &oriz, Statistics &roll, Statistics &pitch, Statistics &yaw) {
294 
295  // Clear any old data
296  posx.clear();
297  posy.clear();
298  posz.clear();
299  orix.clear();
300  oriy.clear();
301  oriz.clear();
302  roll.clear();
303  pitch.clear();
304  yaw.clear();
305 
306  // Calculate the position and orientation error at every timestep
307  for (size_t i = 0; i < est_poses.size(); i++) {
308 
309  // Calculate local orientation error, then propagate its covariance into the global frame of reference
310  Eigen::Vector4d e_q =
311  ov_core::quat_multiply(gt_poses_aignedtoEST.at(i).block(3, 0, 4, 1), ov_core::Inv(est_poses.at(i).block(3, 0, 4, 1)));
312  Eigen::Vector3d errori_local = 2 * e_q.block(0, 0, 3, 1);
313  Eigen::Vector3d errori_global = ov_core::quat_2_Rot(est_poses.at(i).block(3, 0, 4, 1)).transpose() * errori_local;
314  Eigen::Matrix3d cov_global;
315  if (est_times.size() == est_covori.size()) {
316  cov_global = ov_core::quat_2_Rot(est_poses.at(i).block(3, 0, 4, 1)).transpose() * est_covori.at(i) *
317  ov_core::quat_2_Rot(est_poses.at(i).block(3, 0, 4, 1));
318  }
319 
320  // Convert to roll pitch yaw (also need to "wrap" the error to -pi to pi)
321  // NOTE: our rot2rpy is in the form R_input = R_z(yaw)*R_y(pitch)*R_x(roll)
322  // NOTE: this error is in the "global" frame since we do rot2rpy on R_ItoG rotation
323  Eigen::Vector3d ypr_est_ItoG = ov_core::rot2rpy(ov_core::quat_2_Rot(est_poses.at(i).block(3, 0, 4, 1)).transpose());
324  Eigen::Vector3d ypr_gt_ItoG = ov_core::rot2rpy(ov_core::quat_2_Rot(gt_poses_aignedtoEST.at(i).block(3, 0, 4, 1)).transpose());
325  Eigen::Vector3d errori_rpy = ypr_gt_ItoG - ypr_est_ItoG;
326  for (size_t idx = 0; idx < 3; idx++) {
327  while (errori_rpy(idx) < -M_PI) {
328  errori_rpy(idx) += 2 * M_PI;
329  }
330  while (errori_rpy(idx) > M_PI) {
331  errori_rpy(idx) -= 2 * M_PI;
332  }
333  }
334 
335  // Next need to propagate our covariance to the RPY frame of reference
336  // NOTE: one can derive this by perturbing the rpy error equation
337  // NOTE: R*Exp(theta_erro) = Rz*Rz(error)*Ry*Ry(error)*Rx*Rx(error)
338  // NOTE: example can be found here http://mars.cs.umn.edu/tr/reports/Trawny05c.pdf
339  Eigen::Matrix<double, 3, 3> H_xyz2rpy = Eigen::Matrix<double, 3, 3>::Identity();
340  H_xyz2rpy.block(0, 1, 3, 1) = ov_core::rot_x(-ypr_est_ItoG(0)) * H_xyz2rpy.block(0, 1, 3, 1);
341  H_xyz2rpy.block(0, 2, 3, 1) = ov_core::rot_x(-ypr_est_ItoG(0)) * ov_core::rot_y(-ypr_est_ItoG(1)) * H_xyz2rpy.block(0, 2, 3, 1);
342  Eigen::Matrix3d cov_rpy;
343  if (est_times.size() == est_covori.size()) {
344  cov_rpy = H_xyz2rpy.inverse() * est_covori.at(i) * H_xyz2rpy.inverse().transpose();
345  }
346 
347  // Calculate position error
348  Eigen::Vector3d errpos = gt_poses_aignedtoEST.at(i).block(0, 0, 3, 1) - est_poses.at(i).block(0, 0, 3, 1);
349 
350  // POSITION: Append this error!
351  posx.timestamps.push_back(est_times.at(i));
352  posx.values.push_back(errpos(0));
353  posy.timestamps.push_back(est_times.at(i));
354  posy.values.push_back(errpos(1));
355  posz.timestamps.push_back(est_times.at(i));
356  posz.values.push_back(errpos(2));
357  if (est_times.size() == est_covpos.size()) {
358  posx.values_bound.push_back(3 * std::sqrt(est_covpos.at(i)(0, 0)));
359  posy.values_bound.push_back(3 * std::sqrt(est_covpos.at(i)(1, 1)));
360  posz.values_bound.push_back(3 * std::sqrt(est_covpos.at(i)(2, 2)));
361  }
362 
363  // ORIENTATION: Append this error!
364  orix.timestamps.push_back(est_times.at(i));
365  orix.values.push_back(180.0 / M_PI * errori_global(0));
366  oriy.timestamps.push_back(est_times.at(i));
367  oriy.values.push_back(180.0 / M_PI * errori_global(1));
368  oriz.timestamps.push_back(est_times.at(i));
369  oriz.values.push_back(180.0 / M_PI * errori_global(2));
370  if (est_times.size() == est_covori.size()) {
371  orix.values_bound.push_back(3 * 180.0 / M_PI * std::sqrt(cov_global(0, 0)));
372  oriy.values_bound.push_back(3 * 180.0 / M_PI * std::sqrt(cov_global(1, 1)));
373  oriz.values_bound.push_back(3 * 180.0 / M_PI * std::sqrt(cov_global(2, 2)));
374  }
375 
376  // RPY: Append this error!
377  roll.timestamps.push_back(est_times.at(i));
378  roll.values.push_back(180.0 / M_PI * errori_rpy(0));
379  pitch.timestamps.push_back(est_times.at(i));
380  pitch.values.push_back(180.0 / M_PI * errori_rpy(1));
381  yaw.timestamps.push_back(est_times.at(i));
382  yaw.values.push_back(180.0 / M_PI * errori_rpy(2));
383  if (est_times.size() == est_covori.size()) {
384  roll.values_bound.push_back(3 * 180.0 / M_PI * std::sqrt(cov_rpy(0, 0)));
385  pitch.values_bound.push_back(3 * 180.0 / M_PI * std::sqrt(cov_rpy(1, 1)));
386  yaw.values_bound.push_back(3 * 180.0 / M_PI * std::sqrt(cov_rpy(2, 2)));
387  }
388  }
389 
390  // Update stat information
391  posx.calculate();
392  posy.calculate();
393  posz.calculate();
394  orix.calculate();
395  oriy.calculate();
396  oriz.calculate();
397  roll.calculate();
398  pitch.calculate();
399  yaw.calculate();
400 }
Eigen::Matrix< double, 4, 1 > quat_multiply(const Eigen::Matrix< double, 4, 1 > &q, const Eigen::Matrix< double, 4, 1 > &p)
Statistics object for a given set scalar time series values.
Definition: Statistics.h:39
std::vector< Eigen::Matrix< double, 7, 1 > > est_poses
std::vector< Eigen::Matrix< double, 7, 1 > > est_poses_aignedtoGT
static void load_data(std::string path_traj, std::vector< double > &times, std::vector< Eigen::Matrix< double, 7, 1 >> &poses, std::vector< Eigen::Matrix3d > &cov_ori, std::vector< Eigen::Matrix3d > &cov_pos)
This will load space separated trajectory into memory.
Definition: Loader.cpp:26
static void perform_association(double offset, double max_difference, std::vector< double > &est_times, std::vector< double > &gt_times, std::vector< Eigen::Matrix< double, 7, 1 >> &est_poses, std::vector< Eigen::Matrix< double, 7, 1 >> &gt_poses)
Will intersect our loaded data so that we have common timestamps.
Definition: AlignUtils.cpp:95
Eigen::Matrix< double, 3, 3 > rot_x(double t)
void calculate_nees(Statistics &nees_ori, Statistics &nees_pos)
Computes the Normalized Estimation Error Squared (NEES) for this trajectory.
#define RESET
RED
std::vector< Eigen::Matrix< double, 7, 1 > > gt_poses_aignedtoEST
std::vector< double > values
Values (e.g. error or nees at a given time)
Definition: Statistics.h:67
Eigen::Matrix< double, 4, 1 > Inv(Eigen::Matrix< double, 4, 1 > q)
void calculate_error(Statistics &posx, Statistics &posy, Statistics &posz, Statistics &orix, Statistics &oriy, Statistics &oriz, Statistics &roll, Statistics &pitch, Statistics &yaw)
Computes the error at each timestamp for this trajectory.
YELLOW
static double get_total_length(const std::vector< Eigen::Matrix< double, 7, 1 >> &poses)
Will calculate the total trajectory distance.
Definition: Loader.cpp:388
std::vector< double > gt_times
Evaluation and recording utilities.
std::vector< Eigen::Matrix3d > est_covori
void calculate()
Will calculate all values from our vectors of information.
Definition: Statistics.h:73
static void align_trajectory(const std::vector< Eigen::Matrix< double, 7, 1 >> &traj_es, const std::vector< Eigen::Matrix< double, 7, 1 >> &traj_gt, Eigen::Matrix3d &R, Eigen::Vector3d &t, double &s, std::string method, int n_aligned=-1)
Align estimate to GT using a desired method using a set of initial poses.
ResultTrajectory(std::string path_est, std::string path_gt, std::string alignment_method)
Default constructor that will load, intersect, and align our trajectories.
std::vector< Eigen::Matrix3d > est_covpos
Eigen::Matrix< double, 3, 1 > log_so3(const Eigen::Matrix< double, 3, 3 > &R)
std::vector< Eigen::Matrix3d > gt_covpos
std::vector< double > values_bound
Bound of these values (e.g. our expected covariance bound)
Definition: Statistics.h:70
Eigen::Matrix< double, 4, 1 > rot_2_quat(const Eigen::Matrix< double, 3, 3 > &rot)
void calculate_ate(Statistics &error_ori, Statistics &error_pos)
Computes the Absolute Trajectory Error (ATE) for this trajectory.
std::vector< Eigen::Matrix3d > gt_covori
void calculate_ate_2d(Statistics &error_ori, Statistics &error_pos)
Computes the Absolute Trajectory Error (ATE) for this trajectory in the 2d x-y plane.
Eigen::Matrix< double, 3, 1 > rot2rpy(const Eigen::Matrix< double, 3, 3 > &rot)
Eigen::Matrix4d Inv_se3(const Eigen::Matrix4d &T)
std::vector< int > compute_comparison_indices_length(std::vector< double > &distances, double distance, double max_dist_diff)
Gets the indices at the end of subtractories of a given length when starting at each index...
Eigen::Matrix< double, 3, 3 > quat_2_Rot(const Eigen::Matrix< double, 4, 1 > &q)
void clear()
Will clear any old values.
Definition: Statistics.h:124
Eigen::Matrix< double, 3, 3 > rot_y(double t)
std::vector< Eigen::Matrix< double, 7, 1 > > gt_poses
void calculate_rpe(const std::vector< double > &segment_lengths, std::map< double, std::pair< Statistics, Statistics >> &error_rpe)
Computes the Relative Pose Error (RPE) for this trajectory.
std::vector< double > est_times
std::vector< double > timestamps
Timestamp when these values occured at.
Definition: Statistics.h:64


ov_eval
Author(s): Patrick Geneva , Kevin Eckenhoff , Guoquan Huang
autogenerated on Wed Jun 21 2023 03:05:40