00001
00024 #include "ccny_rgbd/mapping/keyframe_graph_detector.h"
00025
00026 namespace ccny_rgbd {
00027
00028 KeyframeGraphDetector::KeyframeGraphDetector(
00029 const ros::NodeHandle& nh,
00030 const ros::NodeHandle& nh_private):
00031 nh_(nh),
00032 nh_private_(nh_private)
00033 {
00034 srand(time(NULL));
00035
00036
00037 if (!nh_private_.getParam ("graph/max_ransac_iterations", max_ransac_iterations_))
00038 max_ransac_iterations_ = 2000;
00039 if (!nh_private_.getParam ("graph/save_ransac_results", save_ransac_results_))
00040 save_ransac_results_ = false;
00041 if (!nh_private_.getParam ("graph/ransac_results_path", ransac_results_path_))
00042 ransac_results_path_ = std::getenv("HOME");
00043 if (!nh_private_.getParam ("graph/n_ransac_candidates", n_ransac_candidates_))
00044 n_ransac_candidates_ = 15;
00045 if (!nh_private_.getParam ("graph/k_nearest_neighbors", k_nearest_neighbors_))
00046 k_nearest_neighbors_ = 15;
00047 if (!nh_private_.getParam ("graph/min_ransac_inliers", min_ransac_inliers_))
00048 min_ransac_inliers_ = 30;
00049 if (!nh_private_.getParam ("graph/max_corresp_dist_desc", max_corresp_dist_desc_))
00050 max_corresp_dist_desc_ = 1.0;
00051 if (!nh_private_.getParam ("graph/max_corresp_dist_eucl", max_corresp_dist_eucl_))
00052 max_corresp_dist_eucl_ = 0.03;
00053 if (!nh_private_.getParam ("graph/n_keypoints", n_keypoints_))
00054 n_keypoints_ = 200;
00055
00056
00057 max_corresp_dist_eucl_sq_ = max_corresp_dist_eucl_ * max_corresp_dist_eucl_;
00058 }
00059
00060 KeyframeGraphDetector::~KeyframeGraphDetector()
00061 {
00062
00063 }
00064
00065 void KeyframeGraphDetector::generateKeyframeAssociations(
00066 KeyframeVector& keyframes,
00067 KeyframeAssociationVector& associations)
00068 {
00069 prepareFeaturesForRANSAC(keyframes);
00070
00071
00072 visualOdometryAssociations(keyframes, associations);
00073
00074 treeAssociations(keyframes, associations);
00075
00076 }
00077
00078 void KeyframeGraphDetector::prepareFeaturesForRANSAC(
00079 KeyframeVector& keyframes)
00080 {
00081 double init_surf_threshold = 400.0;
00082 double min_surf_threshold = 25;
00083
00084 printf("preparing SURF features for RANSAC associations...\n");
00085
00086 cv::SurfDescriptorExtractor extractor;
00087
00088 for (unsigned int kf_idx = 0; kf_idx < keyframes.size(); kf_idx++)
00089 {
00090 RGBDKeyframe& keyframe = keyframes[kf_idx];
00091
00092 double surf_threshold = init_surf_threshold;
00093
00094 while (surf_threshold >= min_surf_threshold)
00095 {
00096 cv::SurfFeatureDetector detector(surf_threshold);
00097 keyframe.keypoints.clear();
00098 detector.detect(keyframe.rgb_img, keyframe.keypoints);
00099
00100 printf("[KF %d of %d] %d SURF keypoints detected (threshold: %.1f)\n",
00101 (int)kf_idx, (int)keyframes.size(),
00102 (int)keyframe.keypoints.size(), surf_threshold);
00103
00104 if ((int)keyframe.keypoints.size() < n_keypoints_)
00105 surf_threshold /= 2.0;
00106 else break;
00107 }
00108
00109 if (save_ransac_results_)
00110 {
00111 cv::Mat kp_img;
00112 cv::drawKeypoints(keyframe.rgb_img, keyframe.keypoints, kp_img);
00113 std::stringstream ss1;
00114 ss1 << "kp_" << kf_idx;
00115 cv::imwrite(ransac_results_path_ + "/" + ss1.str() + ".png", kp_img);
00116 }
00117
00118 extractor.compute(keyframe.rgb_img, keyframe.keypoints, keyframe.descriptors);
00119 keyframe.computeDistributions();
00120 }
00121 }
00122
00123 void KeyframeGraphDetector::visualOdometryAssociations(
00124 KeyframeVector& keyframes,
00125 KeyframeAssociationVector& associations)
00126 {
00127 for (unsigned int kf_idx_a = 0; kf_idx_a < keyframes.size()-1; ++kf_idx_a)
00128 {
00129
00130 unsigned int kf_idx_b = kf_idx_a + 1;
00131
00132
00133 RGBDKeyframe& keyframe_a = keyframes[kf_idx_a];
00134 RGBDKeyframe& keyframe_b = keyframes[kf_idx_b];
00135
00136
00137 KeyframeAssociation association;
00138
00139 association.type = KeyframeAssociation::VO;
00140 association.kf_idx_a = kf_idx_a;
00141 association.kf_idx_b = kf_idx_b;
00142 association.a2b = keyframe_a.pose.inverse() * keyframe_b.pose;
00143
00144 associations.push_back(association);
00145 }
00146 }
00147
00148 void KeyframeGraphDetector::manualBruteForceAssociations(
00149 KeyframeVector& keyframes,
00150 KeyframeAssociationVector& associations)
00151 {
00152
00153 double max_eucl_dist = 0.05;
00154 double max_desc_dist = 10.0;
00155 double min_inlier_ratio = 0.75;
00156 double min_inliers = 20;
00157
00158 double max_eucl_dist_sq = max_eucl_dist * max_eucl_dist;
00159
00160
00161
00162 std::vector<unsigned int> manual_keyframe_indices;
00163
00164 for (unsigned int kf_idx = 0; kf_idx < keyframes.size(); ++kf_idx)
00165 {
00166 const RGBDKeyframe& keyframe = keyframes[kf_idx];
00167 if(keyframe.manually_added)
00168 {
00169 printf("Manual keyframe: %d\n", kf_idx);
00170 manual_keyframe_indices.push_back(kf_idx);
00171 }
00172 }
00173
00174 for (unsigned int mn_idx_a = 0; mn_idx_a < manual_keyframe_indices.size(); ++mn_idx_a)
00175 for (unsigned int mn_idx_b = mn_idx_a+1; mn_idx_b < manual_keyframe_indices.size(); ++mn_idx_b)
00176 {
00177
00178 unsigned int kf_idx_a = manual_keyframe_indices[mn_idx_a];
00179 unsigned int kf_idx_b = manual_keyframe_indices[mn_idx_b];
00180
00181
00182 RGBDKeyframe& keyframe_a = keyframes[kf_idx_a];
00183 RGBDKeyframe& keyframe_b = keyframes[kf_idx_b];
00184
00185
00186 std::vector<cv::DMatch> all_matches, inlier_matches;
00187 Eigen::Matrix4f transformation;
00188
00189 pairwiseMatchingRANSAC(keyframe_a, keyframe_b,
00190 max_eucl_dist_sq, max_desc_dist, min_inlier_ratio,
00191 all_matches, inlier_matches, transformation);
00192
00193 if (inlier_matches.size() >= min_inliers)
00194 {
00195 printf("[RANSAC %d -> %d] OK (%d / %d)\n",
00196 kf_idx_a, kf_idx_b,
00197 (int)inlier_matches.size(), (int)all_matches.size());
00198
00199
00200 KeyframeAssociation association;
00201 association.type = KeyframeAssociation::RANSAC;
00202 association.kf_idx_a = kf_idx_a;
00203 association.kf_idx_b = kf_idx_b;
00204 association.matches = inlier_matches;
00205 association.a2b = tfFromEigen(transformation);
00206 associations.push_back(association);
00207 }
00208 else
00209 {
00210 printf("[RANSAC %d -> %d] FAIL (%d / %d)\n",
00211 kf_idx_a, kf_idx_b,
00212 (int)inlier_matches.size(), (int)all_matches.size());
00213 }
00214 }
00215 }
00216
00217 void KeyframeGraphDetector::pairwiseMatchingRANSAC(
00218 RGBDFrame& frame_a, RGBDFrame& frame_b,
00219 double max_eucl_dist_sq,
00220 double max_desc_dist,
00221 double sufficient_inlier_ratio,
00222 std::vector<cv::DMatch>& all_matches,
00223 std::vector<cv::DMatch>& best_inlier_matches,
00224 Eigen::Matrix4f& best_transformation)
00225 {
00226
00227 int min_sample_size = 3;
00228
00229 cv::FlannBasedMatcher matcher;
00230 TransformationEstimationSVD svd;
00231
00232
00233
00234
00235
00236 matcher.match(frame_b.descriptors, frame_a.descriptors, all_matches);
00237
00238
00239
00240 std::vector<cv::DMatch> candidate_matches;
00241 for (unsigned int m_idx = 0; m_idx < all_matches.size(); ++m_idx)
00242 {
00243 const cv::DMatch& match = all_matches[m_idx];
00244 int idx_b = match.queryIdx;
00245 int idx_a = match.trainIdx;
00246
00247 if (match.distance < max_desc_dist &&
00248 frame_a.kp_valid[idx_a] &&
00249 frame_b.kp_valid[idx_b])
00250 {
00251 candidate_matches.push_back(all_matches[m_idx]);
00252 }
00253 }
00254
00255 int size = candidate_matches.size();
00256
00257
00258
00259 PointCloudFeature features_a, features_b;
00260
00261 features_a.resize(size);
00262 features_b.resize(size);
00263
00264 for (int m_idx = 0; m_idx < size; ++m_idx)
00265 {
00266 const cv::DMatch& match = candidate_matches[m_idx];
00267 int idx_b = match.queryIdx;
00268 int idx_a = match.trainIdx;
00269
00270 PointFeature& p_a = features_a[m_idx];
00271 p_a.x = frame_a.kp_means[idx_a](0,0);
00272 p_a.y = frame_a.kp_means[idx_a](1,0);
00273 p_a.z = frame_a.kp_means[idx_a](2,0);
00274
00275 PointFeature& p_b = features_b[m_idx];
00276 p_b.x = frame_b.kp_means[idx_b](0,0);
00277 p_b.y = frame_b.kp_means[idx_b](1,0);
00278 p_b.z = frame_b.kp_means[idx_b](2,0);
00279 }
00280
00281
00282
00283 int best_n_inliers = 0;
00284 Eigen::Matrix4f transformation;
00285
00286 for (int iteration = 0; iteration < max_ransac_iterations_; ++iteration)
00287 {
00288
00289 IntVector sample_idx;
00290 getRandomIndices(min_sample_size, size, sample_idx);
00291
00292
00293 IntVector inlier_idx;
00294 std::vector<cv::DMatch> inlier_matches;
00295
00296 for (unsigned int s_idx = 0; s_idx < sample_idx.size(); ++s_idx)
00297 {
00298 int m_idx = sample_idx[s_idx];
00299 inlier_idx.push_back(m_idx);
00300 inlier_matches.push_back(candidate_matches[m_idx]);
00301 }
00302
00303
00304 svd.estimateRigidTransformation(
00305 features_b, inlier_idx,
00306 features_a, inlier_idx,
00307 transformation);
00308
00309
00310 PointCloudFeature features_b_tf;
00311 pcl::transformPointCloud(features_b, features_b_tf, transformation);
00312
00313 for (int m_idx = 0; m_idx < size; ++m_idx)
00314 {
00315 const PointFeature& p_a = features_a[m_idx];
00316 const PointFeature& p_b = features_b_tf[m_idx];
00317
00318 float dist_sq = distEuclideanSq(p_a, p_b);
00319
00320 if (dist_sq < max_eucl_dist_sq)
00321 {
00322 inlier_idx.push_back(m_idx);
00323 inlier_matches.push_back(candidate_matches[m_idx]);
00324
00325
00326 svd.estimateRigidTransformation(
00327 features_b, inlier_idx,
00328 features_a, inlier_idx,
00329 transformation);
00330 pcl::transformPointCloud(features_b, features_b_tf, transformation);
00331 }
00332 }
00333
00334
00335 int n_inliers = inlier_idx.size();
00336
00337 if (n_inliers > best_n_inliers)
00338 {
00339 svd.estimateRigidTransformation(
00340 features_b, inlier_idx,
00341 features_a, inlier_idx,
00342 transformation);
00343
00344 best_n_inliers = n_inliers;
00345 best_transformation = transformation;
00346 best_inlier_matches = inlier_matches;
00347 }
00348
00349
00350 double inlier_ratio = (double) n_inliers / (double) size;
00351
00352 if (inlier_ratio > sufficient_inlier_ratio)
00353 break;
00354 }
00355 }
00356
00357 void KeyframeGraphDetector::trainMatcher(
00358 const KeyframeVector& keyframes,
00359 cv::FlannBasedMatcher& matcher)
00360 {
00361 printf("Building aggregate feature vector...\n");
00362 std::vector<cv::Mat> descriptors_vector;
00363
00364 for (unsigned int kf_idx = 0; kf_idx < keyframes.size(); ++kf_idx)
00365 {
00366 const RGBDKeyframe& keyframe = keyframes[kf_idx];
00367 descriptors_vector.push_back(keyframe.descriptors);
00368 }
00369 matcher.add(descriptors_vector);
00370
00371 printf("Training feature matcher...\n");
00372 matcher.train();
00373 }
00374
00375 void KeyframeGraphDetector::treeAssociations(
00376 KeyframeVector& keyframes,
00377 KeyframeAssociationVector& associations)
00378 {
00379
00380 double sufficient_ransac_inlier_ratio = 1.0;
00381
00382
00383 cv::FlannBasedMatcher matcher;
00384 trainMatcher(keyframes, matcher);
00385
00386
00387 printf("Keyframe lookups...\n");
00388
00389 for (unsigned int kf_idx = 0; kf_idx < keyframes.size(); ++kf_idx)
00390 {
00391 printf("[KF %d of %d]:\n", (int)kf_idx, (int)keyframes.size());
00392 RGBDFrame& keyframe = keyframes[kf_idx];
00393
00394
00395 std::vector<std::vector<cv::DMatch> > matches_vector;
00396 matcher.knnMatch(keyframe.descriptors, matches_vector, k_nearest_neighbors_);
00397
00398
00399 std::vector<std::pair<int, int> > bins;
00400 bins.resize(keyframes.size());
00401 for (unsigned int b = 0; b < bins.size(); ++b)
00402 bins[b] = std::pair<int, int>(0, b);
00403
00404
00405 for (unsigned int j = 0; j < matches_vector.size(); ++j)
00406 {
00407 std::vector<cv::DMatch>& matches = matches_vector[j];
00408 for (unsigned int k = 0; k < matches.size(); ++k)
00409 {
00410 bins[matches[k].imgIdx].first++;
00411 }
00412 }
00413
00414
00415 std::sort(bins.begin(), bins.end(), std::greater<std::pair<int, int> >());
00416
00417
00418 printf(" - best matches: ");
00419 for (int b = 0; b < n_ransac_candidates_; ++b)
00420 printf("[%d(%d)] ", bins[b].second, bins[b].first);
00421 printf("\n");
00422
00423
00424
00425 printf(" - candidate matches: ");
00426 IntVector ransac_candidates;
00427 int n_ransac_candidates_found = 0;
00428 for (unsigned int b = 0; b < bins.size(); ++b)
00429 {
00430 unsigned int index_a = kf_idx;
00431 unsigned int index_b = bins[b].second;
00432 int corresp_count = bins[b].first;
00433
00434
00435
00436 if (index_b > index_a &&
00437 corresp_count >= min_ransac_inliers_)
00438 {
00439 ransac_candidates.push_back(index_b);
00440 ++n_ransac_candidates_found;
00441 printf("[%d(%d)] ", index_b, corresp_count);
00442 }
00443
00444 if (n_ransac_candidates_found >= n_ransac_candidates_) break;
00445 }
00446 printf("\n");
00447
00448
00449
00450 for (unsigned int rc = 0; rc < ransac_candidates.size(); ++rc)
00451 {
00452 unsigned int kf_idx_a = kf_idx;
00453 unsigned int kf_idx_b = ransac_candidates[rc];
00454
00455 RGBDKeyframe& keyframe_a = keyframes[kf_idx_a];
00456 RGBDKeyframe& keyframe_b = keyframes[kf_idx_b];
00457
00458 std::vector<cv::DMatch> all_matches;
00459 std::vector<cv::DMatch> inlier_matches;
00460
00461
00462 Eigen::Matrix4f transformation;
00463
00464 pairwiseMatchingRANSAC(keyframe_a, keyframe_b,
00465 max_corresp_dist_eucl_sq_, max_corresp_dist_desc_,
00466 sufficient_ransac_inlier_ratio,
00467 all_matches, inlier_matches, transformation);
00468
00469 if ((int)inlier_matches.size() >= min_ransac_inliers_)
00470 {
00471 if (save_ransac_results_)
00472 {
00473 cv::Mat img_matches;
00474 cv::drawMatches(keyframe_b.rgb_img, keyframe_b.keypoints,
00475 keyframe_a.rgb_img, keyframe_a.keypoints,
00476 inlier_matches, img_matches);
00477
00478 std::stringstream ss1;
00479 ss1 << kf_idx_a << "_to_" << kf_idx_b;
00480 cv::imwrite(ransac_results_path_ + "/" + ss1.str() + ".png", img_matches);
00481 }
00482
00483 printf(" - RANSAC %d -> %d: PASS\n", kf_idx_a, kf_idx_b);
00484
00485
00486 KeyframeAssociation association;
00487 association.type = KeyframeAssociation::RANSAC;
00488 association.kf_idx_a = kf_idx_a;
00489 association.kf_idx_b = kf_idx_b;
00490 association.matches = inlier_matches;
00491 association.a2b = tfFromEigen(transformation);
00492 associations.push_back(association);
00493 }
00494 else
00495 printf(" - RANSAC %d -> %d: FAIL\n", kf_idx_a, kf_idx_b);
00496 }
00497 }
00498 }
00499
00500
00501
00502 void KeyframeGraphDetector::getRandomIndices(
00503 int k, int n, IntVector& output)
00504 {
00505 while ((int)output.size() < k)
00506 {
00507 int random_number = rand() % n;
00508 bool duplicate = false;
00509
00510 for (unsigned int i = 0; i < output.size(); ++i)
00511 {
00512 if (output[i] == random_number)
00513 {
00514 duplicate = true;
00515 break;
00516 }
00517 }
00518
00519 if (!duplicate)
00520 output.push_back(random_number);
00521 }
00522 }
00523
00524 }