39 #include <gtsam/geometry/Pose2.h> 40 #include <gtsam/geometry/Pose3.h> 41 #include <gtsam/inference/Key.h> 42 #include <gtsam/inference/Symbol.h> 43 #include <gtsam/slam/PriorFactor.h> 44 #include <gtsam/slam/BetweenFactor.h> 45 #include <gtsam/sam/BearingRangeFactor.h> 46 #include <gtsam/nonlinear/NonlinearFactorGraph.h> 47 #include <gtsam/nonlinear/GaussNewtonOptimizer.h> 48 #include <gtsam/nonlinear/DoglegOptimizer.h> 49 #include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h> 50 #include <gtsam/nonlinear/NonlinearOptimizer.h> 51 #include <gtsam/nonlinear/Marginals.h> 52 #include <gtsam/nonlinear/Values.h> 57 #ifdef RTABMAP_VERTIGO 61 #endif // end RTABMAP_GTSAM 82 const std::map<int, Transform> & poses,
83 const std::multimap<int, Link> & edgeConstraints,
84 cv::Mat & outputCovariance,
85 std::list<std::map<int, Transform> > * intermediateGraphes,
89 outputCovariance = cv::Mat::eye(6,6,CV_64FC1);
90 std::map<int, Transform> optimizedPoses;
93 #ifndef RTABMAP_VERTIGO 96 UWARN(
"Vertigo robust optimization is not available! Robust optimization is now disabled.");
101 UDEBUG(
"Optimizing graph...");
102 if(edgeConstraints.size()>=1 && poses.size()>=2 &&
iterations() > 0)
104 gtsam::NonlinearFactorGraph graph;
107 bool hasGPSPrior =
false;
108 bool hasGravityConstraints =
false;
111 for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
113 if(iter->second.from() == iter->second.to())
118 if ((
isSlam2d() && 1 / static_cast<double>(iter->second.infMatrix().at<
double>(5,5)) < 9999) ||
119 (1 / static_cast<double>(iter->second.infMatrix().at<
double>(3,3)) < 9999.0 &&
120 1 /
static_cast<double>(iter->second.infMatrix().at<
double>(4,4)) < 9999.0 &&
121 1 /
static_cast<double>(iter->second.infMatrix().at<
double>(5,5)) < 9999.0))
131 hasGravityConstraints =
true;
145 const Transform & initialPose = poses.at(rootId);
146 UDEBUG(
"hasGPSPrior=%s", hasGPSPrior?
"true":
"false");
149 gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(gtsam::Vector3(0.01, 0.01, hasGPSPrior?1
e-2:
std::numeric_limits<double>::min()));
150 graph.add(gtsam::PriorFactor<gtsam::Pose2>(rootId, gtsam::Pose2(initialPose.
x(), initialPose.
y(), initialPose.
theta()), priorNoise));
154 gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(
157 (hasGPSPrior?2:1
e-2), hasGPSPrior?2:1
e-2, hasGPSPrior?2:1
e-2
159 graph.add(gtsam::PriorFactor<gtsam::Pose3>(rootId, gtsam::Pose3(initialPose.
toEigen4d()), priorNoise));
163 UDEBUG(
"fill poses to gtsam... rootId=%d (priorsIgnored=%d landmarksIgnored=%d)",
165 gtsam::Values initialEstimate;
166 std::map<int, bool> isLandmarkWithRotation;
167 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
169 UASSERT(!iter->second.isNull());
174 initialEstimate.insert(iter->first, gtsam::Pose2(iter->second.x(), iter->second.y(), iter->second.theta()));
179 std::multimap<int, Link>::const_iterator jter=edgeConstraints.find(iter->first);
180 UASSERT_MSG(jter != edgeConstraints.end(),
uFormat(
"Not found landmark %d in edges!", iter->first).c_str());
182 if (1 / static_cast<double>(jter->second.infMatrix().at<
double>(5,5)) >= 9999.0)
184 initialEstimate.insert(iter->first, gtsam::Point2(iter->second.x(), iter->second.y()));
185 isLandmarkWithRotation.insert(std::make_pair(iter->first,
false));
189 initialEstimate.insert(iter->first, gtsam::Pose2(iter->second.x(), iter->second.y(), iter->second.theta()));
190 isLandmarkWithRotation.insert(std::make_pair(iter->first,
true));
199 initialEstimate.insert(iter->first, gtsam::Pose3(iter->second.toEigen4d()));
204 std::multimap<int, Link>::const_iterator jter=edgeConstraints.find(iter->first);
205 UASSERT_MSG(jter != edgeConstraints.end(),
uFormat(
"Not found landmark %d in edges!", iter->first).c_str());
207 if (1 / static_cast<double>(jter->second.infMatrix().at<
double>(3,3)) >= 9999.0 ||
208 1 /
static_cast<double>(jter->second.infMatrix().at<
double>(4,4)) >= 9999.0 ||
209 1 /
static_cast<double>(jter->second.infMatrix().at<
double>(5,5)) >= 9999.0)
211 initialEstimate.insert(iter->first, gtsam::Point3(iter->second.x(), iter->second.y(), iter->second.z()));
212 isLandmarkWithRotation.insert(std::make_pair(iter->first,
false));
216 initialEstimate.insert(iter->first, gtsam::Pose3(iter->second.toEigen4d()));
217 isLandmarkWithRotation.insert(std::make_pair(iter->first,
true));
223 UDEBUG(
"fill edges to gtsam...");
224 int switchCounter = poses.rbegin()->first+1;
225 for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
227 int id1 = iter->second.from();
228 int id2 = iter->second.to();
230 UASSERT_MSG(initialEstimate.find(id1)!=initialEstimate.end(),
uFormat(
"id1=%d", id1).c_str());
231 UASSERT_MSG(initialEstimate.find(id2)!=initialEstimate.end(),
uFormat(
"id2=%d", id2).c_str());
233 UASSERT(!iter->second.transform().isNull());
241 if(id1 < 0 && !isLandmarkWithRotation.at(id1))
243 noiseModel::Diagonal::shared_ptr
model = noiseModel::Diagonal::Variances(Vector2(
244 1/iter->second.infMatrix().at<
double>(0,0),
245 1/iter->second.infMatrix().at<
double>(1,1)));
246 graph.add(
XYFactor<gtsam::Point2>(id1, gtsam::Point2(iter->second.transform().x(), iter->second.transform().y()), model));
248 else if (1 / static_cast<double>(iter->second.infMatrix().at<
double>(5,5)) >= 9999.0)
250 noiseModel::Diagonal::shared_ptr
model = noiseModel::Diagonal::Variances(Vector2(
251 1/iter->second.infMatrix().at<
double>(0,0),
252 1/iter->second.infMatrix().at<
double>(1,1)));
253 graph.add(
XYFactor<gtsam::Pose2>(id1, gtsam::Point2(iter->second.transform().x(), iter->second.transform().y()), model));
257 Eigen::Matrix<double, 3, 3> information = Eigen::Matrix<double, 3, 3>::Identity();
260 information(0,0) = iter->second.infMatrix().at<
double>(0,0);
261 information(0,1) = iter->second.infMatrix().at<
double>(0,1);
262 information(0,2) = iter->second.infMatrix().at<
double>(0,5);
263 information(1,0) = iter->second.infMatrix().at<
double>(1,0);
264 information(1,1) = iter->second.infMatrix().at<
double>(1,1);
265 information(1,2) = iter->second.infMatrix().at<
double>(1,5);
266 information(2,0) = iter->second.infMatrix().at<
double>(5,0);
267 information(2,1) = iter->second.infMatrix().at<
double>(5,1);
268 information(2,2) = iter->second.infMatrix().at<
double>(5,5);
271 gtsam::noiseModel::Gaussian::shared_ptr
model = gtsam::noiseModel::Gaussian::Information(information);
272 graph.add(gtsam::PriorFactor<gtsam::Pose2>(id1, gtsam::Pose2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()), model));
277 if(id1 < 0 && !isLandmarkWithRotation.at(id1))
279 noiseModel::Diagonal::shared_ptr
model = noiseModel::Diagonal::Precisions(Vector3(
280 iter->second.infMatrix().at<
double>(0,0),
281 iter->second.infMatrix().at<
double>(1,1),
282 iter->second.infMatrix().at<
double>(2,2)));
283 graph.add(
XYZFactor<gtsam::Point3>(id1, gtsam::Point3(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().z()), model));
285 else if (1 / static_cast<double>(iter->second.infMatrix().at<
double>(3,3)) >= 9999.0 ||
286 1 /
static_cast<double>(iter->second.infMatrix().at<
double>(4,4)) >= 9999.0 ||
287 1 /
static_cast<double>(iter->second.infMatrix().at<
double>(5,5)) >= 9999.0)
289 noiseModel::Diagonal::shared_ptr
model = noiseModel::Diagonal::Precisions(Vector3(
290 iter->second.infMatrix().at<
double>(0,0),
291 iter->second.infMatrix().at<
double>(1,1),
292 iter->second.infMatrix().at<
double>(2,2)));
293 graph.add(
XYZFactor<gtsam::Pose3>(id1, gtsam::Point3(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().z()), model));
297 Eigen::Matrix<double, 6, 6> information = Eigen::Matrix<double, 6, 6>::Identity();
300 memcpy(information.data(), iter->second.infMatrix().data, iter->second.infMatrix().total()*
sizeof(double));
303 Eigen::Matrix<double, 6, 6> mgtsam = Eigen::Matrix<double, 6, 6>::Identity();
304 mgtsam.block(0,0,3,3) = information.block(3,3,3,3);
305 mgtsam.block(3,3,3,3) = information.block(0,0,3,3);
306 mgtsam.block(0,3,3,3) = information.block(3,0,3,3);
307 mgtsam.block(3,0,3,3) = information.block(0,3,3,3);
308 gtsam::SharedNoiseModel
model = gtsam::noiseModel::Gaussian::Information(mgtsam);
310 graph.add(gtsam::PriorFactor<gtsam::Pose3>(id1, gtsam::Pose3(iter->second.transform().toEigen4d()), model));
316 Vector3 r = gtsam::Pose3(iter->second.transform().toEigen4d()).
rotation().xyz();
317 gtsam::Unit3 nG = gtsam::Rot3::RzRyRx(r.x(), r.y(), 0).
rotate(gtsam::Unit3(0,0,-1));
318 gtsam::SharedNoiseModel
model = gtsam::noiseModel::Isotropic::Sigmas(gtsam::Vector2(
gravitySigma(), 10));
322 else if(id1<0 || id2 < 0)
327 UASSERT((id1 < 0 && id2 > 0) || (id1 > 0 && id2 < 0));
331 t = iter->second.transform();
335 t = iter->second.transform().
inverse();
340 if(isLandmarkWithRotation.at(id2))
342 Eigen::Matrix<double, 3, 3> information = Eigen::Matrix<double, 3, 3>::Identity();
345 information(0,0) = iter->second.infMatrix().at<
double>(0,0);
346 information(0,1) = iter->second.infMatrix().at<
double>(0,1);
347 information(0,2) = iter->second.infMatrix().at<
double>(0,5);
348 information(1,0) = iter->second.infMatrix().at<
double>(1,0);
349 information(1,1) = iter->second.infMatrix().at<
double>(1,1);
350 information(1,2) = iter->second.infMatrix().at<
double>(1,5);
351 information(2,0) = iter->second.infMatrix().at<
double>(5,0);
352 information(2,1) = iter->second.infMatrix().at<
double>(5,1);
353 information(2,2) = iter->second.infMatrix().at<
double>(5,5);
355 gtsam::noiseModel::Gaussian::shared_ptr
model = gtsam::noiseModel::Gaussian::Information(information);
356 graph.add(gtsam::BetweenFactor<gtsam::Pose2>(id1, id2, gtsam::Pose2(t.
x(), t.
y(), t.
theta()), model));
360 Eigen::Matrix<double, 2, 2> information = Eigen::Matrix<double, 2, 2>::Identity();
363 cv::Mat linearCov = cv::Mat(iter->second.infMatrix(), cv::Range(0,2), cv::Range(0,2)).clone();;
364 memcpy(information.data(), linearCov.data, linearCov.total()*
sizeof(double));
366 gtsam::SharedNoiseModel
model = gtsam::noiseModel::Gaussian::Information(information);
368 gtsam::Point2 landmark(t.
x(), t.
y());
370 graph.add(gtsam::BearingRangeFactor<gtsam::Pose2, gtsam::Point2>(id1, id2, p.bearing(landmark), p.range(landmark),
model));
375 if(isLandmarkWithRotation.at(id2))
377 Eigen::Matrix<double, 6, 6> information = Eigen::Matrix<double, 6, 6>::Identity();
380 memcpy(information.data(), iter->second.infMatrix().data, iter->second.infMatrix().total()*
sizeof(double));
383 Eigen::Matrix<double, 6, 6> mgtsam = Eigen::Matrix<double, 6, 6>::Identity();
384 mgtsam.block(0,0,3,3) = information.block(3,3,3,3);
385 mgtsam.block(3,3,3,3) = information.block(0,0,3,3);
386 mgtsam.block(0,3,3,3) = information.block(3,0,3,3);
387 mgtsam.block(3,0,3,3) = information.block(0,3,3,3);
388 gtsam::SharedNoiseModel
model = gtsam::noiseModel::Gaussian::Information(mgtsam);
389 graph.add(gtsam::BetweenFactor<gtsam::Pose3>(id1, id2, gtsam::Pose3(t.
toEigen4d()), model));
393 Eigen::Matrix<double, 3, 3> information = Eigen::Matrix<double, 3, 3>::Identity();
396 cv::Mat linearCov = cv::Mat(iter->second.infMatrix(), cv::Range(0,3), cv::Range(0,3)).clone();;
397 memcpy(information.data(), linearCov.data, linearCov.total()*
sizeof(double));
399 gtsam::SharedNoiseModel
model = gtsam::noiseModel::Gaussian::Information(information);
401 gtsam::Point3 landmark(t.
x(), t.
y(), t.
z());
403 graph.add(gtsam::BearingRangeFactor<gtsam::Pose3, gtsam::Point3>(id1, id2, p.bearing(landmark), p.range(landmark),
model));
410 #ifdef RTABMAP_VERTIGO 428 gtsam::noiseModel::Diagonal::shared_ptr switchPriorModel = gtsam::noiseModel::Diagonal::Sigmas(gtsam::Vector1(1.0));
429 graph.add(gtsam::PriorFactor<vertigo::SwitchVariableLinear> (gtsam::Symbol(
's',switchCounter),
vertigo::SwitchVariableLinear(prior), switchPriorModel));
434 Eigen::Matrix<double, 3, 3> information = Eigen::Matrix<double, 3, 3>::Identity();
437 information(0,0) = iter->second.infMatrix().at<
double>(0,0);
438 information(0,1) = iter->second.infMatrix().at<
double>(0,1);
439 information(0,2) = iter->second.infMatrix().at<
double>(0,5);
440 information(1,0) = iter->second.infMatrix().at<
double>(1,0);
441 information(1,1) = iter->second.infMatrix().at<
double>(1,1);
442 information(1,2) = iter->second.infMatrix().at<
double>(1,5);
443 information(2,0) = iter->second.infMatrix().at<
double>(5,0);
444 information(2,1) = iter->second.infMatrix().at<
double>(5,1);
445 information(2,2) = iter->second.infMatrix().at<
double>(5,5);
447 gtsam::noiseModel::Gaussian::shared_ptr
model = gtsam::noiseModel::Gaussian::Information(information);
449 #ifdef RTABMAP_VERTIGO 460 graph.add(gtsam::BetweenFactor<gtsam::Pose2>(id1, id2, gtsam::Pose2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()), model));
465 Eigen::Matrix<double, 6, 6> information = Eigen::Matrix<double, 6, 6>::Identity();
468 memcpy(information.data(), iter->second.infMatrix().data, iter->second.infMatrix().total()*
sizeof(double));
471 Eigen::Matrix<double, 6, 6> mgtsam = Eigen::Matrix<double, 6, 6>::Identity();
472 mgtsam.block(0,0,3,3) = information.block(3,3,3,3);
473 mgtsam.block(3,3,3,3) = information.block(0,0,3,3);
474 mgtsam.block(0,3,3,3) = information.block(3,0,3,3);
475 mgtsam.block(3,0,3,3) = information.block(0,3,3,3);
476 gtsam::SharedNoiseModel
model = gtsam::noiseModel::Gaussian::Information(mgtsam);
478 #ifdef RTABMAP_VERTIGO 489 graph.add(gtsam::BetweenFactor<gtsam::Pose3>(id1, id2, gtsam::Pose3(iter->second.transform().toEigen4d()), model));
495 UDEBUG(
"create optimizer");
496 gtsam::NonlinearOptimizer * optimizer;
500 gtsam::DoglegParams parameters;
501 parameters.relativeErrorTol =
epsilon();
503 optimizer =
new gtsam::DoglegOptimizer(graph, initialEstimate, parameters);
507 gtsam::GaussNewtonParams parameters;
508 parameters.relativeErrorTol =
epsilon();
510 optimizer =
new gtsam::GaussNewtonOptimizer(graph, initialEstimate, parameters);
514 gtsam::LevenbergMarquardtParams parameters;
515 parameters.relativeErrorTol =
epsilon();
517 optimizer =
new gtsam::LevenbergMarquardtOptimizer(graph, initialEstimate, parameters);
523 double lastError = optimizer->error();
526 if(intermediateGraphes && i > 0)
529 std::map<int, Transform> tmpPoses;
530 for(gtsam::Values::const_iterator iter=optimizer->values().begin(); iter!=optimizer->values().end(); ++iter)
532 if(iter->value.dim() > 1)
534 int key = (int)iter->key;
539 gtsam::Pose2 p = iter->value.cast<gtsam::Pose2>();
540 tmpPoses.insert(std::make_pair(key,
Transform(p.x(), p.y(), p.theta())));
542 else if(!
landmarksIgnored() && isLandmarkWithRotation.find(key)!=isLandmarkWithRotation.end())
544 if(isLandmarkWithRotation.at(key))
546 poses.at(key).getTranslationAndEulerAngles(x,y,z,roll,pitch,yaw);
547 gtsam::Pose2 p = iter->value.cast<gtsam::Pose2>();
548 tmpPoses.insert(std::make_pair(key,
Transform(p.x(), p.y(), z,
roll,
pitch, p.theta())));
552 poses.at(key).getTranslationAndEulerAngles(x,y,z,roll,pitch,yaw);
553 gtsam::Point2 p = iter->value.cast<gtsam::Point2>();
562 gtsam::Pose3 p = iter->value.cast<gtsam::Pose3>();
565 else if(!
landmarksIgnored() && isLandmarkWithRotation.find(key)!=isLandmarkWithRotation.end())
567 if(isLandmarkWithRotation.at(key))
569 gtsam::Pose3 p = iter->value.cast<gtsam::Pose3>();
574 poses.at(key).getTranslationAndEulerAngles(x,y,z,roll,pitch,yaw);
575 gtsam::Point3 p = iter->value.cast<gtsam::Point3>();
582 intermediateGraphes->push_back(tmpPoses);
586 optimizer->iterate();
589 catch(gtsam::IndeterminantLinearSystemException &
e)
591 UWARN(
"GTSAM exception caught: %s\n Graph has %d edges and %d vertices", e.what(),
592 (int)edgeConstraints.size(),
595 return optimizedPoses;
599 double error = optimizer->error();
600 UDEBUG(
"iteration %d error =%f", i+1, error);
601 double errorDelta = lastError - error;
602 if(i>0 && errorDelta < this->
epsilon())
606 UDEBUG(
"Negative improvement?! Ignore and continue optimizing... (%f < %f)", errorDelta, this->
epsilon());
610 UDEBUG(
"Stop optimizing, not enough improvement (%f < %f)", errorDelta, this->
epsilon());
614 else if(i==0 && error < this->
epsilon())
616 UINFO(
"Stop optimizing, error is already under epsilon (%f < %f)", error, this->
epsilon());
623 *finalError = lastError;
627 *iterationsDone = it;
629 UDEBUG(
"GTSAM optimizing end (%d iterations done, error=%f (initial=%f final=%f), time=%f s)",
630 optimizer->iterations(), optimizer->error(), graph.error(initialEstimate), graph.error(optimizer->values()), timer.
ticks());
633 for(gtsam::Values::const_iterator iter=optimizer->values().begin(); iter!=optimizer->values().end(); ++iter)
635 if(iter->value.dim() > 1)
637 int key = (int)iter->key;
642 poses.at(key).getTranslationAndEulerAngles(x,y,z,roll,pitch,yaw);
643 gtsam::Pose2 p = iter->value.cast<gtsam::Pose2>();
644 optimizedPoses.insert(std::make_pair(key,
Transform(p.x(), p.y(), z,
roll,
pitch, p.theta())));
646 else if(!
landmarksIgnored() && isLandmarkWithRotation.find(key)!=isLandmarkWithRotation.end())
648 if(isLandmarkWithRotation.at(key))
650 poses.at(key).getTranslationAndEulerAngles(x,y,z,roll,pitch,yaw);
651 gtsam::Pose2 p = iter->value.cast<gtsam::Pose2>();
652 optimizedPoses.insert(std::make_pair(key,
Transform(p.x(), p.y(), z,
roll,
pitch, p.theta())));
656 poses.at(key).getTranslationAndEulerAngles(x,y,z,roll,pitch,yaw);
657 gtsam::Point2 p = iter->value.cast<gtsam::Point2>();
666 gtsam::Pose3 p = iter->value.cast<gtsam::Pose3>();
669 else if(!
landmarksIgnored() && isLandmarkWithRotation.find(key)!=isLandmarkWithRotation.end())
671 if(isLandmarkWithRotation.at(key))
673 gtsam::Pose3 p = iter->value.cast<gtsam::Pose3>();
678 poses.at(key).getTranslationAndEulerAngles(x,y,z,roll,pitch,yaw);
679 gtsam::Point3 p = iter->value.cast<gtsam::Point3>();
689 UDEBUG(
"Computing marginals...");
691 gtsam::Marginals marginals(graph, optimizer->values());
692 gtsam::Matrix info = marginals.marginalCovariance(poses.rbegin()->first);
693 UDEBUG(
"Computed marginals = %fs (key=%d)", t.
ticks(), poses.rbegin()->first);
694 if(
isSlam2d() && info.cols() == 3 && info.cols() == 3)
696 outputCovariance.at<
double>(0,0) = info(0,0);
697 outputCovariance.at<
double>(0,1) = info(0,1);
698 outputCovariance.at<
double>(0,5) = info(0,2);
699 outputCovariance.at<
double>(1,0) = info(1,0);
700 outputCovariance.at<
double>(1,1) = info(1,1);
701 outputCovariance.at<
double>(1,5) = info(1,2);
702 outputCovariance.at<
double>(5,0) = info(2,0);
703 outputCovariance.at<
double>(5,1) = info(2,1);
704 outputCovariance.at<
double>(5,5) = info(2,2);
706 else if(!
isSlam2d() && info.cols() == 6 && info.cols() == 6)
708 Eigen::Matrix<double, 6, 6> mgtsam = Eigen::Matrix<double, 6, 6>::Identity();
709 mgtsam.block(3,3,3,3) = info.block(0,0,3,3);
710 mgtsam.block(0,0,3,3) = info.block(3,3,3,3);
711 mgtsam.block(0,3,3,3) = info.block(3,0,3,3);
712 mgtsam.block(3,0,3,3) = info.block(0,3,3,3);
713 memcpy(outputCovariance.data, mgtsam.data(), outputCovariance.total()*
sizeof(double));
717 UERROR(
"GTSAM: Could not compute marginal covariance!");
718 optimizedPoses.clear();
721 catch(gtsam::IndeterminantLinearSystemException &
e)
723 UERROR(
"GTSAM exception caught: %s", e.what());
724 optimizedPoses.clear();
726 catch(std::exception& e)
728 UERROR(
"GTSAM exception caught: %s", e.what());
729 optimizedPoses.clear();
734 else if(poses.size() == 1 ||
iterations() <= 0)
736 optimizedPoses = poses;
740 UWARN(
"This method should be called at least with 1 pose!");
742 UDEBUG(
"Optimizing graph...end!");
744 UERROR(
"Not built with GTSAM support!");
746 return optimizedPoses;
GLM_FUNC_DECL T roll(detail::tquat< T, P > const &x)
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
virtual void parseParameters(const ParametersMap ¶meters)
GLM_FUNC_DECL genType min(genType const &x, genType const &y)
GLM_FUNC_DECL genType e()
std::map< std::string, std::string > ParametersMap
void swap(linb::any &lhs, linb::any &rhs) noexcept
Basic mathematics functions.
Some conversion functions.
GLM_FUNC_DECL T pitch(detail::tquat< T, P > const &x)
float gravitySigma() const
#define UASSERT(condition)
Wrappers of STL for convenient functions.
virtual void parseParameters(const ParametersMap ¶meters)
bool landmarksIgnored() const
#define UASSERT_MSG(condition, msg_str)
bool uContains(const std::list< V > &list, const V &value)
GLM_FUNC_DECL detail::tquat< T, P > rotation(detail::tvec3< T, P > const &orig, detail::tvec3< T, P > const &dest)
void setRobust(bool enabled)
ULogger class and convenient macros.
GLM_FUNC_DECL T yaw(detail::tquat< T, P > const &x)
virtual std::map< int, Transform > optimize(int rootId, const std::map< int, Transform > &poses, const std::multimap< int, Link > &edgeConstraints, cv::Mat &outputCovariance, std::list< std::map< int, Transform > > *intermediateGraphes=0, double *finalError=0, int *iterationsDone=0)
bool isCovarianceIgnored() const
bool priorsIgnored() const
std::string UTILITE_EXP uFormat(const char *fmt,...)