39 #include <ceres/ceres.h>
41 #if CERES_VERSION_MAJOR >= 3 || \
42 (CERES_VERSION_MAJOR == 2 && CERES_VERSION_MINOR >= 1)
43 #include <ceres/manifold.h>
45 #include <ceres/local_parameterization.h>
56 #if not(CERES_VERSION_MAJOR > 1 || (CERES_VERSION_MAJOR == 1 && CERES_VERSION_MINOR >= 12))
57 #include "ceres/pose_graph_3d/eigen_quaternion_manifold.h"
66 #if CERES_VERSION_MAJOR >= 3 || \
67 (CERES_VERSION_MAJOR == 2 && CERES_VERSION_MINOR >= 1)
68 inline void SetCeresProblemManifold(ceres::Problem& problem,
double* params,
69 ceres::Manifold* manifold) {
70 problem.SetManifold(params, manifold);
72 inline void SetCeresProblemManifold(
73 ceres::Problem& problem,
double* params,
74 ceres::LocalParameterization* parameterization) {
75 problem.SetParameterization(params, parameterization);
93 const std::map<int, Transform> & poses,
94 const std::multimap<int, Link> & edgeConstraints,
95 cv::Mat & outputCovariance,
96 std::list<std::map<int, Transform> > * intermediateGraphes,
100 outputCovariance = cv::Mat::eye(6,6,CV_64FC1);
101 std::map<int, Transform> optimizedPoses;
103 UDEBUG(
"Optimizing graph (pose=%d constraints=%d)...", (
int)poses.size(), (
int)edgeConstraints.size());
104 if(edgeConstraints.size()>=1 && poses.size()>=2 &&
iterations() > 0)
107 ceres::Problem problem;
108 std::map<int, ceres::examples::Pose2d> poses2d;
111 UDEBUG(
"fill poses to Ceres...");
114 for(std::map<int, Transform>::const_iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
120 p.x =
iter->second.x();
121 p.y =
iter->second.y();
123 poses2d.insert(std::make_pair(
iter->first,
p));
129 for(std::map<int, Transform>::const_iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
135 p.p.x() =
iter->second.x();
136 p.p.y() =
iter->second.y();
137 p.p.z() =
iter->second.z();
138 p.q =
iter->second.getQuaterniond();
139 poses3d.insert(std::make_pair(
iter->first,
p));
145 ceres::LossFunction* loss_function =
NULL;
146 #if CERES_VERSION_MAJOR >= 3 || \
147 (CERES_VERSION_MAJOR == 2 && CERES_VERSION_MINOR >= 1)
148 ceres::Manifold* angle_local_manifold =
NULL;
149 ceres::Manifold* quaternion_local_manifold =
NULL;
151 ceres::LocalParameterization* angle_local_manifold =
NULL;
152 ceres::LocalParameterization* quaternion_local_manifold =
NULL;
155 for(std::multimap<int, Link>::const_iterator
iter=edgeConstraints.begin();
iter!=edgeConstraints.end(); ++
iter)
157 int id1 =
iter->second.from();
158 int id2 =
iter->second.to();
160 if(id1 != id2 && id1 > 0 && id2 > 0)
162 UASSERT(poses.find(id1) != poses.end() && poses.find(id2) != poses.end());
169 information(0,0) =
iter->second.infMatrix().at<
double>(0,0);
170 information(0,1) =
iter->second.infMatrix().at<
double>(0,1);
171 information(0,2) =
iter->second.infMatrix().at<
double>(0,5);
172 information(1,0) =
iter->second.infMatrix().at<
double>(1,0);
173 information(1,1) =
iter->second.infMatrix().at<
double>(1,1);
174 information(1,2) =
iter->second.infMatrix().at<
double>(1,5);
175 information(2,0) =
iter->second.infMatrix().at<
double>(5,0);
176 information(2,1) =
iter->second.infMatrix().at<
double>(5,1);
177 information(2,2) =
iter->second.infMatrix().at<
double>(5,5);
181 const Eigen::Matrix3d sqrt_information = information.llt().matrixL();
185 iter->second.transform().x(),
186 iter->second.transform().y(),
190 std::map<int, ceres::examples::Pose2d>::iterator pose_begin_iter = poses2d.find(id1);
191 std::map<int, ceres::examples::Pose2d>::iterator pose_end_iter = poses2d.find(id2);
193 problem.AddResidualBlock(
194 cost_function, loss_function,
195 &pose_begin_iter->second.x, &pose_begin_iter->second.y, &pose_begin_iter->second.yaw_radians,
196 &pose_end_iter->second.x, &pose_end_iter->second.y, &pose_end_iter->second.yaw_radians);
198 if(angle_local_manifold ==
NULL)
202 SetCeresProblemManifold(problem, &pose_begin_iter->second.yaw_radians, angle_local_manifold);
203 SetCeresProblemManifold(problem, &pose_end_iter->second.yaw_radians, angle_local_manifold);
207 ceres::examples::MapOfPoses::iterator pose_begin_iter = poses3d.find(id1);
208 ceres::examples::MapOfPoses::iterator pose_end_iter = poses3d.find(id2);
213 memcpy(information.
data(),
iter->second.infMatrix().data,
iter->second.infMatrix().total()*
sizeof(
double));
217 t.p.
x() =
iter->second.transform().x();
218 t.p.
y() =
iter->second.transform().y();
219 t.p.z() =
iter->second.transform().z();
220 t.q =
iter->second.transform().getQuaterniond();
225 problem.AddResidualBlock(cost_function, loss_function,
226 pose_begin_iter->second.p.data(), pose_begin_iter->second.q.coeffs().data(),
227 pose_end_iter->second.p.data(), pose_end_iter->second.q.coeffs().data());
228 if(quaternion_local_manifold ==
NULL)
230 #if CERES_VERSION_MAJOR >= 3 || \
231 (CERES_VERSION_MAJOR == 2 && CERES_VERSION_MINOR >= 1)
232 quaternion_local_manifold =
new ceres::EigenQuaternionManifold;
237 SetCeresProblemManifold(problem, pose_begin_iter->second.q.coeffs().data(), quaternion_local_manifold);
238 SetCeresProblemManifold(problem, pose_end_iter->second.q.coeffs().data(), quaternion_local_manifold);
253 std::map<int, ceres::examples::Pose2d>::iterator pose_start_iter = rootId>0?poses2d.find(rootId):poses2d.begin();
254 UASSERT(pose_start_iter != poses2d.end());
255 problem.SetParameterBlockConstant(&pose_start_iter->second.x);
256 problem.SetParameterBlockConstant(&pose_start_iter->second.y);
257 problem.SetParameterBlockConstant(&pose_start_iter->second.yaw_radians);
268 ceres::examples::MapOfPoses::iterator pose_start_iter = rootId>0?poses3d.find(rootId):poses3d.begin();
269 UASSERT(pose_start_iter != poses3d.end());
270 problem.SetParameterBlockConstant(pose_start_iter->second.p.data());
271 problem.SetParameterBlockConstant(pose_start_iter->second.q.coeffs().data());
276 ceres::Solver::Options
options;
277 options.linear_solver_type = ceres::ITERATIVE_SCHUR;
278 options.sparse_linear_algebra_library_type = ceres::SUITE_SPARSE;
281 ceres::Solver::Summary summary;
283 ceres::Solve(
options, &problem, &summary);
287 std::cout << summary.FullReport() <<
'\n';
289 if(!summary.IsSolutionUsable())
291 UWARN(
"ceres: Could not find a usable solution, aborting optimization!");
292 return optimizedPoses;
297 *finalError = summary.final_cost;
301 *iterationsDone = summary.iterations.size();
303 UINFO(
"Ceres optimizing end (%d iterations done, error=%f, time = %f s)", (
int)summary.iterations.size(), summary.final_cost,
timer.ticks());
306 for(std::map<int, Transform>::const_iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
312 const std::map<int, ceres::examples::Pose2d>::iterator & pter = poses2d.find(
iter->first);
316 Transform newPose(pter->second.x, pter->second.y,
iter->second.z(),
roll,
pitch, pter->second.yaw_radians);
319 optimizedPoses.insert(std::pair<int, Transform>(
iter->first, newPose));
323 const std::map<int, ceres::examples::Pose3d, std::less<int>,
325 iterator& pter = poses3d.find(
iter->first);
327 Transform newPose(pter->second.p.x(), pter->second.p.y(), pter->second.p.z(), pter->second.q.x(), pter->second.q.y(), pter->second.q.z(), pter->second.q.w());
330 optimizedPoses.insert(std::pair<int, Transform>(
iter->first, newPose));
338 else if(poses.size() == 1 ||
iterations() <= 0)
340 optimizedPoses = poses;
344 UWARN(
"This method should be called at least with 1 pose!");
346 UDEBUG(
"Optimizing graph...end!");
348 UERROR(
"Not built with Ceres support!");
350 return optimizedPoses;
355 const std::map<int, Transform> & posesIn,
356 const std::multimap<int, Link> & links,
357 const std::map<
int, std::vector<CameraModel> > & models,
358 std::map<int, cv::Point3f> & points3DMap,
359 const std::map<
int, std::map<int, FeatureBA> > & wordReferences,
360 std::set<int> * outliers)
365 std::map<int, Transform> poses(posesIn.lower_bound(1), posesIn.end());
372 for(std::map<
int, std::map<int, FeatureBA> >::const_iterator
iter=wordReferences.begin();
373 iter!=wordReferences.end();
388 std::map<int, int> camIdToIndex;
389 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
394 std::map<int, std::vector<CameraModel> >::const_iterator iterModel = models.find(
iter->first);
395 UASSERT(iterModel != models.end());
396 if(iterModel->second.size() != 1)
398 UERROR(
"Multi-camera BA not implemented for Ceres, only single camera.");
399 return std::map<int, Transform>();
401 UASSERT(iterModel->second[0].isValidForProjection());
404 cv::Mat
R = (cv::Mat_<double>(3,3) <<
405 (double)
t.r11(), (double)
t.r12(), (double)
t.r13(),
406 (double)
t.r21(), (double)
t.r22(), (double)
t.r23(),
407 (double)
t.r31(), (double)
t.r32(), (double)
t.r33());
409 cv::Mat rvec(1,3, CV_64FC1);
410 cv::Rodrigues(
R, rvec);
414 baProblem.
cameras_[oi++] = rvec.at<
double>(0,0);
415 baProblem.
cameras_[oi++] = rvec.at<
double>(0,1);
416 baProblem.
cameras_[oi++] = rvec.at<
double>(0,2);
421 camIdToIndex.insert(std::make_pair(
iter->first, camIndex++));
427 std::map<int, int> pointIdToIndex;
428 for(std::map<int, cv::Point3f>::const_iterator kter = points3DMap.begin(); kter!=points3DMap.end(); ++kter)
432 baProblem.
points_[oi++] = kter->second.x;
433 baProblem.
points_[oi++] = kter->second.y;
434 baProblem.
points_[oi++] = kter->second.z;
436 pointIdToIndex.insert(std::make_pair(kter->first, pointIndex++));
441 for(std::map<
int, std::map<int, FeatureBA> >::const_iterator
iter=wordReferences.begin();
442 iter!=wordReferences.end();
445 for(std::map<int, FeatureBA>::const_iterator jter=
iter->second.begin();
446 jter!=
iter->second.end();
449 std::map<int, std::vector<CameraModel> >::const_iterator iterModel = models.find(jter->first);
450 UASSERT(iterModel != models.end());
451 if(iterModel->second.size() != 1)
453 UERROR(
"Multi-camera BA not implemented for Ceres, only single camera.");
454 return std::map<int, Transform>();
456 UASSERT(iterModel->second[0].isValidForProjection());
460 baProblem.
observations_[4*oi] = jter->second.kpt.pt.x - iterModel->second[0].cx();
461 baProblem.
observations_[4*oi+1] = jter->second.kpt.pt.y - iterModel->second[0].cy();
473 ceres::Problem problem;
479 ceres::CostFunction* cost_function =
482 observations[4 *
i + 1],
483 observations[4 *
i + 2],
484 observations[4 *
i + 3]);
485 ceres::LossFunction* loss_function =
new ceres::HuberLoss(8.0);
486 problem.AddResidualBlock(cost_function,
496 ceres::Solver::Options
options;
497 options.linear_solver_type = ceres::ITERATIVE_SCHUR;
498 options.sparse_linear_algebra_library_type = ceres::SUITE_SPARSE;
502 ceres::Solver::Summary summary;
503 ceres::Solve(
options, &problem, &summary);
507 std::cout << summary.FullReport() <<
"\n";
509 if(!summary.IsSolutionUsable())
511 UWARN(
"ceres: Could not find a usable solution, aborting optimization!");
516 std::map<int, Transform> newPoses = poses;
518 for(std::map<int, Transform>::iterator
iter=newPoses.begin();
iter!=newPoses.end(); ++
iter)
520 cv::Mat rvec = (cv::Mat_<double>(1,3) <<
524 cv::Rodrigues(rvec,
R);
526 R.at<
double>(1,0),
R.at<
double>(1,1),
R.at<
double>(1,2), baProblem.
cameras_[oi+4],
527 R.at<
double>(2,0),
R.at<
double>(2,1),
R.at<
double>(2,2), baProblem.
cameras_[oi+5]);
533 t = (models.at(
iter->first)[0].localTransform() *
t).
inverse();
534 t =
iter->second.inverse() *
t;
535 iter->second *=
t.to3DoF();
546 for(std::map<int, cv::Point3f>::iterator kter = points3DMap.begin(); kter!=points3DMap.end(); ++kter)
548 kter->second.x = baProblem.
points_[oi++];
549 kter->second.y = baProblem.
points_[oi++];
550 kter->second.z = baProblem.
points_[oi++];
556 UERROR(
"RTAB-Map is not built with ceres!");
557 return std::map<int, Transform>();