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
00042 log_one_minus_ransac_confidence_ = log(1.0 - ransac_confidence_);
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
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
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
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
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
00117 int min_sample_size = 3;
00118
00119
00120
00121
00122 cv::BFMatcher matcher(cv::NORM_HAMMING, false);
00123
00124
00125
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
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
00138 if (candidate_matches.size() < min_sample_size) return 0;
00139 if (candidate_matches.size() < sac_min_inliers_) return 0;
00140
00141
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
00166
00167 TransformationEstimationSVD svd;
00168 Eigen::Matrix4f transformation;
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
00176 IntVector sample_idx;
00177 get3RandomIndices(candidate_matches.size(), mask, sample_idx);
00178
00179
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
00191 svd.estimateRigidTransformation(
00192 features_q, init_inlier_idx,
00193 features_t, init_inlier_idx,
00194 transformation);
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
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
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
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
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
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
00268 void MotionEstimationPairwiseRANSAC::getCandidateMatches(
00269 const RGBDFrame& frame_q, const RGBDFrame& frame_t,
00270 cv::DescriptorMatcher& matcher,
00271 DMatchVector& candidate_matches)
00272 {
00273
00274
00275
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
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
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 }