motion_estimation_pairwise_ransac.cpp
Go to the documentation of this file.
00001 
00024 #include "rgbdtools/registration/motion_estimation_pairwise_ransac.h"
00025 
00026 namespace rgbdtools {
00027 
00028 MotionEstimationPairwiseRANSAC::MotionEstimationPairwiseRANSAC():
00029   MotionEstimation(),
00030   initialized_(false)
00031 {
00032   sac_min_inliers_ = 20;
00033   sac_max_eucl_dist_sq_ = pow(0.03, 2.0);
00034   sac_reestimate_tf_ = true;
00035   ransac_max_iterations_ = 200;
00036   ransac_confidence_ = 0.98;
00037   matcher_use_desc_ratio_test_ = true;
00038   matcher_max_desc_ratio_ = 1.0;
00039   matcher_max_desc_dist_ = 50.0;
00040     
00041   // derived parameters
00042   log_one_minus_ransac_confidence_ = log(1.0 - ransac_confidence_);
00043   
00044   //detector_.reset(new OrbDetector());
00045   //detector_->setComputeDescriptors(true);
00046     
00047   //OrbDetectorPtr orb_detector = 
00048   //  boost::static_pointer_cast<OrbDetector>(detector_);
00049         
00050   //orb_detector->setThreshold(31.0);
00051   //orb_detector->setNFeatures(200);
00052   //orb_detector->setSmooth(0);
00053   
00054   f2b_.setIdentity();
00055 }
00056 
00057 MotionEstimationPairwiseRANSAC::~MotionEstimationPairwiseRANSAC()
00058 {
00059 
00060 }
00061 
00062 bool MotionEstimationPairwiseRANSAC::getMotionEstimationImpl(
00063   RGBDFrame& frame,
00064   const AffineTransform& prediction,
00065   AffineTransform& motion)
00066 {  
00067   bool result;
00068 
00069   detector_->findFeatures(frame);
00070 
00071   if ((int)frame.keypoints.size() == 0) return false;
00072 
00073   if (!initialized_)
00074   {
00075     initialized_ = true;
00076     result = false;
00077   }
00078   else
00079   {
00080     DMatchVector sac_matches;
00081     Eigen::Matrix4f sac_transformation;
00082     int ransac_iterations = pairwiseMatchingRANSAC(
00083       frame, *prev_frame_, sac_matches, sac_transformation);
00084       
00085     printf("ransac_iterations: %d\n", ransac_iterations);
00086     if (sac_matches.size() > sac_min_inliers_)
00087     {
00088       // express the motion in the fixed frame
00089       AffineTransform motion_cam(sac_transformation);
00090       AffineTransform f2c = f2b_ * b2c_;
00091       AffineTransform f2c_new = f2c * motion_cam;      
00092       motion = f2c_new * f2c.inverse();
00093    
00094       // update the pose of the base frame
00095       f2b_ = f2c_new * b2c_.inverse();
00096    
00097       delete prev_frame_;
00098       
00099       result = true;
00100     }
00101     else
00102       result = false;
00103   }
00104   
00105   prev_frame_ = new RGBDFrame(frame);
00106 
00107   return result;
00108 }
00109        
00110 // frame_a = train, frame_b = query
00111 int MotionEstimationPairwiseRANSAC::pairwiseMatchingRANSAC(
00112   const RGBDFrame& frame_q, const RGBDFrame& frame_t,
00113   DMatchVector& best_inlier_matches,
00114   Eigen::Matrix4f& best_transformation)
00115 {
00116   // constants
00117   int min_sample_size = 3; 
00118    
00119   // **** establish matches ***************************************
00120    
00121   // build matcher  
00122   cv::BFMatcher matcher(cv::NORM_HAMMING, false);
00123 
00124   // train
00125   //printf("training\n");
00126   std::vector<cv::Mat> descriptors_vector;
00127   descriptors_vector.push_back(frame_t.descriptors);
00128   matcher.add(descriptors_vector);
00129   matcher.train();    
00130 
00131   // get matchers 
00132   DMatchVector candidate_matches;
00133   getCandidateMatches(frame_q, frame_t, matcher, candidate_matches);
00134   
00135   printf("candidate_matches.size(): %d\n", (int)candidate_matches.size());
00136   
00137   // check if enough matches are present
00138   if (candidate_matches.size() < min_sample_size)  return 0;
00139   if (candidate_matches.size() < sac_min_inliers_) return 0;
00140   
00141   // **** build 3D features for SVD ********************************
00142 
00143   PointCloudFeature features_t, features_q;
00144 
00145   features_t.resize(candidate_matches.size());
00146   features_q.resize(candidate_matches.size());
00147 
00148   for (int m_idx = 0; m_idx < candidate_matches.size(); ++m_idx)
00149   {
00150     const cv::DMatch& match = candidate_matches[m_idx];
00151     int idx_q = match.queryIdx;
00152     int idx_t = match.trainIdx; 
00153 
00154     PointFeature& p_t = features_t[m_idx];
00155     p_t.x = frame_t.kp_means[idx_t](0,0);
00156     p_t.y = frame_t.kp_means[idx_t](1,0);
00157     p_t.z = frame_t.kp_means[idx_t](2,0);
00158 
00159     PointFeature& p_q = features_q[m_idx];
00160     p_q.x = frame_q.kp_means[idx_q](0,0);
00161     p_q.y = frame_q.kp_means[idx_q](1,0);
00162     p_q.z = frame_q.kp_means[idx_q](2,0);
00163   }
00164 
00165   // **** main RANSAC loop ****************************************
00166   
00167   TransformationEstimationSVD svd;
00168   Eigen::Matrix4f transformation; // transformation used inside loop
00169   best_inlier_matches.clear(); 
00170   std::set<int> mask;
00171   
00172   int iteration = 0;  
00173   for (iteration = 0; iteration < ransac_max_iterations_; ++iteration)
00174   {   
00175     // generate random indices
00176     IntVector sample_idx;
00177     get3RandomIndices(candidate_matches.size(), mask, sample_idx);
00178     
00179     // build initial inliers from random indices
00180     IntVector init_inlier_idx;
00181     std::vector<cv::DMatch> init_inlier_matches;
00182 
00183     for (unsigned int s_idx = 0; s_idx < sample_idx.size(); ++s_idx)
00184     {
00185       int m_idx = sample_idx[s_idx];
00186       init_inlier_idx.push_back(m_idx);
00187       init_inlier_matches.push_back(candidate_matches[m_idx]);
00188     } 
00189     
00190     // estimate transformation from minimum set of random samples
00191     svd.estimateRigidTransformation(
00192       features_q, init_inlier_idx,
00193       features_t, init_inlier_idx,
00194       transformation);
00195 
00196     // transformation rejection
00197     
00198     /*
00199     double angular, linear;
00200     AffineTransform temp(transformation);
00201     getTfDifference(temp, linear, angular);
00202     if (linear > 0.10 || angular > 5.0 * M_PI / 180.0)
00203       continue;
00204     */
00205     
00206     // evaluate transformation fitness by checking distance to all points
00207     PointCloudFeature features_q_tf;
00208     pcl::transformPointCloud(features_q, features_q_tf, transformation);
00209 
00210     IntVector inlier_idx;
00211     std::vector<cv::DMatch> inlier_matches;
00212     
00213     for (int m_idx = 0; m_idx < candidate_matches.size(); ++m_idx)
00214     {
00215       // euclidedan distance test
00216       const PointFeature& p_t = features_t[m_idx];
00217       const PointFeature& p_q = features_q_tf[m_idx];
00218       float eucl_dist_sq = distEuclideanSq(p_t, p_q);
00219       
00220       if (eucl_dist_sq < sac_max_eucl_dist_sq_)
00221       {
00222         inlier_idx.push_back(m_idx);
00223         inlier_matches.push_back(candidate_matches[m_idx]);
00224 
00225         // reestimate transformation from all inliers
00226         if (sac_reestimate_tf_)
00227         {
00228           svd.estimateRigidTransformation(
00229             features_q, inlier_idx,
00230             features_t, inlier_idx,
00231             transformation);
00232           pcl::transformPointCloud(features_q, features_q_tf, transformation);
00233         }
00234       }
00235     }
00236     
00237     // check if inliers are better than the best model so far
00238     if (inlier_matches.size() > best_inlier_matches.size())
00239     {
00240       svd.estimateRigidTransformation(
00241         features_q, inlier_idx,
00242         features_t, inlier_idx,
00243         transformation);
00244 
00245       best_transformation = transformation;
00246       best_inlier_matches = inlier_matches;
00247     }
00248 
00249     double best_inlier_ratio = (double) best_inlier_matches.size() / 
00250                                (double) candidate_matches.size();
00251     
00252     // **** early termination: iterations + inlier ratio
00253     if(best_inlier_matches.size() >= sac_min_inliers_)
00254     {
00255       double h = log_one_minus_ransac_confidence_ / 
00256                 log(1.0 - pow(best_inlier_ratio, min_sample_size));
00257                 
00258       if (iteration > (int)(h+1)) break;
00259     }
00260   }
00261   
00262     printf("best_inlier_matches.size(): %d\n", (int)best_inlier_matches.size());
00263   
00264   return iteration;
00265 }
00266 
00267 // frame_a = train, frame_b = query
00268 void MotionEstimationPairwiseRANSAC::getCandidateMatches(
00269   const RGBDFrame& frame_q, const RGBDFrame& frame_t, 
00270   cv::DescriptorMatcher& matcher,
00271   DMatchVector& candidate_matches)
00272 {
00273   // **** build candidate matches ***********************************
00274   // assumes detectors and distributions are computed
00275   // establish all matches from b to a
00276 
00277   if (matcher_use_desc_ratio_test_)
00278   {
00279     std::vector<DMatchVector> all_matches2;
00280     
00281     matcher.knnMatch(
00282       frame_q.descriptors, all_matches2, 2);
00283 
00284     for (unsigned int m_idx = 0; m_idx < all_matches2.size(); ++m_idx)
00285     {
00286       const cv::DMatch& match1 = all_matches2[m_idx][0];
00287       const cv::DMatch& match2 = all_matches2[m_idx][1];
00288       
00289       double ratio = match1.distance / match2.distance;
00290       
00291       // remove bad matches - ratio test, valid keypoints
00292       if (ratio < matcher_max_desc_ratio_)
00293       {
00294         int idx_q = match1.queryIdx;
00295         int idx_t = match1.trainIdx; 
00296 
00297         if (frame_t.kp_valid[idx_t] && frame_q.kp_valid[idx_q])
00298           candidate_matches.push_back(match1);
00299       }
00300     }
00301   }
00302   else
00303   {
00304     DMatchVector all_matches;
00305     
00306     matcher.match(
00307       frame_q.descriptors, all_matches);
00308 
00309     for (unsigned int m_idx = 0; m_idx < all_matches.size(); ++m_idx)
00310     {
00311       const cv::DMatch& match = all_matches[m_idx];
00312 
00313       // remove bad matches - descriptor distance, valid keypoints
00314       if (match.distance < matcher_max_desc_dist_)
00315       {      
00316         int idx_q = match.queryIdx;
00317         int idx_t = match.trainIdx; 
00318         
00319         if (frame_t.kp_valid[idx_t] && frame_q.kp_valid[idx_q])
00320           candidate_matches.push_back(match);
00321       }
00322     }
00323   }
00324 }
00325 
00326 } // namespace rgbdtools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends


lib_rgbdtools
Author(s): Ivan Dryanovski
autogenerated on Tue Aug 27 2013 10:33:54