00001
00005 #ifndef VSLAM_GRAPH_UTILS_H_INCLUDED
00006 #define VSLAM_GRAPH_UTILS_H_INCLUDED
00007 #include "utils.h"
00008 #include "pose_graph.h"
00009
00010 namespace vslam{
00013
00020
00028
00029
00030 template<class G> int getFeatureIdx(const G& g, int source_idx,
00031 typename graph_traits<G>::vertex_descriptor source_vd,
00032 typename graph_traits<G>::vertex_descriptor target_vd){
00033 using namespace boost;
00034 assert(edge(source_vd, target_vd, g).second);
00035 typename graph_traits<G>::edge_descriptor ed = edge(source_vd, target_vd, g).first;
00036 map<int, int>::const_iterator it =
00037 get(edge_kp_idx_map, g, ed).find(source_idx);
00038 if(it != get(edge_kp_idx_map, g, ed).end()){
00039 return it->second;
00040 } else{
00041 return BAD_INDEX;
00042 }
00043 }
00044
00046 template<class G> int getFeatureIdx(const G& g, FeatureID<G> srcf,
00047 typename graph_traits<G>::vertex_descriptor target_vd){
00048 return getFeatureIdx(g, srcf.vidx, srcf.vd, target_vd);
00049 }
00050
00052 template<typename G> void remove_idx_pair(
00053 int sidx,
00054 typename graph_traits<G>::vertex_descriptor src,
00055 typename graph_traits<G>::vertex_descriptor dest,
00056 G& g){
00057 using namespace boost;
00058 typename property_map<G, edge_kp_idx_map_t>::type epmap = get(edge_kp_idx_map, g);
00059 int didx = epmap[edge(src, dest, g).first][sidx];
00060 epmap[edge(src, dest, g).first].erase(sidx);
00061 epmap[edge(dest, src, g).first].erase(didx);
00062 }
00063
00065 template<typename G> void add_idx_pair(
00066 int src_idx, int dest_idx,
00067 typename graph_traits<G>::vertex_descriptor src,
00068 typename graph_traits<G>::vertex_descriptor dest, G& g){
00069 using namespace boost;
00070 typename property_map<G, edge_kp_idx_map_t>::type epmap = get(edge_kp_idx_map, g);
00071 assert((size_t)dest_idx < get(vertex_kp, g, dest).size());
00072 assert((size_t)src_idx < get(vertex_kp, g, src).size());
00073 epmap[edge(src, dest, g).first][src_idx] = dest_idx;
00074 epmap[edge(dest, src, g).first][dest_idx] = src_idx;
00075 }
00076
00078 template<typename G> void add_idx_pair_from_dmatch(
00079 const cv::DMatch& dmatch,
00080 typename graph_traits<G>::vertex_descriptor tvd,
00081 typename graph_traits<G>::vertex_descriptor qvd,
00082 G& g){
00083 add_idx_pair(dmatch.trainIdx, dmatch.queryIdx, tvd, qvd, g);
00084 }
00085
00087 template<typename G> bool filter_index_pair_duplicates(
00088 const cv::DMatch& dmatch,
00089 typename graph_traits<G>::vertex_descriptor src,
00090 typename graph_traits<G>::vertex_descriptor dest, G& g){
00091 using namespace boost;
00092 bool add = (getFeatureIdx(g, dmatch.trainIdx, src, dest) == BAD_INDEX);
00093 add = add && (getFeatureIdx(g, dmatch.queryIdx, dest, src) == BAD_INDEX);
00094 return add;
00095 }
00096
00100 inline vector<cv::DMatch> remapDMatchIdxs(
00101 const vector<cv::DMatch>& dmatches, const vector<int>& tidx, const vector<int>& qidx){
00102 vector<cv::DMatch> result;
00103 result.reserve(dmatches.size());
00104 for(vector<cv::DMatch>::const_iterator it=dmatches.begin(); it!= dmatches.end(); ++it){
00105 cv::DMatch tmp = *it;
00106 tmp.trainIdx = tidx[it->trainIdx];
00107 tmp.queryIdx = qidx[it->queryIdx];
00108 result.push_back(tmp);
00109 }
00110 return result;
00111 }
00112
00113 inline cv::DMatch dmatchFromPair(const pair<int, int>& p){
00114 return cv::DMatch(p.first, p.second, 0.1);
00115 }
00116
00117 inline pair<int, int> pairFromDMatch(const cv::DMatch& dmatch){
00118 return make_pair(dmatch.trainIdx, dmatch.queryIdx);
00119 }
00120
00127 template<template<class, class> class CT, class G> CT<int, std::allocator<int> >
00128 common_feature_tracks(
00129 G&g,
00130 typename graph_traits<G>::vertex_descriptor vad,
00131 typename graph_traits<G>::vertex_descriptor vbd,
00132 typename graph_traits<G>::vertex_descriptor vcd){
00133 typename property_map<G, edge_kp_idx_map_t>::type ekpimap = get(edge_kp_idx_map, g);
00134 typedef typename graph_traits<G>::edge_descriptor EdgeD;
00135 EdgeD edba = edge(vbd, vad, g).first;
00136 EdgeD edbc = edge(vbd, vcd, g).first;
00137 CT<int, std::allocator<int> > common_b_idx = switchCont<CT>(getCommon(
00138 transformF<int>(mapToList(ekpimap[edba]), getFirst),
00139 transformF<int>(mapToList(ekpimap[edbc]), getFirst)));
00140 return common_b_idx;
00141 }
00143
00144
00145
00148
00149
00151 template<class G> ImageMatch computeMatch(const G&g, FeatureID<G> source, FeatureID<G> target){
00152 using namespace boost;
00153 typename property_map<G, vertex_kp_t>::const_type kp_pmap = get(vertex_kp, g);
00154 cv::KeyPoint kp;
00155 kp = kp_pmap[source.vd][source.vidx];
00156 PanoImCoord c1 = PanoImCoord::fromPixel(Vector2d(kp.pt.x, kp.pt.y));
00157 kp = kp_pmap[target.vd][target.vidx];
00158 PanoImCoord c2 = PanoImCoord::fromPixel(Vector2d(kp.pt.x, kp.pt.y));
00159 return ImageMatch(c1.getHomogenous(), c2.getHomogenous());
00160 }
00161
00162 template<class G> ImageMatch computeMatch(const G&g, int source_idx,
00163 typename graph_traits<G>::vertex_descriptor source_vd,
00164 typename graph_traits<G>::vertex_descriptor target_vd){
00165 using namespace boost;
00166 int target_idx = getFeatureIdx(g, source_idx, source_vd, target_vd);
00167 return computeMatch(g, FeatureID<G>(source_vd, source_idx), FeatureID<G>(target_vd, target_idx));
00168 }
00169
00170
00171
00172 template<typename G> ImageMatchVec computeMatches(
00173 typename graph_traits<G>::vertex_descriptor src,
00174 typename graph_traits<G>::vertex_descriptor dest,
00175 const G& g){
00176 using namespace boost;
00177 ImageMatchVec matches;
00178 typename property_map<G, vertex_kp_t>::const_type vkpmap = get(vertex_kp, g);
00179 for(vector<cv::KeyPoint>::size_type i=0; i<vkpmap[src].size(); i++){
00180 if(getFeatureIdx(g, i, src, dest)!=BAD_INDEX){
00181 matches.push_back(computeMatch(g, i, src, dest));
00182 }
00183 }
00184 return matches;
00185 }
00186
00188
00189
00190
00193
00195
00196 template<class PoseGraphT> SE3 getEdgeTransform(
00197 const PoseGraphT& g,
00198 typename graph_traits<PoseGraphT>::vertex_descriptor vd1,
00199 typename graph_traits<PoseGraphT>::vertex_descriptor vd2){
00200 return get(vertex_transform, g, vd2) * get(vertex_transform, g, vd1).inverse();
00201 }
00202
00204 template<class G> void setEdgeTransform(
00205 const SE3& T_tvd_qvd,
00206 typename graph_traits<G>::vertex_descriptor tvd,
00207 typename graph_traits<G>::vertex_descriptor qvd,
00208 G& g){
00209 get(edge_transform, g, edge(tvd, qvd, g).first) = T_tvd_qvd;
00210 get(edge_transform, g, edge(qvd, tvd, g).first) = T_tvd_qvd.inverse();
00211 get(vertex_transform, g, qvd) = T_tvd_qvd * get(vertex_transform, g, tvd);
00212 }
00214
00215
00216
00221
00222
00223 inline double vectorAngle(const Vector3d& vec1, const Vector3d& vec2){
00224 double d = (vec1.normalized() - vec2.normalized()).norm();
00225 double angle = asin(d/2.0) * 2.0;
00226 return angle;
00227 }
00228
00229 template<class PoseGraphT> double disparityAngle(
00230 const PoseGraphT& g, FeatureID<PoseGraphT> f1, FeatureID<PoseGraphT> f2){
00231 SE3 T_wv1 = get(vertex_transform, g, f1.vd);
00232 SE3 T_wv2 = get(vertex_transform, g, f2.vd);
00233 SE3 T_v1v2 = T_wv2 * T_wv1.inverse();
00234
00235 ImageMatch m = computeMatch(g, f1, f2);
00236 m.first = (T_v1v2.rotation_matrix() * m.first).eval();
00237 return vectorAngle(m.first, m.second);
00238 }
00239
00240
00241 template<class PoseGraphT> double minEdgeDisparityAngle(
00242 PoseGraphT& g,
00243 typename graph_traits<PoseGraphT>::vertex_descriptor srcv,
00244 typename graph_traits<PoseGraphT>::vertex_descriptor destv){
00245
00246 vector<double> disparity_angles;
00247 const map<int, int> & src_dst_map = get(edge_kp_idx_map, g, edge(srcv, destv, g).first);
00248
00249 for(map<int, int>::const_iterator it=src_dst_map.begin(); it!=src_dst_map.end(); ++ it){
00250 double angle =disparityAngle(g, FeatureID<PoseGraphT>(srcv, it->first),
00251 FeatureID<PoseGraphT>(destv, it->second));
00252 disparity_angles.push_back(angle);
00253 }
00254 std::sort(disparity_angles.begin(), disparity_angles.end());
00255 return disparity_angles[disparity_angles.size() - disparity_angles.size() / 10];
00256 }
00258
00259
00260
00263
00269 template<class G> Vector3d triangulatePointWrtWorld(const G& g, FeatureID<G> f1, FeatureID<G> f2){
00270 SE3 T_v1v2 = getEdgeTransform(g, f1.vd, f2.vd);
00271 ImageMatchVec matches;
00272 matches.push_back(computeMatch(g, f1, f2));
00273 Points3dSTL tr_pts;
00274 computeStructure(T_v1v2, matches, tr_pts);
00275 return get(vertex_transform, g, f1.vd).inverse() * tr_pts[0];
00276 }
00277
00278 template<class G> Vector3d triangulatePointWrtWorldPos(const G& g, FeatureID<G> f1, FeatureID<G> f2){
00279 SE3 T_v1v2 = getEdgeTransform(g, f1.vd, f2.vd);
00280 ImageMatchVec matches;
00281 matches.push_back(computeMatch(g, f1, f2));
00282 Points3dSTL tr_pts;
00283 computeStructureForcePositiveDepths(T_v1v2, matches, tr_pts);
00284 return get(vertex_transform, g, f1.vd).inverse() * tr_pts[0];
00285 }
00286
00287 inline bool isEstimateInFrontOfCamera(const LandmarkObservation& obs, const Vector3d& estimate){
00288 double angle = vectorAngle(
00289 obs.T_cw.inverse() * estimate, PanoImCoord::fromPixel(obs.pixel).getHomogenous());
00290
00291 if(angle < 0.5 * M_PI) return true;
00292 else return false;
00293 }
00295
00296
00297
00298 template<class G> void landmarkObservationsBySize(
00299 const G& g,
00300 Points<G>& points,
00301 typename graph_traits<G>::vertex_descriptor vd,
00302 vector<vector<int> > & all_result,
00303 vector<vector<int> > & kf_result){
00304 const vector<cv::KeyPoint> & keypoints = get(vertex_kp, g, vd);
00305 const vector<int> & fix_map = get(vertex_fix_idx, g, vd);
00306
00307 int maxlen=8;
00308 all_result.assign(maxlen+1, vector<int>());
00309 kf_result.assign(maxlen+1, vector<int>());
00310
00311 for(int kp_idx=0; kp_idx< (int)keypoints.size(); kp_idx++){
00312 if(fix_map[kp_idx]!=BAD_INDEX && points.getPoint(fix_map[kp_idx]).initialized){
00313 int sz = points.getPoint(fix_map[kp_idx]).seen_from.size();
00314 for(sz=std::min(sz, maxlen); sz>0; sz--){
00315 all_result[sz].push_back(fix_map[kp_idx]);
00316 }
00317 int count=0;
00318 typedef pair<typename Point<G>::VertexD, int> T;
00319 BOOST_FOREACH(T fc, points.getPoint(fix_map[kp_idx]).seen_from){
00320 if(get(boost::vertex_keyframe_flag, g, fc.first)){
00321 count++;
00322 }
00323 }
00324 for(count=std::min(count, maxlen); count>0; count--){
00325 kf_result[count].push_back(fix_map[kp_idx]);
00326 }
00327 }
00328 }
00329 }
00330
00331
00333 template<class G> Vector2d getFeaturePixel(const G& g, const FeatureID<G> f){
00334 cv::KeyPoint kp = get(vertex_kp, g, f.vd)[f.vidx];
00335 return Vector2d(kp.pt.x, kp.pt.y);
00336 }
00337
00338 template<class G>
00339 double maxFeatureDistance(const G& g, const Points<G>& points, typename Point<G>::VertexD v){
00340 const vector<int>& fix_idxs = get(vertex_fix_idx, g, v);
00341 double max=0;
00342 for(size_t idx1=0; idx1 < fix_idxs.size(); idx1++){
00343 for(size_t idx2=0; idx2 < fix_idxs.size(); idx2++){
00344 if(fix_idxs[idx1]!=BAD_INDEX && fix_idxs[idx2]!=BAD_INDEX){
00345 if(points.getPoint(fix_idxs[idx1]).initialized && points.getPoint(idx2).initialized){
00346 double val = (getFeaturePixel(g, FeatureID<G>(v, idx1)) -
00347 getFeaturePixel(g, FeatureID<G>(v, idx2))).norm();
00348 if(val > max){
00349 max=val;
00350 }
00351 }
00352 }
00353 }
00354 }
00355 return max;
00356 }
00357
00359 template<class G> std::string printVertexId(
00360 const G& g, typename graph_traits<G>::vertex_descriptor vd){
00361 std::ostringstream oss;
00362 oss << get(vertex_seq, g, vd);
00363 return oss.str();
00364 }
00365
00366
00367
00368
00370
00372
00373 }
00374
00375
00376
00377 #endif