00001
00007 #ifndef VSLAM_UTILS_H_INCLUDED
00008 #define VSLAM_UTILS_H_INCLUDED
00009
00010 #define ROSCONSOLE_MIN_SEVERITY ROSCONSOLE_SEVERITY_DEBUG
00011
00012
00013 #define EIGEN_DONT_ALIGN
00014 #define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
00015
00016 #include <Eigen/Dense>
00017 #include <Eigen/StdVector>
00018 #include <vector>
00019 #include <list>
00020 #include <set>
00021 #include <assert.h>
00022 #include "ros/ros.h"
00023 #include <opencv2/core/core.hpp>
00024 #include <opencv2/imgproc/imgproc.hpp>
00025 #include <opencv2/highgui/highgui.hpp>
00026 #include <opencv2/features2d/features2d.hpp>
00027 #include <opencv2/calib3d/calib3d.hpp>
00028 #include <boost/tr1/memory.hpp>
00029 #include <boost/tr1/cmath.hpp>
00030 #include <iostream>
00031 #include <boost/foreach.hpp>
00032 #include <boost/random.hpp>
00033 #include <boost/filesystem.hpp>
00034 #include "Sophus/se3.h"
00035 #include "Sophus/so3.h"
00036
00037 #include "nav_msgs/Odometry.h"
00038
00040 extern boost::mt19937 rng_mt19937;
00041
00042 const double PI = std::atan(1.0)*4;
00043
00044 template <typename T1, typename T2 = T1>
00045 struct ALIGNED {
00046 typedef std::vector<T1, Eigen::aligned_allocator<T1> > vector;
00047 typedef std::list<T1, Eigen::aligned_allocator<T1> > list;
00048 typedef std::set<T1, Eigen::aligned_allocator<T1> > set;
00049 typedef std::map<T1, T2> map;
00050 };
00051
00052 typedef ALIGNED<Eigen::Vector3d>::vector Points3dSTL;
00053 typedef ALIGNED<Eigen::Vector2d>::vector Points2dSTL;
00054 typedef ALIGNED<std::pair<int, Eigen::Vector3d> >::vector IdxPoint3dVec;
00055 typedef ALIGNED<std::pair<int, Eigen::Vector2d> >::vector IdxPoint2dVec;
00056 typedef std::pair<Eigen::Vector3d, Eigen::Vector3d> ImageMatch;
00057 typedef ALIGNED<ImageMatch>::vector ImageMatchVec;
00058
00059 using Eigen::Vector2f;
00060 using Eigen::Vector2d; using Eigen::Vector3d; using Eigen::VectorXd;
00061 using Eigen::Matrix3d; using Eigen::Matrix4d; using Eigen::MatrixXd; using Eigen::Matrix;
00062 using std::tr1::shared_ptr;
00063 using std::cout; using std::cerr; using std::endl; using std::pair; using std::make_pair;
00064 using std::list; using std::map; using std::vector;
00065 using Sophus::SE3; using Sophus::SO3;
00066
00067
00068 namespace vslam{
00069 extern std::string image_mask_file;
00070 extern std::string image_sample_file;
00071 extern boost::filesystem::path debug_output_path;
00072 }
00073
00074 class PanoramaParams{
00075 public:
00076 static const int width = 1600;
00077 static const int height = 800;
00078 };
00079
00080
00081
00082
00083 template<class T> T linspace_idx(T first, T last, int count, T idx){
00084 if(idx > count - 1.0){
00085 T tmp = ((T)count - 1) + 0.0000001;
00086 idx = (idx / tmp - (T)std::tr1::round(idx / tmp)) * tmp;
00087 }
00088 return first + ((last-first) / (T)((T)count - 1)) * idx;
00089 }
00090
00091 template<class T> T inv_linspace_idx(T first, T last, int count, T val){
00092 return (val - first) / ((last-first) / (T)(count - 1));
00093 }
00094
00095 template<class Iterator> void printContainer(Iterator b, Iterator e, const char * separator){
00096 while(b!=e){
00097 cout << *b << separator;
00098 ++b;
00099 }
00100 }
00101
00105 template<class ImageParamsObj> class ImageCoordinate{
00106 private:
00107 bool initialized;
00108 double azimuth;
00109 double elevation;
00110
00111 public:
00112 typedef ImageParamsObj Params;
00113
00114 ImageCoordinate() : initialized(false) {}
00115
00116
00117
00118 static ImageCoordinate<ImageParamsObj> fromPixel(Eigen::Vector2d pixel){
00119 ImageCoordinate<ImageParamsObj> obj;
00120 obj.azimuth = linspace_idx(
00121 (double)0,
00122 (double)(ImageParamsObj::width - 1) / (double)ImageParamsObj::width * (-2.0)*M_PI,
00123 ImageParamsObj::width,
00124 pixel(0) - (double)(((int)ImageParamsObj::width) / 2));
00125 obj.elevation = -linspace_idx(-M_PI / 2.0, M_PI / 2.0, ImageParamsObj::height, pixel(1));
00126 obj.initialized = true;
00127 return obj;
00128 }
00129
00130
00131 static ImageCoordinate<ImageParamsObj> fromSpherical(Eigen::Vector2d spherical){
00132 ImageCoordinate<ImageParamsObj> obj;
00133 obj.azimuth = spherical(0);
00134 obj.elevation = spherical(1);
00135 obj.initialized = true;
00136 return obj;
00137 }
00138
00139 static ImageCoordinate<ImageParamsObj> fromHomogenous(Eigen::Vector3d homogenous){
00140 ImageCoordinate<ImageParamsObj> obj;
00141 homogenous.normalize();
00142 double x = homogenous(0);
00143 double y = homogenous(1);
00144 double z = homogenous(2);
00145
00146 double r_xz = std::sqrt(x*x + z*z);
00147 obj.azimuth = std::atan2(-x, z);
00148 obj.elevation = std::atan2(y, r_xz);
00149 obj.initialized = true;
00150 return obj;
00151 }
00152
00153 Eigen::Vector2d getPixel() const{
00154 assert(initialized);
00155 Eigen::Vector2d t;
00156 t(0) = inv_linspace_idx(
00157 (double)0,
00158 (double)(ImageParamsObj::width - 1) / (double)ImageParamsObj::width * (-2.0)*M_PI,
00159 ImageParamsObj::width,
00160 azimuth) + (double)(((int)ImageParamsObj::width) / 2);
00161 t(1) = inv_linspace_idx(-M_PI / 2.0, M_PI / 2.0, ImageParamsObj::height, -elevation);
00162 return t;
00163 }
00164
00165 Eigen::Vector2d getSpherical() const{
00166 assert(initialized);
00167 return Eigen::Vector2d(azimuth, elevation);
00168 }
00169
00170 Eigen::Vector3d getHomogenous() const{
00171 assert(initialized);
00172 Eigen::Vector3d direction;
00173 direction(0) = -std::sin( azimuth ) * std::cos( elevation );
00174 direction(1) = std::sin( elevation );
00175 direction(2) = std::cos( azimuth ) * std::cos( elevation );
00176 return direction;
00177 }
00178
00179 void print(){
00180 {
00181 Vector2d c = getPixel();
00182 cout << "pixel coordinates: " << "x: " << c(0) << "y: " << c(1) << endl;
00183 }
00184 cout << "spherical coordinates: " <<
00185 "azimuth/PI: " << azimuth / M_PI << "elevation/PI: " << elevation / M_PI << endl;
00186 {
00187 Vector3d c = getHomogenous();
00188 cout << "homogenous coordinates: " <<
00189 "x: " << c(0) << "y: " << c(1) << "z: " << c(2) << endl;
00190 }
00191 }
00192 };
00193
00194 typedef ImageCoordinate<PanoramaParams> PanoImCoord;
00195 typedef vector<PanoImCoord> ImageCoordinateVec;
00196
00197
00198 inline Vector2d homogenousToPixel(const Vector3d & hom){
00199 return PanoImCoord::fromHomogenous(hom).getPixel();
00200 }
00201
00202
00204 template<typename T> class Maybe {
00205 T * obj;
00206
00207 Maybe(){
00208 obj = 0;
00209 }
00210 public:
00211
00212 const static Maybe<T> no;
00213 static Maybe<T> yes(const T & _obj){
00214 Maybe m;
00215 m.obj=new T(_obj);
00216 return m;
00217 }
00218
00219 T & value() const{
00220 assert(obj != NULL);
00221 return *obj;
00222 }
00223
00224 operator bool(){
00225 return obj != NULL;
00226 }
00227
00228 bool operator==(const Maybe<T> & _obj) const{
00229 if(obj && _obj){
00230 return *obj == *(_obj.obj);
00231 } else{
00232 return false;
00233 }
00234 }
00235
00236 bool operator!=(const Maybe<T> & _obj) const{
00237 return !(*this == _obj);
00238 }
00239
00240 Maybe(const Maybe<T> & _obj){
00241 if(_obj == Maybe<T>::no){
00242 obj = 0;
00243 } else{
00244 obj = new T(_obj.value());
00245 }
00246 }
00247 };
00248
00250
00251 inline ImageMatch computeMatch(const Vector2d& px_c1, const Vector2d& px_c2){
00252 PanoImCoord c1 = PanoImCoord::fromPixel(px_c1);
00253 PanoImCoord c2 = PanoImCoord::fromPixel(px_c2);
00254 return ImageMatch(c1.getHomogenous(), c2.getHomogenous());
00255 }
00256
00257
00258 template<class T> cv::Point cvPointFromVector2(Eigen::Matrix<T, 2, 1> vec){
00259 return cv::Point(vec(0), vec(1));
00260 }
00261
00262
00263
00264 ImageMatchVec imageMatchCoords(const vector<cv::KeyPoint> & tkpts, const vector<cv::KeyPoint> & qkpts,
00265 const std::vector<cv::DMatch> &matches);
00266
00267 typedef Eigen::Matrix<double, 3, Eigen::Dynamic> PointMatrix;
00268
00269 void points3dSTLToPointMatrix(const Points3dSTL & pts, PointMatrix & ptmat);
00270
00271 ImageMatchVec buildImageMatchesFrom3dPoints(
00272 const SE3 & T_wc1, const SE3 & T_wc2, const Points3dSTL & points);
00273
00274 Points3dSTL projectPoints(SE3 T_sd, const Points3dSTL & points);
00275
00276
00278 void generateRandomScene(
00279 const Vector3d & upper_left_deep,
00280 const Vector3d & bottom_right_shallow,
00281 double target_num_vec,
00282 Points3dSTL & points);
00283
00285 void generateRandomTrajectory(
00286 const Vector3d & upper_left_deep,
00287 const Vector3d & bottom_right_shallow,
00288 int num_stops,
00289 ALIGNED<SE3>::vector & transforms);
00290
00292 inline void generateLineTrajectory(
00293 const Vector3d & start,
00294 const Vector3d & end,
00295 int num_stops,
00296 ALIGNED<SE3>::vector & transforms){
00297 Points3dSTL poses;
00298 Points3dSTL orientations;
00299 Vector3d normalized_direction = (end-start).normalized();
00300 double track_len = (end-start).norm();
00301 double segment_len = track_len / (double) (num_stops - 1);
00302 Vector3d tmp=start;
00303 for(int i=0; i<num_stops; i++){
00304 transforms.push_back(SE3(SO3(0, 0, 0), -tmp));
00305 tmp = (tmp + normalized_direction * segment_len).eval();
00306 }
00307 }
00308
00309
00310 template< class T> class SingleVariableWrapper{
00311 protected:
00312 T value_var;
00313 public:
00314 T val() const { return value_var; };
00315 };
00316
00317 class SpeedAsNaturalNumber : public SingleVariableWrapper<int>{
00318 public:
00319 SpeedAsNaturalNumber(int speed){
00320 value_var = speed;
00321 assert(speed >=0);
00322 }
00323 };
00324
00325 class TimeAsNaturalNumber : public SingleVariableWrapper<int>{
00326 public:
00327 TimeAsNaturalNumber(int time){
00328 value_var=time;
00329 assert(time >=0);
00330 }
00331 };
00332
00333 struct SpeedSegment{
00334 SE3 T_c1c2;
00335 SpeedAsNaturalNumber speed_mul;
00336 TimeAsNaturalNumber time_mul;
00337
00338 SpeedSegment(const SE3& _T_c1c2, SpeedAsNaturalNumber _speed_mul, TimeAsNaturalNumber _time_mul) :
00339 T_c1c2(_T_c1c2), speed_mul(_speed_mul), time_mul(_time_mul) {}
00340 };
00341
00342 inline void constructTrajectoryFromSpeedSegments(
00343 std::vector<SpeedSegment> speed_segments,
00344 ALIGNED<SE3>::vector& transforms){
00345 transforms.push_back(SE3());
00346 SE3 prevT_wc = SE3();
00347 BOOST_FOREACH(SpeedSegment segment, speed_segments){
00348 SE3 T_c1ct = SE3();
00349 for(int i=0; i < segment.speed_mul.val(); i++){
00350 T_c1ct = T_c1ct * (T_c1ct.inverse() * segment.T_c1c2 * T_c1ct);
00351 }
00352 for(int i=0; i < segment.time_mul.val(); i++){
00353 SE3 T_wc = prevT_wc * (prevT_wc.inverse() * T_c1ct * prevT_wc);
00354 transforms.push_back(T_wc);
00355 prevT_wc = T_wc;
00356 }
00357 }
00358 }
00359
00360 bool isApprox(double num, double target_num, double error);
00361
00362
00364 inline std::string seqencedName(int seq, std::string name){
00365 std::ostringstream s;
00366 s << seq << "_" << name;
00367 return s.str();
00368 }
00369
00370 inline Vector3d coordFrameConventionLocalToROS(const Vector3d& vec){
00371 return Vector3d(vec(2), -vec(0), vec(1));
00372
00373 }
00374
00375 inline SE3 coordFrameConventionLocalToROS(const SE3& T){
00376
00377 Eigen::Matrix4d C = Eigen::Matrix4d::Zero();
00378 C(0,2)=1; C(1,0)=-1; C(2,1)=1; C(3,3)=1;
00379 Eigen::Matrix4d M = C * T.matrix() * C.inverse();
00380 return SE3(M.block(0,0,3,3), M.block(0,3,3,1));
00381
00382 }
00383
00384
00385
00386
00387 template<class T> struct EigenAllocTraits{
00388 typedef std::allocator<T> alloc;
00389 };
00390
00391 template<> struct EigenAllocTraits<Vector3d>{
00392 typedef Eigen::aligned_allocator<Vector3d> alloc;
00393 };
00394
00395
00396
00397
00398
00400 template<class T1, class T2> T1 getFirst(const pair<T1, T2>& pair){
00401 return pair.first;
00402 }
00403
00405 template<class T1, class T2> T2 getSecond(const pair<T1, T2>& pair){
00406 return pair.second;
00407 }
00408
00409
00417 template< class TR, template<class, class> class C, template<class> class A, class T>
00418 C<TR, typename EigenAllocTraits<TR>::alloc >
00419 transformF(const C<T, A<T> > & container, TR (*f)(const T&)){
00420 C<TR, typename EigenAllocTraits<TR>::alloc > result;
00421 std::transform(container.begin(), container.end(), std::back_inserter(result), f);
00422 return result;
00423 }
00424
00425
00432 template<class C1, class C2> C1 getCommon(const C1 & idx1, const C2 & idx2){
00433 C1 result;
00434 typename C1::const_iterator i1 = idx1.begin();
00435 typename C2::const_iterator i2 = idx2.begin();
00436 while(i1 != idx1.end() && i2 != idx2.end()){
00437 if(*i2 < *i1) { ++i2; continue; }
00438 if(*i1 < *i2) { ++i1; continue; }
00439 result.push_back(*i1);
00440 ++i1; ++i2;
00441 }
00442 return result;
00443 }
00444
00445
00447 template<template<class, class> class C1, template<class, class> class C2,
00448 template<class> class Alloc1, template<class> class Alloc2, class TK, class TV>
00449 list<pair<TK, TV>, Alloc2<pair<TK, TV> > >
00450 indexBy(const C1<TK, Alloc1<TK> >& idx, const C2<TV, Alloc2<TV> >& points){
00451 list<pair<TK, TV>, Alloc2<pair<TK, TV> > > result;
00452 std::transform(idx.begin(), idx.end(), points.begin(), back_inserter(result),
00453 std::make_pair<TK, TV>);
00454 return result;
00455 }
00456
00457
00464 template<template<class, class> class C1, template<class, class> class C2,
00465 class T1, class T2, template<class> class A1, template<class> class A2>
00466 C1<pair<T1, T2>, A1<pair<T1, T2> > >
00467 getByIdx(const C1<pair<T1, T2>, A1<pair<T1, T2> > > & pts, const C2<T1, A2<T1> >& idx){
00468 typedef C1<pair<T1, T2>, A1<pair<T1, T2> > > C1I;
00469 C1I result;
00470 typename C1I::const_iterator pi = pts.begin();
00471 BOOST_FOREACH(T1 i, idx){
00472 while(i != pi->first) ++pi;
00473 result.push_back(*pi);
00474 }
00475 return result;
00476 }
00477
00478
00480 template<template<class, class, class, class> class M, class V, class K, class Cmp,
00481 template<class> class Alloc>
00482 list<pair<K, V>, Alloc<pair<K, V> > > mapToList(const M<K, V, Cmp, Alloc<pair< const K, V> > >& map){
00483 list<pair<K, V>, Alloc<pair<K, V> > > result(map.begin(), map.end());
00484 return result;
00485 }
00486
00487
00489 template<template<class, class> class CT, template<class, class> class CS, class T,
00490 template<class> class Alloc>
00491 CT<T, Alloc<T> > switchCont(const CS<T, Alloc<T> > & container){
00492 return CT<T, Alloc<T> >(container.begin(), container.end());
00493 }
00494
00495
00497 inline Matrix3d sE3ToE(const SE3 & T){
00498 return (SO3::hat(T.translation()) * T.rotation_matrix()).eval();
00499 }
00500
00501
00502
00504 template<class T> list<T> makeSeq(T first, T last, T step){
00505 list<T> result;
00506 for(T i = first; i <= last; i += step){
00507 result.push_back(i);
00508 }
00509 return result;
00510 }
00511
00512 template<class T> bool truePred(const T& t){ return true; }
00513
00515 template<template<class,class> class C1, template<class, class> class C2, class T, class A>
00516 list<T> inverse_idxs(const C1<T, A>& idx, const C2<T, A>& all_idx){
00517 typename C1<T, A>::const_iterator it = idx.begin();
00518 typename C2<T, A>::const_iterator it_all = all_idx.begin();
00519 list<T> inv_idx;
00520 while(it_all != all_idx.end()){
00521 if(*it_all != *it) inv_idx.push_back(*it_all);
00522 else ++it;
00523 ++it_all;
00524 }
00525 return inv_idx;
00526 }
00527
00528
00529 template<template<class,class> class C, class T>
00530 C<T, std::allocator<T> > mkOneValueCont(const T& value){
00531 C<T, std::allocator<T> > container;
00532 std::back_insert_iterator<C<T, std::allocator<T> > > it = back_inserter(container);
00533 it = value;
00534 return container;
00535 }
00536
00537 template<template<class,class> class C, class T>
00538 C<T, Eigen::aligned_allocator<T> > mkOneValueContAA(const T& value){
00539 C<T, Eigen::aligned_allocator<T> > container;
00540
00541
00542 container.push_back(value);
00543 return container;
00544 }
00545
00546 inline geometry_msgs::Pose getPoseFromTcwInSE3(const SE3& T_cw){
00547 geometry_msgs::Pose pose;
00548
00549 Vector3d t = T_cw.translation();
00550 geometry_msgs::Point point;
00551 point.x=t(0);
00552 point.y=t(1);
00553 point.z=t(2);
00554 pose.position = point;
00555
00556 geometry_msgs::Quaternion quat;
00557 Eigen::Quaterniond q = T_cw.unit_quaternion();
00558 quat.x=q.x();
00559 quat.y=q.y();
00560 quat.z=q.z();
00561 quat.w=q.w();
00562 pose.orientation = quat;
00563
00564 return pose;
00565 }
00566
00567
00568
00570 template<class T> vector<T> getArrayIdices(const vector<T>& array, const vector<int>& idxs){
00571 typename vector<int>::const_iterator it = idxs.begin();
00572 vector<T> result;
00573 while(it!=idxs.end()){
00574 result.push_back(array[*it]);
00575 ++it;
00576 }
00577 return result;
00578 }
00579
00581 template<class T> cv::Mat getArrayIdices(const cv::Mat& mat, const vector<int>& idxs){
00582 cv::Mat result(0, mat.size().width, mat.type());
00583 result.reserve(idxs.size());
00584 typename vector<int>::const_iterator it = idxs.begin();
00585 while(it!=idxs.end()){
00586 result.push_back(mat.row(*it));
00587 ++it;
00588 }
00589 return result;
00590 }
00591
00592
00593
00594 template<template<class T, class = std::allocator<T> > class C, class T> C<T>
00595 mkContainer(const T& val){
00596 C<T> container;
00597 container.push_back(val);
00598 return container;
00599 }
00600
00601 inline Vector2d c1PixelToc2Pixel(const SE3& T_c1c2, const Vector2d& pixel1){
00602 Vector3d v = T_c1c2 * PanoImCoord::fromPixel(pixel1).getHomogenous();
00603 return PanoImCoord::fromHomogenous(v).getPixel();
00604 }
00605
00606
00607
00608
00609
00610
00611 #endif