00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "rtabmap/core/util3d_motion_estimation.h"
00029
00030 #include "rtabmap/utilite/UStl.h"
00031 #include "rtabmap/utilite/UMath.h"
00032 #include "rtabmap/utilite/ULogger.h"
00033 #include "rtabmap/core/util3d_transforms.h"
00034 #include "rtabmap/core/util3d_registration.h"
00035 #include "rtabmap/core/util3d_correspondences.h"
00036 #include "rtabmap/core/util3d.h"
00037
00038 #include <pcl/common/common.h>
00039
00040 #include "opencv/solvepnp.h"
00041
00042 namespace rtabmap
00043 {
00044
00045 namespace util3d
00046 {
00047
00048 Transform estimateMotion3DTo2D(
00049 const std::map<int, cv::Point3f> & words3A,
00050 const std::map<int, cv::KeyPoint> & words2B,
00051 const CameraModel & cameraModel,
00052 int minInliers,
00053 int iterations,
00054 double reprojError,
00055 int flagsPnP,
00056 int refineIterations,
00057 const Transform & guess,
00058 const std::map<int, cv::Point3f> & words3B,
00059 cv::Mat * covariance,
00060 std::vector<int> * matchesOut,
00061 std::vector<int> * inliersOut)
00062 {
00063 UASSERT(cameraModel.isValidForProjection());
00064 UASSERT(!guess.isNull());
00065 Transform transform;
00066 std::vector<int> matches, inliers;
00067
00068 if(covariance)
00069 {
00070 *covariance = cv::Mat::eye(6,6,CV_64FC1);
00071 }
00072
00073
00074 std::vector<int> ids = uKeys(words2B);
00075 std::vector<cv::Point3f> objectPoints(ids.size());
00076 std::vector<cv::Point2f> imagePoints(ids.size());
00077 int oi=0;
00078 matches.resize(ids.size());
00079 for(unsigned int i=0; i<ids.size(); ++i)
00080 {
00081 std::map<int, cv::Point3f>::const_iterator iter=words3A.find(ids[i]);
00082 if(iter != words3A.end() && util3d::isFinite(iter->second))
00083 {
00084 const cv::Point3f & pt = iter->second;
00085 objectPoints[oi].x = pt.x;
00086 objectPoints[oi].y = pt.y;
00087 objectPoints[oi].z = pt.z;
00088 imagePoints[oi] = words2B.find(ids[i])->second.pt;
00089 matches[oi++] = ids[i];
00090 }
00091 }
00092
00093 objectPoints.resize(oi);
00094 imagePoints.resize(oi);
00095 matches.resize(oi);
00096
00097 UDEBUG("words3A=%d words2B=%d matches=%d words3B=%d guess=%s",
00098 (int)words3A.size(), (int)words2B.size(), (int)matches.size(), (int)words3B.size(), guess.prettyPrint().c_str());
00099
00100 if((int)matches.size() >= minInliers)
00101 {
00102
00103 cv::Mat K = cameraModel.K();
00104 cv::Mat D = cameraModel.D();
00105 Transform guessCameraFrame = (guess * cameraModel.localTransform()).inverse();
00106 cv::Mat R = (cv::Mat_<double>(3,3) <<
00107 (double)guessCameraFrame.r11(), (double)guessCameraFrame.r12(), (double)guessCameraFrame.r13(),
00108 (double)guessCameraFrame.r21(), (double)guessCameraFrame.r22(), (double)guessCameraFrame.r23(),
00109 (double)guessCameraFrame.r31(), (double)guessCameraFrame.r32(), (double)guessCameraFrame.r33());
00110
00111 cv::Mat rvec(1,3, CV_64FC1);
00112 cv::Rodrigues(R, rvec);
00113 cv::Mat tvec = (cv::Mat_<double>(1,3) <<
00114 (double)guessCameraFrame.x(), (double)guessCameraFrame.y(), (double)guessCameraFrame.z());
00115
00116 util3d::solvePnPRansac(
00117 objectPoints,
00118 imagePoints,
00119 K,
00120 D,
00121 rvec,
00122 tvec,
00123 true,
00124 iterations,
00125 reprojError,
00126 minInliers,
00127 inliers,
00128 flagsPnP,
00129 refineIterations);
00130
00131 if((int)inliers.size() >= minInliers)
00132 {
00133 cv::Rodrigues(rvec, R);
00134 Transform pnp(R.at<double>(0,0), R.at<double>(0,1), R.at<double>(0,2), tvec.at<double>(0),
00135 R.at<double>(1,0), R.at<double>(1,1), R.at<double>(1,2), tvec.at<double>(1),
00136 R.at<double>(2,0), R.at<double>(2,1), R.at<double>(2,2), tvec.at<double>(2));
00137
00138 transform = (cameraModel.localTransform() * pnp).inverse();
00139
00140
00141 if(covariance && words3B.size())
00142 {
00143 std::vector<float> errorSqrdDists(inliers.size());
00144 std::vector<float> errorSqrdAngles(inliers.size());
00145 oi = 0;
00146 for(unsigned int i=0; i<inliers.size(); ++i)
00147 {
00148 std::map<int, cv::Point3f>::const_iterator iter = words3B.find(matches[inliers[i]]);
00149 if(iter != words3B.end() && util3d::isFinite(iter->second))
00150 {
00151 const cv::Point3f & objPt = objectPoints[inliers[i]];
00152 cv::Point3f newPt = util3d::transformPoint(iter->second, transform);
00153 errorSqrdDists[oi] = uNormSquared(objPt.x-newPt.x, objPt.y-newPt.y, objPt.z-newPt.z);
00154
00155 Eigen::Vector4f v1(objPt.x - transform.x(), objPt.y - transform.y(), objPt.z - transform.z(), 0);
00156 Eigen::Vector4f v2(newPt.x - transform.x(), newPt.y - transform.y(), newPt.z - transform.z(), 0);
00157 errorSqrdAngles[oi++] = pcl::getAngle3D(v1, v2);
00158 }
00159 }
00160
00161 errorSqrdDists.resize(oi);
00162 errorSqrdAngles.resize(oi);
00163 if(errorSqrdDists.size())
00164 {
00165 std::sort(errorSqrdDists.begin(), errorSqrdDists.end());
00166
00167 double median_error_sqr = 2.1981 * (double)errorSqrdDists[errorSqrdDists.size () >> 2];
00168 UASSERT(uIsFinite(median_error_sqr));
00169 (*covariance)(cv::Range(0,3), cv::Range(0,3)) *= median_error_sqr;
00170 std::sort(errorSqrdAngles.begin(), errorSqrdAngles.end());
00171 median_error_sqr = 2.1981 * (double)errorSqrdAngles[errorSqrdAngles.size () >> 2];
00172 UASSERT(uIsFinite(median_error_sqr));
00173 (*covariance)(cv::Range(3,6), cv::Range(3,6)) *= median_error_sqr;
00174 }
00175 else
00176 {
00177 UWARN("Not enough close points to compute covariance!");
00178 }
00179 }
00180 else if(covariance)
00181 {
00182
00183 std::vector<cv::Point2f> imagePointsReproj;
00184 cv::projectPoints(objectPoints, rvec, tvec, K, cv::Mat(), imagePointsReproj);
00185 float err = 0.0f;
00186 for(unsigned int i=0; i<inliers.size(); ++i)
00187 {
00188 err += uNormSquared(imagePoints.at(inliers[i]).x - imagePointsReproj.at(inliers[i]).x, imagePoints.at(inliers[i]).y - imagePointsReproj.at(inliers[i]).y);
00189 }
00190 UASSERT(uIsFinite(err));
00191 *covariance *= std::sqrt(err/float(inliers.size()));
00192 }
00193 }
00194 }
00195
00196 if(matchesOut)
00197 {
00198 *matchesOut = matches;
00199 }
00200 if(inliersOut)
00201 {
00202 inliersOut->resize(inliers.size());
00203 for(unsigned int i=0; i<inliers.size(); ++i)
00204 {
00205 inliersOut->at(i) = matches[inliers[i]];
00206 }
00207 }
00208
00209 return transform;
00210 }
00211
00212 Transform estimateMotion3DTo3D(
00213 const std::map<int, cv::Point3f> & words3A,
00214 const std::map<int, cv::Point3f> & words3B,
00215 int minInliers,
00216 double inliersDistance,
00217 int iterations,
00218 int refineIterations,
00219 cv::Mat * covariance,
00220 std::vector<int> * matchesOut,
00221 std::vector<int> * inliersOut)
00222 {
00223 Transform transform;
00224 std::vector<cv::Point3f> inliers1;
00225 std::vector<cv::Point3f> inliers2;
00226
00227 std::vector<int> matches;
00228 util3d::findCorrespondences(
00229 words3A,
00230 words3B,
00231 inliers1,
00232 inliers2,
00233 0,
00234 &matches);
00235 UASSERT(inliers1.size() == inliers2.size());
00236 UDEBUG("Unique correspondences = %d", (int)inliers1.size());
00237
00238 if(covariance)
00239 {
00240 *covariance = cv::Mat::eye(6,6,CV_64FC1);
00241 }
00242
00243 std::vector<int> inliers;
00244 if((int)inliers1.size() >= minInliers)
00245 {
00246 pcl::PointCloud<pcl::PointXYZ>::Ptr inliers1cloud(new pcl::PointCloud<pcl::PointXYZ>);
00247 pcl::PointCloud<pcl::PointXYZ>::Ptr inliers2cloud(new pcl::PointCloud<pcl::PointXYZ>);
00248 inliers1cloud->resize(inliers1.size());
00249 inliers2cloud->resize(inliers1.size());
00250 for(unsigned int i=0; i<inliers1.size(); ++i)
00251 {
00252 (*inliers1cloud)[i].x = inliers1[i].x;
00253 (*inliers1cloud)[i].y = inliers1[i].y;
00254 (*inliers1cloud)[i].z = inliers1[i].z;
00255 (*inliers2cloud)[i].x = inliers2[i].x;
00256 (*inliers2cloud)[i].y = inliers2[i].y;
00257 (*inliers2cloud)[i].z = inliers2[i].z;
00258 }
00259 Transform t = util3d::transformFromXYZCorrespondences(
00260 inliers2cloud,
00261 inliers1cloud,
00262 inliersDistance,
00263 iterations,
00264 refineIterations,
00265 3.0,
00266 &inliers,
00267 covariance);
00268
00269 if(!t.isNull() && (int)inliers.size() >= minInliers)
00270 {
00271 transform = t;
00272 }
00273 }
00274
00275 if(matchesOut)
00276 {
00277 *matchesOut = matches;
00278 }
00279 if(inliersOut)
00280 {
00281 inliersOut->resize(inliers.size());
00282 for(unsigned int i=0; i<inliers.size(); ++i)
00283 {
00284 inliersOut->at(i) = matches[inliers[i]];
00285 }
00286 }
00287
00288 return transform;
00289 }
00290
00291
00292 std::vector<float> computeReprojErrors(
00293 std::vector<cv::Point3f> opoints,
00294 std::vector<cv::Point2f> ipoints,
00295 const cv::Mat & cameraMatrix,
00296 const cv::Mat & distCoeffs,
00297 const cv::Mat & rvec,
00298 const cv::Mat & tvec,
00299 float reprojErrorThreshold,
00300 std::vector<int> & inliers)
00301 {
00302 UASSERT(opoints.size() == ipoints.size());
00303 int count = (int)opoints.size();
00304
00305 std::vector<cv::Point2f> projpoints;
00306 projectPoints(opoints, rvec, tvec, cameraMatrix, distCoeffs, projpoints);
00307
00308 inliers.resize(count,0);
00309 std::vector<float> err(count);
00310 int oi=0;
00311 for (int i = 0; i < count; ++i)
00312 {
00313 float e = (float)cv::norm( ipoints[i] - projpoints[i]);
00314 if(e <= reprojErrorThreshold)
00315 {
00316 inliers[oi] = i;
00317 err[oi++] = e;
00318 }
00319 }
00320 inliers.resize(oi);
00321 err.resize(oi);
00322 return err;
00323 }
00324
00325 void solvePnPRansac(
00326 const std::vector<cv::Point3f> & objectPoints,
00327 const std::vector<cv::Point2f> & imagePoints,
00328 const cv::Mat & cameraMatrix,
00329 const cv::Mat & distCoeffs,
00330 cv::Mat & rvec,
00331 cv::Mat & tvec,
00332 bool useExtrinsicGuess,
00333 int iterationsCount,
00334 float reprojectionError,
00335 int minInliersCount,
00336 std::vector<int> & inliers,
00337 int flags,
00338 int refineIterations,
00339 float refineSigma)
00340 {
00341 if(minInliersCount < 4)
00342 {
00343 minInliersCount = 4;
00344 }
00345
00346
00347
00348 cv3::solvePnPRansac(
00349 objectPoints,
00350 imagePoints,
00351 cameraMatrix,
00352 distCoeffs,
00353 rvec,
00354 tvec,
00355 useExtrinsicGuess,
00356 iterationsCount,
00357 reprojectionError,
00358 0.99,
00359 inliers,
00360 flags);
00361
00362 float inlierThreshold = reprojectionError;
00363 if((int)inliers.size() >= minInliersCount && refineIterations>0)
00364 {
00365 float error_threshold = inlierThreshold;
00366 int refine_iterations = 0;
00367 bool inlier_changed = false, oscillating = false;
00368 std::vector<int> new_inliers, prev_inliers = inliers;
00369 std::vector<size_t> inliers_sizes;
00370
00371 cv::Mat new_model_rvec = rvec;
00372 cv::Mat new_model_tvec = tvec;
00373
00374 do
00375 {
00376
00377 std::vector<cv::Point3f> opoints_inliers(prev_inliers.size());
00378 std::vector<cv::Point2f> ipoints_inliers(prev_inliers.size());
00379 for(unsigned int i=0; i<prev_inliers.size(); ++i)
00380 {
00381 opoints_inliers[i] = objectPoints[prev_inliers[i]];
00382 ipoints_inliers[i] = imagePoints[prev_inliers[i]];
00383 }
00384
00385 UDEBUG("inliers=%d refine_iterations=%d, rvec=%f,%f,%f tvec=%f,%f,%f", (int)prev_inliers.size(), refine_iterations,
00386 *new_model_rvec.ptr<double>(0), *new_model_rvec.ptr<double>(1), *new_model_rvec.ptr<double>(2),
00387 *new_model_tvec.ptr<double>(0), *new_model_tvec.ptr<double>(1), *new_model_tvec.ptr<double>(2));
00388
00389
00390 cv::solvePnP(opoints_inliers, ipoints_inliers, cameraMatrix, distCoeffs, new_model_rvec, new_model_tvec, true, flags);
00391 inliers_sizes.push_back(prev_inliers.size());
00392
00393 UDEBUG("rvec=%f,%f,%f tvec=%f,%f,%f",
00394 *new_model_rvec.ptr<double>(0), *new_model_rvec.ptr<double>(1), *new_model_rvec.ptr<double>(2),
00395 *new_model_tvec.ptr<double>(0), *new_model_tvec.ptr<double>(1), *new_model_tvec.ptr<double>(2));
00396
00397
00398 std::vector<float> err = computeReprojErrors(objectPoints, imagePoints, cameraMatrix, distCoeffs, new_model_rvec, new_model_tvec, error_threshold, new_inliers);
00399 UDEBUG("RANSAC refineModel: Number of inliers found (before/after): %d/%d, with an error threshold of %f.",
00400 (int)prev_inliers.size (), (int)new_inliers.size (), error_threshold);
00401
00402 if ((int)new_inliers.size() < minInliersCount)
00403 {
00404 ++refine_iterations;
00405 if (refine_iterations >= refineIterations)
00406 {
00407 break;
00408 }
00409 continue;
00410 }
00411
00412
00413 float m = uMean(err.data(), err.size());
00414 float variance = uVariance(err.data(), err.size());
00415 error_threshold = std::min(inlierThreshold, refineSigma * float(sqrt(variance)));
00416
00417 UDEBUG ("RANSAC refineModel: New estimated error threshold: %f (variance=%f mean=%f) on iteration %d out of %d.",
00418 error_threshold, variance, m, refine_iterations, refineIterations);
00419 inlier_changed = false;
00420 std::swap (prev_inliers, new_inliers);
00421
00422
00423 if (new_inliers.size () != prev_inliers.size ())
00424 {
00425
00426 if ((int)inliers_sizes.size () >= minInliersCount)
00427 {
00428 if (inliers_sizes[inliers_sizes.size () - 1] == inliers_sizes[inliers_sizes.size () - 3] &&
00429 inliers_sizes[inliers_sizes.size () - 2] == inliers_sizes[inliers_sizes.size () - 4])
00430 {
00431 oscillating = true;
00432 break;
00433 }
00434 }
00435 inlier_changed = true;
00436 continue;
00437 }
00438
00439
00440 for (size_t i = 0; i < prev_inliers.size (); ++i)
00441 {
00442
00443 if (prev_inliers[i] != new_inliers[i])
00444 {
00445 inlier_changed = true;
00446 break;
00447 }
00448 }
00449 }
00450 while (inlier_changed && ++refine_iterations < refineIterations);
00451
00452
00453 if ((int)prev_inliers.size() < minInliersCount)
00454 {
00455 UWARN ("RANSAC refineModel: Refinement failed: got very low inliers (%d)!", (int)prev_inliers.size());
00456 }
00457
00458 if (oscillating)
00459 {
00460 UDEBUG("RANSAC refineModel: Detected oscillations in the model refinement.");
00461 }
00462
00463 std::swap (inliers, new_inliers);
00464 rvec = new_model_rvec;
00465 tvec = new_model_tvec;
00466 }
00467
00468 }
00469
00470 }
00471
00472 }