00001
00015 #ifndef VSLAM_GRAPH_BUILDER_H_INCLUDED
00016 #define VSLAM_GRAPH_BUILDER_H_INCLUDED
00017 #include "pose_graph.h"
00018 #include "graph_utils.h"
00019 #include "landmark_manager.h"
00020 #include "emat_estimation.h"
00021 #include "grid.h"
00022
00023 #include <algorithm>
00024 #include <tr1/functional>
00025 #include <string>
00026 namespace vslam{
00027
00028
00029
00030
00059 template<class PoseGraphT> void findLocalMatchesSE3(
00060 const PoseGraphT& g,
00061 typename graph_traits<PoseGraphT>::vertex_descriptor vd1,
00062 typename graph_traits<PoseGraphT>::vertex_descriptor vd2,
00063 shared_ptr<RobustFeatureMatcher> rmatcher,
00064 vector<cv::DMatch>& matches){
00065 assert(matches.size()==0);
00066 typename graph_traits<PoseGraphT>::vertex_descriptor vd0;
00067 typename graph_traits<PoseGraphT>::adjacency_iterator vi, vi_end;
00068 for(tie(vi, vi_end) = adjacent_vertices(vd1 , g); vi!=vi_end; ++vi){
00069 if(*vi!=vd2){
00070 vd0=*vi;
00071 break;
00072 }
00073 }
00074 if(vi==vi_end) return;
00075
00076 typename property_map<PoseGraphT, vertex_kp_t>::const_type kp_pmap = get(vertex_kp, g);
00077 typename property_map<PoseGraphT, vertex_desc_t>::const_type desc_pmap = get(vertex_desc, g);
00078 Grid grid2(60,60, kp_pmap[vd2]);
00079
00080 for(size_t i=0; i<kp_pmap[vd1].size(); i++) {
00081 int j = getFeatureIdx(g, i, vd1, vd2);
00082 int h = getFeatureIdx(g, i, vd1, vd0);
00083 if(j==BAD_INDEX){
00084 Vector3d pt_c2;
00085 Vector2d c2Pixel;
00086 if(h != BAD_INDEX){
00087 pt_c2 = get(vertex_transform, g, vd2) * triangulatePointWrtWorldPos(
00088 g, FeatureID<PoseGraphT>(vd0, h), FeatureID<PoseGraphT>(vd1, i));
00089 c2Pixel = PanoImCoord::fromHomogenous(pt_c2).getPixel();
00090 } else{
00091 pt_c2 = PanoImCoord::fromPixel(
00092 Vector2d(kp_pmap[vd1][i].pt.x, kp_pmap[vd1][i].pt.y)).getHomogenous();
00093 pt_c2 = (getEdgeTransform(g, vd1, vd2).rotation_matrix() * pt_c2).eval();
00094 c2Pixel = PanoImCoord::fromHomogenous(pt_c2).getPixel();
00095 }
00096 vector<int> keypoint_idxs_c2 = grid2.getNearKeypoints(grid2.getCell(c2Pixel));
00097
00098 vector<cv::KeyPoint> keypoints2_sel=getArrayIdices(kp_pmap[vd2], keypoint_idxs_c2);
00099 cv::Mat descriptors2_sel=getArrayIdices<cv::Mat>(desc_pmap[vd2], keypoint_idxs_c2);
00100
00101 vector<cv::DMatch> matches_tmp;
00102 RobustFeatureMatcherStats stats;
00103 rmatcher->nonsymetricalMatch(keypoints2_sel, mkContainer<vector>(kp_pmap[vd1][i]),
00104 descriptors2_sel,
00105 getArrayIdices<cv::Mat>(desc_pmap[vd1], mkContainer<vector>((int)i)),
00106 stats, matches_tmp);
00107 if(matches_tmp.size()>=1){
00108 cv::DMatch tmp = matches_tmp[0];
00109 tmp.queryIdx=keypoint_idxs_c2[matches_tmp[0].trainIdx];
00110 tmp.trainIdx=i;
00111 matches.push_back(tmp);
00112 }
00113 }
00114 }
00115 }
00116
00117 template<class PoseGraphT> void findLocalMatchesSO3(
00118 const PoseGraphT& g,
00119 typename graph_traits<PoseGraphT>::vertex_descriptor tvd,
00120 typename graph_traits<PoseGraphT>::vertex_descriptor qvd,
00121 shared_ptr<RobustFeatureMatcher> rmatcher,
00122 Vector2d grid_dim,
00123 bool skip_landmarks,
00124 vector<cv::DMatch>& matches){
00125 assert(matches.size()==0);
00126
00127 typename property_map<PoseGraphT, vertex_kp_t>::const_type kp_pmap = get(vertex_kp, g);
00128 typename property_map<PoseGraphT, vertex_desc_t>::const_type desc_pmap = get(vertex_desc, g);
00129 Grid grid2(grid_dim(0), grid_dim(1), kp_pmap[qvd]);
00130
00131 for(size_t i=0; i<kp_pmap[tvd].size(); i++) {
00132 int j = getFeatureIdx(g, i, tvd, qvd);
00133 if(j!=BAD_INDEX) continue;
00134 if(skip_landmarks && (get(vertex_fix_idx, g, tvd)[i]!=BAD_INDEX)) continue;
00135
00136 Vector2d ctvd_pixel = Vector2d(kp_pmap[tvd][i].pt.x, kp_pmap[tvd][i].pt.y);
00137 Vector3d pt_ct = PanoImCoord::fromPixel(ctvd_pixel).getHomogenous();
00138 Vector3d pt_cq = getEdgeTransform(g, tvd, qvd).rotation_matrix() * pt_ct;
00139 Vector2d cqvd_pixel = PanoImCoord::fromHomogenous(pt_cq).getPixel();
00140 vector<int> keypoint_idxs_c2 = grid2.getNearKeypoints(grid2.getCell(cqvd_pixel));
00141
00142 vector<cv::KeyPoint> keypointsq_sel=getArrayIdices(kp_pmap[qvd], keypoint_idxs_c2);
00143 cv::Mat descriptorsq_sel=getArrayIdices<cv::Mat>(desc_pmap[qvd], keypoint_idxs_c2);
00144
00145 vector<cv::DMatch> matches_tmp;
00146 RobustFeatureMatcherStats stats;
00147 rmatcher->nonsymetricalMatch(
00148 keypointsq_sel,
00149 mkContainer<vector>(kp_pmap[tvd][i]),
00150 descriptorsq_sel,
00151 getArrayIdices<cv::Mat>(desc_pmap[tvd], mkContainer<vector>((int)i)),
00152 stats,
00153 matches_tmp);
00154
00155 if(matches_tmp.size()>=1){
00156 cv::DMatch tmp = matches_tmp[0];
00157 tmp.queryIdx=keypoint_idxs_c2[matches_tmp[0].trainIdx];
00158 tmp.trainIdx=i;
00159 matches.push_back(tmp);
00160 }
00161 }
00162 }
00164
00166
00167
00168
00171
00172
00175
00176
00177 template<class PoseGraphT>
00178 bool OneDetectorNodeBuilder<PoseGraphT>::build(const cv::Mat & image, int image_seq_num,
00179 uint64_t pose_timestamp, typename graph_traits<PoseGraphT>::vertex_descriptor& vd, PoseGraphT& g){
00180 using namespace boost;
00181 ros::WallTime nodebuilder_start_time = ros::WallTime::now();
00182 assert(!image.empty());
00183 vd = add_vertex(g);
00184 get(vertex_seq, g, vd) = image_seq_num;
00185 get(vertex_timestamp, g, vd) = pose_timestamp;
00186 vector<cv::KeyPoint> & keypoints = get(vertex_kp, g, vd);
00187 cv::Mat & descriptors = get(vertex_desc, g, vd);
00188 if(feature_2d_detector){
00189 (*feature_2d_detector)(image, mask, keypoints, descriptors, false);
00190 } else{
00191 detector->detect(image, keypoints, mask);
00192 }
00193 int detected_kpts = keypoints.size();
00194 vector<int> keep_kp_idx;
00195 if(nms_options.do_nms){
00196 nonMaximaSuppresion(keypoints, nms_options.target_num_points, keep_kp_idx);
00197 keypoints=getArrayIdices<cv::KeyPoint>(keypoints, keep_kp_idx);
00198 }
00199 if(feature_2d_detector && nms_options.do_nms){
00200 descriptors=getArrayIdices<cv::Mat>(descriptors, keep_kp_idx);
00201 } else{
00202 extractor->compute(image, keypoints, descriptors);
00203 }
00204
00205 vector<int> & pt3_idx = get(vertex_fix_idx, g, vd);
00206 pt3_idx = vector<int>(keypoints.size());
00207 std::fill_n(pt3_idx.begin(), keypoints.size(), BAD_INDEX);
00208 get(vertex_debug_info, g, vd).double_propmap["num_kpts"]=detected_kpts;
00209 get(vertex_debug_info, g, vd).double_propmap["num_kpts_nms"]=keypoints.size();
00210 ROS_INFO_STREAM_NAMED("PoseGraph", "constructed node for image number " << image_seq_num <<
00211 ". Detected " << detected_kpts << " keypoints. " <<
00212 "Out of this: " << keypoints.size() << " were retained adter NMS.");
00213
00214 ros::WallDuration nodebuilder_duration = ros::WallTime::now() - nodebuilder_start_time;
00215 get(vertex_debug_info, g, vd).double_propmap["timings_nodebuilder_d"]=
00216 nodebuilder_duration.toSec();
00217 return true;
00218 }
00219
00220
00221 template<class PoseGraphT> void OneDetectorNodeBuilder<PoseGraphT>::demolish( PoseGraphT& g,
00222 Points<PoseGraphT>& points, typename graph_traits<PoseGraphT>::vertex_descriptor & vd){
00223 vector<cv::KeyPoint> & keypoints = get(vertex_kp, g, vd);
00224 vector<int> & fixed_points = get(vertex_fix_idx, g, vd);
00225 for(size_t i = 0; i<keypoints.size(); i++){
00226 if(fixed_points[i] != BAD_INDEX){
00227
00228 points.deleteLmObs(g, FeatureID<PoseGraphT>(vd, i));
00229 }
00230 }
00231
00232 typename graph_traits<PoseGraphT>::adjacency_iterator vi, vi_end;
00233 for(tie(vi, vi_end) = adjacent_vertices(vd , g); vi!=vi_end; ++vi){
00234 remove_edge(*vi, vd, g);
00235 remove_edge(vd, *vi, g);
00236 }
00237
00238 get(vertex_debug_info, g, vd).double_propmap["deleted"]= 1.0;
00239 get(vertex_debug_info, g, vd).double_propmap.clear();
00240 }
00241
00243
00244
00245
00249 template<class G> void setRelTranslationError(
00250 double r_min, double r_max,
00251 typename graph_traits<G>::vertex_descriptor vs,
00252 typename graph_traits<G>::vertex_descriptor vt,
00253 G& g){
00254 double dist = get(edge_transform, g, edge(vs, vt, g).first).translation().norm();
00255 double error = (dist*r_max - dist*r_min) / (dist*r_max);
00256 get(edge_rel_scale_error, g, edge(vs, vt, g).first) = error;
00257 get(edge_rel_scale_error, g, edge(vt, vs, g).first) = error;
00258 }
00259
00260
00261
00267
00268
00280 template<class G> void MonoFtrClassEdgeBuilder<G>::compute3viewStructure( VertexD vad, VertexD vbd,
00281 VertexD vcd, G & g, IdxPoint3dVec& common_pts_3d, SE3& scaled_T_vbd_vcd){
00282 using namespace boost;
00283 typename property_map<G, edge_kp_idx_map_t>::type ekpimap = get(edge_kp_idx_map, g);
00284
00285 EdgeD edba = edge(vbd, vad, g).first;
00286 EdgeD edbc = edge(vbd, vcd, g).first;
00287 const map<int, int>& ba_idx = ekpimap[edba];
00288 const map<int, int>& bc_idx = ekpimap[edbc];
00289 Points3dSTL pts_ab;
00290
00291 computeStructure(getEdgeTransform(g, vbd, vad), computeMatches(vbd, vad, g), pts_ab);
00292
00293 vector<int> common_idx = switchCont<vector>(getCommon(
00294 transformF<int>(mapToList(ba_idx), getFirst),
00295 transformF<int>(mapToList(bc_idx), getFirst)));
00296 Points3dSTL pts_ba_common = switchCont<vector>(transformF<Vector3d>(
00297 getByIdx(indexBy(transformF<int>(mapToList(ba_idx), getFirst), pts_ab), common_idx),
00298 getSecond));
00299
00300 Points3dSTL pts_bc;
00301
00302 computeStructure(getEdgeTransform(g, vbd, vcd) , computeMatches(vbd, vcd, g), pts_bc);
00303 Points3dSTL pts_bc_common = switchCont<vector>(transformF<Vector3d>(
00304 getByIdx(indexBy(transformF<int>(mapToList(bc_idx), getFirst), pts_bc), common_idx),
00305 getSecond));
00306 double r_low, r_hi;
00307 double ab_to_bc_ratio;
00308 computeScale(pts_ba_common, pts_bc_common, r_low, ab_to_bc_ratio, r_hi);
00309 setRelTranslationError(r_low, r_hi, vbd, vcd, g);
00310 Points3dSTL::const_iterator pts_ba_common_it = pts_bc_common.begin();
00311 Points3dSTL::const_iterator pts_bc_common_it = pts_ba_common.begin();
00312 BOOST_FOREACH(int i, common_idx){
00313 common_pts_3d.push_back(std::make_pair(i, *pts_bc_common_it));
00314 ++pts_ba_common_it;
00315 ++pts_bc_common_it;
00316 }
00317
00318
00319 scaled_T_vbd_vcd = SE3(getEdgeTransform(g, vbd, vcd).rotation_matrix(),
00320 getEdgeTransform(g, vbd, vcd).translation() * ab_to_bc_ratio);
00321
00322
00323
00324 }
00325
00326
00342 template<class G> void MonoFtrClassEdgeBuilder<G>::matchScaleFindNewLandmarks(
00343 VertexD vsrc, VertexD vdest, Points<G> & points, G & g){
00344 using namespace boost;
00345 typename graph_traits<G>::adjacency_iterator vi, vi_end;
00346 int new_track_count=0;
00347
00348 for(tie(vi, vi_end) = adjacent_vertices(vsrc , g); vi!=vi_end; ++vi){
00349 if(*vi != vdest){
00350 IdxPoint3dVec common_pts_3d_vsrc;
00351 SE3 scaled_T_vsrc_vdest;
00352 compute3viewStructure(*vi, vsrc, vdest, g, common_pts_3d_vsrc, scaled_T_vsrc_vdest);
00353 if(get(vertex_keyframe_flag, g, *vi)){
00354 get(edge_transform, g, edge(vsrc, vdest, g).first) = scaled_T_vsrc_vdest;
00355 get(edge_transform, g, edge(vdest, vsrc, g).first) = scaled_T_vsrc_vdest.inverse();
00356 get(vertex_transform, g, vdest) = scaled_T_vsrc_vdest * get(vertex_transform, g, vsrc);
00357 }
00358 }
00359 }
00360
00361
00362 for(tie(vi, vi_end) = adjacent_vertices(vsrc , g); vi!=vi_end; ++vi){
00363 if(*vi != vdest){
00364
00365 IdxPoint3dVec common_pts_3d_vsrc;
00366 SE3 scaled_T_vsrc_vdest;
00367 compute3viewStructure(*vi, vsrc, vdest, g, common_pts_3d_vsrc, scaled_T_vsrc_vdest);
00368
00369 IdxPoint3dVec::const_iterator common_pts_3d_it = common_pts_3d_vsrc.begin();
00370 while(common_pts_3d_it!=common_pts_3d_vsrc.end()){
00371 FeatureID<G> srcf = FeatureID<G>(vsrc, common_pts_3d_it->first);
00372 FeatureID<G> destf = FeatureID<G>(vdest, getFeatureIdx(g, srcf, vdest));
00373 FeatureID<G> vif = FeatureID<G>(*vi, getFeatureIdx(g, srcf, *vi));
00374
00375
00376 if(!isLandmakFeature(g, vif) && !isLandmakFeature(g, srcf) &&
00377 !isLandmakFeature(g, destf)){
00378 if(points.fixNewLandmark(vif, srcf, destf, g)){
00379 new_track_count++;
00380 }
00381 }
00382 ++common_pts_3d_it;;
00383 }
00384 }
00385 }
00386 std::string num_new_lms_key="num_new_lms";
00387 map<std::string, double> & pmap = get(vertex_debug_info, g, vsrc).double_propmap;
00388 if(pmap.find(num_new_lms_key) == pmap.end()){
00389 pmap[num_new_lms_key]= new_track_count;
00390 } else{
00391 get(vertex_debug_info, g, vdest).double_propmap[num_new_lms_key]=new_track_count;
00392 }
00393 ROS_INFO_STREAM_NAMED("EdgeBulder", "# of new tracks: " << new_track_count);
00394 get(vertex_debug_info, g, vsrc).double_propmap["tracks_new"]=new_track_count;
00395 }
00397
00398
00399
00400
00409 template<class G> void MonoFtrClassEdgeBuilder<G>::computeScale(VertexD convd, VertexD newvd,
00410 G & g, Points<G>& points, SE3& scaled_T_vbd_vcd){
00411
00412 scaled_T_vbd_vcd = SE3(scaled_T_vbd_vcd.rotation_matrix(),
00413 scaled_T_vbd_vcd.translation().normalized());
00414 VertexD vad, vbd, vcd;
00415
00416
00417 bool found_neighbour = false;
00418 typename graph_traits<G>::adjacency_iterator vi, vi_end;
00419 for(tie(vi, vi_end) = adjacent_vertices(convd , g); vi!=vi_end; ++vi){
00420 if(*vi != newvd){
00421 found_neighbour = true;
00422 vad = *vi;
00423 vbd = convd;
00424 vcd = newvd;
00425 if(get(vertex_keyframe_flag, g, *vi)) break;
00426 }
00427 }
00428
00429 double total2;
00430 if(found_neighbour){
00431
00432 vector<int> common_b_idx = common_feature_tracks<vector>(g, vad, vbd, vcd);
00433 int count=0;
00434 ALIGNED<ScaleObservation>::vector data;
00435 ALIGNED<ScaleObservation>::vector data_lm;
00436 for(size_t i = 0; i<common_b_idx.size(); i++){
00437 ScaleObservation datum;
00438 FeatureID<G> vbd_f(vbd, common_b_idx[i]);
00439 FeatureID<G> vcd_f(
00440 vcd,
00441 (get(edge_kp_idx_map, g, edge(vbd, vcd, g).first).find(common_b_idx[i]))->second);
00442 datum.k_proj_measurement = getFeaturePixel(g, vbd_f);
00443 datum.n_proj_measurement = getFeaturePixel(g, vcd_f);
00444 datum.T_wk = get(vertex_transform, g, vbd);
00445 datum.T_kn = scaled_T_vbd_vcd;
00446 int fix_idx_i = get(vertex_fix_idx, g, vbd)[common_b_idx[i]];
00447 if(fix_idx_i!=BAD_INDEX && points.getPoint(fix_idx_i).initialized){
00448 datum.lm_estimate_kk_k =
00449 get(vertex_transform, g, vbd) *points.getPoint(fix_idx_i).global;
00450 data_lm.push_back(datum);
00451 } else{
00453 datum.lm_estimate_kk_k =
00454 get(vertex_transform, g, vbd) * triangulatePointWrtWorldPos(g, vbd_f, vcd_f);
00455 if(count < 1) data_lm.push_back(datum);
00456 count++;
00457 }
00458 data.push_back(datum);
00459 }
00460
00461
00462 const double reproj_error_tolerance = 5;
00463 ScaleReprojectionError error_func;
00464 typedef MDErrorFuncAdaptor<ScaleReprojectionError> AErrorFuncT;
00465 AErrorFuncT adapted_error_func(error_func);
00466 typedef RealErrorMaxErrorAccumulator<AErrorFuncT> ErrorAccumT;
00467 ErrorAccumT error_accum(adapted_error_func, reproj_error_tolerance);
00468 shared_ptr<ModelBuilder<ErrorAccumT::ModelClassT> > mbuilder(
00469 new ScaleModelBuilder<ErrorAccumT>(error_accum));
00470
00471 ROS_INFO_STREAM_NAMED("EdgeBulder", "# total common features for scale matching: " <<
00472 data.size() << " " << data_lm.size());
00473
00474
00475 typedef Model<double, ScaleObservation> ModelT;
00476 typedef DataSelector<typename ModelT::DataVec> DataSelectorT;
00477
00478
00479 shared_ptr<DataSelectorT> selector(new RandomDataSelector<typename ModelT::DataVec>(
00480 data, mbuilder->getSize(), 100));
00481 shared_ptr<ModelT> best_model = ranSaC<ErrorAccumT>(mbuilder, selector, data);
00482 assert(best_model);
00483 total2 = best_model->getModel();
00484 ROS_INFO_STREAM_NAMED("EdgeBulder", "# of scale-match inliers: " <<
00485 best_model->getInlierCount() << " " << best_model->getError());
00486 } else{
00487
00488 total2=1.0;
00489 }
00490
00491 SE3 tmp(scaled_T_vbd_vcd.unit_quaternion(),
00492 total2 *scaled_T_vbd_vcd.translation());
00493 scaled_T_vbd_vcd = tmp;
00494 get(edge_transform, g, edge(convd, newvd, g).first) = scaled_T_vbd_vcd;
00495 get(edge_transform, g, edge(newvd, convd, g).first) = scaled_T_vbd_vcd.inverse();
00496 get(vertex_transform, g, newvd) =
00497 scaled_T_vbd_vcd * get(vertex_transform, g, convd);
00498 }
00499
00500
00501
00502
00503
00504
00517 template<class G> void EdgeBuilder<G>::featureSelection(
00518 G& g,
00519 VertexD vd,
00520 int target_num,
00521 vector<int>& keep_idxs,
00522 vector<cv::KeyPoint>& sel_keypoints,
00523 cv::Mat& sel_descriptors){
00524 keep_idxs.clear();
00525 sel_keypoints.clear();
00526
00527 nonMaximaSuppresion(get(vertex_kp, g, vd), target_num, keep_idxs);
00528 sel_keypoints= getArrayIdices(get(vertex_kp, g, vd), keep_idxs);
00529 sel_descriptors= getArrayIdices<cv::Mat>(get(vertex_desc, g, vd), keep_idxs);
00530
00531 ROS_INFO_STREAM_NAMED("EdgeBuilder", "Using " << keep_idxs.size() <<
00532 " features in image " << printVertexId(g, vd) << " for grobal matching.");
00533 }
00534
00547 template<class G> bool MonoFtrClassEdgeBuilder<G>::unguidedMatching(
00548 const vector<cv::KeyPoint>& sel_tvd_keypoints,
00549 const vector<cv::KeyPoint>& sel_qvd_keypoints,
00550 const cv::Mat& sel_tvd_descriptors,
00551 const cv::Mat& sel_qvd_descriptors,
00552 SE3& T_tvd_qvd,
00553 std::vector<cv::DMatch>& global_dmatches_c1c2){
00554 std::vector<cv::DMatch> global_dmatches_c1c2_0;
00555
00556 RobustFeatureMatcherStats stats;
00557 rmatcher->symaetricalMatch(sel_tvd_keypoints, sel_qvd_keypoints,
00558 sel_tvd_descriptors, sel_qvd_descriptors, stats, global_dmatches_c1c2_0);
00559 ROS_INFO_STREAM_NAMED("EdgeBuilder", "# non-symetrical matches: " << stats.ratio_qt);
00560 ROS_INFO_STREAM_NAMED("EdgeBuilder", "# symetrical matches: " << stats.symetry);
00561 ImageMatchVec global_matches_c1c2 =
00562 imageMatchCoords(sel_tvd_keypoints, sel_qvd_keypoints, global_dmatches_c1c2_0);
00563 if(!rmatcher->ransacTest(
00564 global_matches_c1c2, global_dmatches_c1c2_0, stats, global_dmatches_c1c2, T_tvd_qvd)){
00565 ROS_WARN_NAMED("PoseGraph", "Model estimation failed. RanSac did not return model.");
00566 return false;
00567 } else{
00568 ROS_INFO_STREAM_NAMED("PoseGraph.EdgeBuilder", "# RanSaC-filtered matches: " << stats.ransac);
00569 return true;
00570 }
00571 }
00572
00573
00585 template<class ErrorAccumT> typename ErrorAccumT::ErrorT outlierRemoval(
00586 const Matrix3d& E,
00587 const ErrorAccumT& ea,
00588 const ImageMatchVec& matches_c1c2,
00589 const vector<cv::DMatch>& dmatches_c1c2,
00590 vector<cv::DMatch>& filtered_matches_c1c2){
00591 ALIGNED<Matrix3d>::vector Ematrices;
00592 Ematrices.push_back(E);
00593 shared_ptr<EMatrixModel> model =
00594 DummyModelBuilder<ErrorAccumT>( ea, Ematrices)(ImageMatchVec());
00595 model->compute(matches_c1c2);
00596 MaskVec::const_iterator itIn= model->getInlierMask().begin();
00597 std::vector<cv::DMatch>::const_iterator itM = dmatches_c1c2.begin();
00598 while(itIn!= model->getInlierMask().end()) {
00599 if (*itIn) {
00600 filtered_matches_c1c2.push_back(*itM);
00601 }
00602 ++itIn, ++itM;
00603 }
00604 return model->getError();
00605 }
00606
00607
00616 template<class G> void MonoFtrClassEdgeBuilder<G>::guidedMatching(
00617 G& g,
00618 VertexD qvd,
00619 VertexD tvd){
00620 ROS_INFO_NAMED("EdgeBuilder", "Starting local matching.");
00621 PerformanceLogger<G> pl(g, qvd, "local_matching");
00622 typename property_map<G, vertex_kp_t>::type vkp_pmap = get(vertex_kp, g);
00623 vector<cv::DMatch> local_dmatches0, local_dmatches;
00624 vector<int> retain_idxs;
00625 findLocalMatchesSO3(g, tvd, qvd, rmatcher, Vector2d(60, 60), false, local_dmatches);
00626 if(local_dmatches.size() > 0){
00627 for(size_t i = 0 ; i< local_dmatches.size();i++){
00628 if(filter_index_pair_duplicates(local_dmatches[i], tvd, qvd, g)){
00629 retain_idxs.push_back(i);
00630 }
00631 }
00632 local_dmatches=getArrayIdices(local_dmatches, retain_idxs);
00633 ROS_INFO_STREAM_NAMED("PoseGraph.EdgeBuilder",
00634 "# non-symetrical matches (excl global): " << local_dmatches.size());
00635 ImageMatchVec matches_c1c2 =
00636 imageMatchCoords(vkp_pmap[tvd], vkp_pmap[qvd], local_dmatches);
00638 RealErrorMaxErrorAccumulator<AngleError> ea(AngleError(), ((M_PI / 180.0)*1.0));
00639 SE3 T_tvd_qvd = getEdgeTransform(g, tvd, qvd);
00640 outlierRemoval(
00641 sE3ToE(T_tvd_qvd),
00642 ea,
00643 matches_c1c2,
00644 local_dmatches,
00645 local_dmatches0);
00646 std::for_each(local_dmatches0.begin(), local_dmatches0.end(), std::tr1::bind(
00647 add_idx_pair_from_dmatch<G>, std::tr1::placeholders::_1, tvd, qvd,
00648 std::tr1::ref(g)));
00649 int tmp = get(edge_kp_idx_map, g, edge(qvd, tvd, g).first).size();
00650 ROS_INFO_STREAM_NAMED("EdgeBuilder",
00651 "# matches satisfying 2-view constraint (excl. global): " << local_dmatches0.size());
00652 ROS_INFO_STREAM_NAMED("EdgeBuilder",
00653 "# matches satisfying 2-view constraint (incl. global): " << tmp);
00654 get(vertex_debug_info, g, qvd).double_propmap["num_2view_match_kpts_tot"]=tmp;
00655 get(vertex_debug_info, g, qvd).double_propmap["num_2view_match_kpts_loc"]=
00656 local_dmatches0.size();
00657
00658 } else{
00659 ROS_INFO_NAMED("PoseGraph", "Did not find any new mactehs.");
00660 }
00661 }
00662
00663
00664
00665
00666
00667
00668 template<class G> bool MonoFtrClassEdgeBuilder<G>::buildImpl(
00669 const VertexD & convd, const VertexD & newvd, Points<G> & points, G & g) {
00670 using namespace boost;
00671 ROS_INFO_STREAM_NAMED("PoseGraph", "Constructing edge (" << printVertexId(g, convd) <<
00672 ", " << printVertexId(g, newvd) << ").");
00673 PerformanceLogger<G> edge_builder_pl(g, newvd, "edge_builder");
00674
00675 std::vector<cv::DMatch> global_dmatches_con_new,dmatches_con_new_0;
00676 SE3 T_con_new;
00677
00678
00679 vector<int> gm_convd_keep_idx, gm_newvd_keep_idx;
00680 vector<cv::KeyPoint> gm_convd_keypoints, gm_newvd_keypoints;
00681 cv::Mat gm_newvd_descriptors, gm_convd_descriptors;
00682 {
00683 PerformanceLogger<G> pl(g, newvd, "feature_selection");
00684 EdgeBuilder<G>::featureSelection(
00685 g, convd, 700, gm_convd_keep_idx, gm_convd_keypoints, gm_convd_descriptors);
00686 EdgeBuilder<G>::featureSelection(
00687 g, newvd, 700, gm_newvd_keep_idx, gm_newvd_keypoints, gm_newvd_descriptors);
00688 }
00689
00690
00691 {
00692 PerformanceLogger<G> edge_builder_pl(g, newvd, "global_matching");
00693 if(!unguidedMatching(gm_convd_keypoints, gm_newvd_keypoints,
00694 gm_convd_descriptors, gm_newvd_descriptors, T_con_new, global_dmatches_con_new)){
00695 return false;
00696 }
00697 }
00698 {
00699 bool status;
00700 status=add_edge(newvd, convd, g).second;
00701 status=status && add_edge(convd, newvd, g).second;
00702 assert(status);
00703 }
00704 setEdgeTransform(T_con_new, convd, newvd, g);
00705 dmatches_con_new_0=remapDMatchIdxs(global_dmatches_con_new, gm_convd_keep_idx, gm_newvd_keep_idx);
00706 std::for_each(dmatches_con_new_0.begin(), dmatches_con_new_0.end(), std::tr1::bind(
00707 add_idx_pair_from_dmatch<G>, std::tr1::placeholders::_1, convd, newvd, std::tr1::ref(g)));
00708
00709
00710 guidedMatching(g, newvd, convd);
00711
00713 if(minEdgeDisparityAngle(g, convd, newvd) < (M_PI/180.0)*1.5){
00714 ROS_WARN_NAMED("PoseGraph", "edge construction failed. Disparity too small.");
00715 ROS_WARN_STREAM_NAMED("PoseGraph", "disparity:" <<
00716 minEdgeDisparityAngle(g, convd, newvd) / M_PI * 180.0);
00717 remove_edge(newvd, convd, g);
00718 remove_edge(convd, newvd, g);
00719 return false;
00720 }
00721 ROS_WARN_STREAM_NAMED("PoseGraph", "disparity:" <<
00722 minEdgeDisparityAngle(g, convd, newvd) / M_PI * 180.0);
00723
00724
00725 SE3 scaled_T_vsrc_vdest = get(edge_transform, g, edge(convd, newvd, g).first);
00726 computeScale(convd, newvd, g, points, scaled_T_vsrc_vdest);
00727
00728
00729 {
00730 PerformanceLogger<G> pl(g, newvd, "lm_accounting");
00731 findNewLandmarks(convd, newvd, points, g);
00732
00733 extendLandmarks(convd, newvd, points, g);
00734 }
00735 ROS_INFO_STREAM_NAMED("PoseGraph", "Done constructing edge");
00736 return true;
00737 }
00738
00739
00740
00741 std::tr1::shared_ptr<RobustFeatureMatcher> constructRMatcher(
00742 std::tr1::shared_ptr<cv::DescriptorMatcher> _dmatcher,
00743 std::tr1::shared_ptr<EMatrixModelBuilder> _minbuilder,
00744 std::tr1::shared_ptr<EMatrixModelBuilder> _builder){
00745 return std::tr1::shared_ptr<RobustFeatureMatcher>(
00746 new RobustFeatureMatcher( _dmatcher, _minbuilder, _builder));
00747 }
00748
00749
00750
00755
00756
00757
00758
00759
00760
00761 }
00762 #endif