39 #include <ceres/ceres.h>
40 #include <ceres/local_parameterization.h>
49 #if not(CERES_VERSION_MAJOR > 1 || (CERES_VERSION_MAJOR == 1 && CERES_VERSION_MINOR >= 12))
68 const std::map<int, Transform> & poses,
69 const std::multimap<int, Link> & edgeConstraints,
70 cv::Mat & outputCovariance,
71 std::list<std::map<int, Transform> > * intermediateGraphes,
75 outputCovariance = cv::Mat::eye(6,6,CV_64FC1);
76 std::map<int, Transform> optimizedPoses;
78 UDEBUG(
"Optimizing graph (pose=%d constraints=%d)...", (
int)poses.size(), (
int)edgeConstraints.size());
79 if(edgeConstraints.size()>=1 && poses.size()>=2 &&
iterations() > 0)
82 ceres::Problem problem;
83 std::map<int, ceres::examples::Pose2d> poses2d;
86 UDEBUG(
"fill poses to Ceres...");
89 for(std::map<int, Transform>::const_iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
95 p.x =
iter->second.x();
96 p.y =
iter->second.y();
98 poses2d.insert(std::make_pair(
iter->first,
p));
104 for(std::map<int, Transform>::const_iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
110 p.p.x() =
iter->second.x();
111 p.p.y() =
iter->second.y();
112 p.p.z() =
iter->second.z();
113 p.q =
iter->second.getQuaterniond();
114 poses3d.insert(std::make_pair(
iter->first,
p));
120 ceres::LossFunction* loss_function =
NULL;
121 ceres::LocalParameterization* angle_local_parameterization =
NULL;
122 ceres::LocalParameterization* quaternion_local_parameterization =
NULL;
124 for(std::multimap<int, Link>::const_iterator
iter=edgeConstraints.begin();
iter!=edgeConstraints.end(); ++
iter)
126 int id1 =
iter->second.from();
127 int id2 =
iter->second.to();
129 if(id1 != id2 && id1 > 0 && id2 > 0)
131 UASSERT(poses.find(id1) != poses.end() && poses.find(id2) != poses.end());
138 information(0,0) =
iter->second.infMatrix().at<
double>(0,0);
139 information(0,1) =
iter->second.infMatrix().at<
double>(0,1);
140 information(0,2) =
iter->second.infMatrix().at<
double>(0,5);
141 information(1,0) =
iter->second.infMatrix().at<
double>(1,0);
142 information(1,1) =
iter->second.infMatrix().at<
double>(1,1);
143 information(1,2) =
iter->second.infMatrix().at<
double>(1,5);
144 information(2,0) =
iter->second.infMatrix().at<
double>(5,0);
145 information(2,1) =
iter->second.infMatrix().at<
double>(5,1);
146 information(2,2) =
iter->second.infMatrix().at<
double>(5,5);
150 const Eigen::Matrix3d sqrt_information = information.llt().matrixL();
154 iter->second.transform().x(),
155 iter->second.transform().y(),
159 std::map<int, ceres::examples::Pose2d>::iterator pose_begin_iter = poses2d.find(id1);
160 std::map<int, ceres::examples::Pose2d>::iterator pose_end_iter = poses2d.find(id2);
162 problem.AddResidualBlock(
163 cost_function, loss_function,
164 &pose_begin_iter->second.x, &pose_begin_iter->second.y, &pose_begin_iter->second.yaw_radians,
165 &pose_end_iter->second.x, &pose_end_iter->second.y, &pose_end_iter->second.yaw_radians);
167 if(angle_local_parameterization ==
NULL)
171 problem.SetParameterization(&pose_begin_iter->second.yaw_radians, angle_local_parameterization);
172 problem.SetParameterization(&pose_end_iter->second.yaw_radians, angle_local_parameterization);
176 ceres::examples::MapOfPoses::iterator pose_begin_iter = poses3d.find(id1);
177 ceres::examples::MapOfPoses::iterator pose_end_iter = poses3d.find(id2);
182 memcpy(information.
data(),
iter->second.infMatrix().data,
iter->second.infMatrix().total()*
sizeof(
double));
186 t.p.
x() =
iter->second.transform().x();
187 t.p.
y() =
iter->second.transform().y();
188 t.p.z() =
iter->second.transform().z();
189 t.q =
iter->second.transform().getQuaterniond();
194 problem.AddResidualBlock(cost_function, loss_function,
195 pose_begin_iter->second.p.data(), pose_begin_iter->second.q.coeffs().data(),
196 pose_end_iter->second.p.data(), pose_end_iter->second.q.coeffs().data());
197 if(quaternion_local_parameterization ==
NULL)
201 problem.SetParameterization(pose_begin_iter->second.q.coeffs().data(), quaternion_local_parameterization);
202 problem.SetParameterization(pose_end_iter->second.q.coeffs().data(), quaternion_local_parameterization);
217 std::map<int, ceres::examples::Pose2d>::iterator pose_start_iter = rootId>0?poses2d.find(rootId):poses2d.begin();
218 UASSERT(pose_start_iter != poses2d.end());
219 problem.SetParameterBlockConstant(&pose_start_iter->second.x);
220 problem.SetParameterBlockConstant(&pose_start_iter->second.y);
221 problem.SetParameterBlockConstant(&pose_start_iter->second.yaw_radians);
232 ceres::examples::MapOfPoses::iterator pose_start_iter = rootId>0?poses3d.find(rootId):poses3d.begin();
233 UASSERT(pose_start_iter != poses3d.end());
234 problem.SetParameterBlockConstant(pose_start_iter->second.p.data());
235 problem.SetParameterBlockConstant(pose_start_iter->second.q.coeffs().data());
240 ceres::Solver::Options
options;
241 options.linear_solver_type = ceres::ITERATIVE_SCHUR;
242 options.sparse_linear_algebra_library_type = ceres::SUITE_SPARSE;
245 ceres::Solver::Summary summary;
247 ceres::Solve(
options, &problem, &summary);
251 std::cout << summary.FullReport() <<
'\n';
253 if(!summary.IsSolutionUsable())
255 UWARN(
"ceres: Could not find a usable solution, aborting optimization!");
256 return optimizedPoses;
261 *finalError = summary.final_cost;
265 *iterationsDone = summary.iterations.size();
267 UINFO(
"Ceres optimizing end (%d iterations done, error=%f, time = %f s)", (
int)summary.iterations.size(), summary.final_cost,
timer.ticks());
270 for(std::map<int, Transform>::const_iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
276 const std::map<int, ceres::examples::Pose2d>::iterator & pter = poses2d.find(
iter->first);
280 Transform newPose(pter->second.x, pter->second.y,
iter->second.z(),
roll,
pitch, pter->second.yaw_radians);
283 optimizedPoses.insert(std::pair<int, Transform>(
iter->first, newPose));
287 const std::map<int, ceres::examples::Pose3d, std::less<int>,
289 iterator& pter = poses3d.find(
iter->first);
291 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());
294 optimizedPoses.insert(std::pair<int, Transform>(
iter->first, newPose));
302 else if(poses.size() == 1 ||
iterations() <= 0)
304 optimizedPoses = poses;
308 UWARN(
"This method should be called at least with 1 pose!");
310 UDEBUG(
"Optimizing graph...end!");
312 UERROR(
"Not built with Ceres support!");
314 return optimizedPoses;
319 const std::map<int, Transform> & posesIn,
320 const std::multimap<int, Link> & links,
321 const std::map<
int, std::vector<CameraModel> > & models,
322 std::map<int, cv::Point3f> & points3DMap,
323 const std::map<
int, std::map<int, FeatureBA> > & wordReferences,
324 std::set<int> * outliers)
329 std::map<int, Transform> poses(posesIn.lower_bound(1), posesIn.end());
336 for(std::map<
int, std::map<int, FeatureBA> >::const_iterator
iter=wordReferences.begin();
337 iter!=wordReferences.end();
352 std::map<int, int> camIdToIndex;
353 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
358 std::map<int, std::vector<CameraModel> >::const_iterator iterModel = models.find(
iter->first);
359 UASSERT(iterModel != models.end());
360 if(iterModel->second.size() != 1)
362 UERROR(
"Multi-camera BA not implemented for Ceres, only single camera.");
363 return std::map<int, Transform>();
365 UASSERT(iterModel->second[0].isValidForProjection());
368 cv::Mat
R = (cv::Mat_<double>(3,3) <<
369 (double)
t.r11(), (double)
t.r12(), (double)
t.r13(),
370 (double)
t.r21(), (double)
t.r22(), (double)
t.r23(),
371 (double)
t.r31(), (double)
t.r32(), (double)
t.r33());
373 cv::Mat rvec(1,3, CV_64FC1);
374 cv::Rodrigues(
R, rvec);
378 baProblem.
cameras_[oi++] = rvec.at<
double>(0,0);
379 baProblem.
cameras_[oi++] = rvec.at<
double>(0,1);
380 baProblem.
cameras_[oi++] = rvec.at<
double>(0,2);
385 camIdToIndex.insert(std::make_pair(
iter->first, camIndex++));
391 std::map<int, int> pointIdToIndex;
392 for(std::map<int, cv::Point3f>::const_iterator kter = points3DMap.begin(); kter!=points3DMap.end(); ++kter)
396 baProblem.
points_[oi++] = kter->second.x;
397 baProblem.
points_[oi++] = kter->second.y;
398 baProblem.
points_[oi++] = kter->second.z;
400 pointIdToIndex.insert(std::make_pair(kter->first, pointIndex++));
405 for(std::map<
int, std::map<int, FeatureBA> >::const_iterator
iter=wordReferences.begin();
406 iter!=wordReferences.end();
409 for(std::map<int, FeatureBA>::const_iterator jter=
iter->second.begin();
410 jter!=
iter->second.end();
413 std::map<int, std::vector<CameraModel> >::const_iterator iterModel = models.find(jter->first);
414 UASSERT(iterModel != models.end());
415 if(iterModel->second.size() != 1)
417 UERROR(
"Multi-camera BA not implemented for Ceres, only single camera.");
418 return std::map<int, Transform>();
420 UASSERT(iterModel->second[0].isValidForProjection());
424 baProblem.
observations_[4*oi] = jter->second.kpt.pt.x - iterModel->second[0].cx();
425 baProblem.
observations_[4*oi+1] = jter->second.kpt.pt.y - iterModel->second[0].cy();
437 ceres::Problem problem;
443 ceres::CostFunction* cost_function =
446 observations[4 *
i + 1],
447 observations[4 *
i + 2],
448 observations[4 *
i + 3]);
449 ceres::LossFunction* loss_function =
new ceres::HuberLoss(8.0);
450 problem.AddResidualBlock(cost_function,
460 ceres::Solver::Options
options;
461 options.linear_solver_type = ceres::ITERATIVE_SCHUR;
462 options.sparse_linear_algebra_library_type = ceres::SUITE_SPARSE;
466 ceres::Solver::Summary summary;
467 ceres::Solve(
options, &problem, &summary);
471 std::cout << summary.FullReport() <<
"\n";
473 if(!summary.IsSolutionUsable())
475 UWARN(
"ceres: Could not find a usable solution, aborting optimization!");
480 std::map<int, Transform> newPoses = poses;
482 for(std::map<int, Transform>::iterator
iter=newPoses.begin();
iter!=newPoses.end(); ++
iter)
484 cv::Mat rvec = (cv::Mat_<double>(1,3) <<
488 cv::Rodrigues(rvec,
R);
490 R.at<
double>(1,0),
R.at<
double>(1,1),
R.at<
double>(1,2), baProblem.
cameras_[oi+4],
491 R.at<
double>(2,0),
R.at<
double>(2,1),
R.at<
double>(2,2), baProblem.
cameras_[oi+5]);
497 t = (models.at(
iter->first)[0].localTransform() *
t).
inverse();
498 t =
iter->second.inverse() *
t;
499 iter->second *=
t.to3DoF();
510 for(std::map<int, cv::Point3f>::iterator kter = points3DMap.begin(); kter!=points3DMap.end(); ++kter)
512 kter->second.x = baProblem.
points_[oi++];
513 kter->second.y = baProblem.
points_[oi++];
514 kter->second.z = baProblem.
points_[oi++];
520 UERROR(
"RTAB-Map is not built with ceres!");
521 return std::map<int, Transform>();