sfm_utils.cpp
Go to the documentation of this file.
00001 //part of the source code of master thesis, source code produced by Jiri Divis
00008 #include "sfm_utils.h"
00009 
00010 using std::vector;
00011 using Sophus::SE3; using Sophus::SO3;
00012 using Eigen::Vector3d; using Eigen::VectorXd; using Eigen::Matrix3d; using Eigen::MatrixXd;
00013 
00014 
00015 
00016 //solves for depth multipliers of matches in coordinate frame c1 for given image transform.
00017 /*void computeStructure0( const SE3 & T_c1c2, const ImageMatchVec & matches_c1c2,
00018         VectorXd & depths_c1){
00019     int n = matches_c1c2.size();
00020     assert(n >= 1);
00021     MatrixXd A = MatrixXd::Zero(3*n, n);
00022     VectorXd b = MatrixXd::Zero(3*n, 1);
00023     for(int i = 0 ; i < n; i++){
00024         Vector3d m;
00025         m = matches_c1c2[i].second.cross(T_c1c2.rotation_matrix() * matches_c1c2[i].first);
00026         A.block(i*3, i, 3, 1) = m;
00027         b.segment(i*3, 3) = -matches_c1c2[i].second.cross(T_c1c2.translation());
00028     }
00029     depths_c1 = A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
00030 }
00031 
00032 
00033 //solves for depth multipliers of matches in coordinate frame c1 for given image transform.
00034 //sparse matrix version
00035 void computeStructure0( const SE3 & T_c1c2, const ImageMatchVec & matches_c1c2,
00036         VectorXd & depths_c1){
00037     int n = matches_c1c2.size();
00038     assert(n >= 1);
00039     MatrixXd A = MatrixXd::Zero(3*n, n);
00040     VectorXd b = MatrixXd::Zero(3*n, 1);
00041     for(int i = 0 ; i < n; i++){
00042         Vector3d m;
00043         m = matches_c1c2[i].second.cross(T_c1c2.rotation_matrix() * matches_c1c2[i].first);
00044         A.block(i*3, i, 3, 1) = m;
00045         b.segment(i*3, 3) = -matches_c1c2[i].second.cross(T_c1c2.translation());
00046     }
00047     depths_c1 = A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
00048 }
00049 */
00050 //solves for depth multipliers of matches in coordinate frame c1 for given image transform.
00051 //version where individual features are done separately
00052 void computeStructure0( const SE3 & T_c1c2, const ImageMatchVec & matches_c1c2,
00053         VectorXd & depths_c1){
00054     int n = matches_c1c2.size();
00055     assert(n >= 1);
00056     depths_c1 = VectorXd::Zero(n);
00057     for(int i = 0 ; i < n; i++){
00058         Vector3d A;
00059         Vector3d b;
00060         A = matches_c1c2[i].second.cross(T_c1c2.rotation_matrix() * matches_c1c2[i].first);
00061         b = -matches_c1c2[i].second.cross(T_c1c2.translation());
00062         Eigen::Matrix<double, 1, 1> tmp = 
00063                 A.jacobiSvd(Eigen::ComputeFullU | Eigen::ComputeFullV).solve(b);
00064         depths_c1(i) = tmp(0,0);
00065     }
00066 }
00067 
00068 
00069 void computeStructure0ForcePositiveDepths( const SE3 & T_c1c2, const ImageMatchVec & matches_c1c2,
00070         VectorXd & depths_c1){
00071     computeStructure0(T_c1c2, matches_c1c2, depths_c1);
00072     int n = matches_c1c2.size();
00073     for(int i = 0 ; i < n; i++){
00074         if(depths_c1(i) < 0.0) depths_c1(i) = - depths_c1(i);
00075     }
00076 }
00077 
00078 
00079 //solves for depth. Outputs 3d points wrt. to c1 frame.
00080 void computeStructure(
00081         const SE3 & T_c1c2,
00082         const ImageMatchVec & matches_c1c2,
00083         Points3dSTL & triangulated_points_c1){
00084     VectorXd lambda_1;
00085     computeStructure0(T_c1c2, matches_c1c2, lambda_1);
00086     triangulated_points_c1.clear();
00087     for(unsigned int i=0 ; i < matches_c1c2.size(); i++){
00088         triangulated_points_c1.push_back(matches_c1c2[i].first * lambda_1(i));
00089     }
00090 }
00091 
00092 //solves for depth. Outputs 3d points wrt. to c1 frame.
00093 void computeStructureForcePositiveDepths(
00094         const SE3 & T_c1c2,
00095         const ImageMatchVec & matches_c1c2,
00096         Points3dSTL & triangulated_points_c1){
00097     VectorXd lambda_1;
00098     computeStructure0ForcePositiveDepths(T_c1c2, matches_c1c2, lambda_1);
00099     triangulated_points_c1.clear();
00100     for(unsigned int i=0 ; i < matches_c1c2.size(); i++){
00101         triangulated_points_c1.push_back(matches_c1c2[i].first * lambda_1(i));
00102     }
00103 }
00104 
00105 void computeStructure(
00106         const Sophus::SE3 & T_c1c2, const ImageMatch& match_c1c2, Vector3d & triangulated_point_c1){
00107     ImageMatchVec imv;
00108     imv.push_back(match_c1c2);
00109     Points3dSTL pv;
00110     computeStructure(T_c1c2, imv, pv);
00111     triangulated_point_c1=pv[0];
00112 }
00113 
00114 void computeStructureForcePositiveDepth(
00115         const Sophus::SE3 & T_c1c2, const ImageMatch& match_c1c2, Vector3d & triangulated_point_c1){
00116     ImageMatchVec imv;
00117     imv.push_back(match_c1c2);
00118     Points3dSTL pv;
00119     computeStructureForcePositiveDepths(T_c1c2, imv, pv);
00120     triangulated_point_c1=pv[0];
00121 }
00122 
00123 typedef ALIGNED<pair<int, Vector3d> >::vector IdxPoint3dVec;
00124 
00125 
00126 //solves for depth with T_c1c2 given up to a positive scale.
00127 void computeStructure(
00128         const SE3 & T_c1c2,
00129         const ImageMatchVec & matches_c1c2,
00130         const IdxPoint3dVec & idx_points3d_c1,
00131         Points3dSTL & points3d_c1,
00132         SE3 & scaled_T_c1c2){
00133     points3d_c1.clear();
00134     computeStructure(T_c1c2, matches_c1c2, points3d_c1);
00135     IdxPoint3dVec tmp=switchCont<vector>(getByIdx(
00136             indexBy( makeSeq(0, (int)matches_c1c2.size() - 1, 1), points3d_c1), 
00137             transformF<int>(idx_points3d_c1, getFirst)));
00138     double scale = computeScale(
00139             transformF<Vector3d>(idx_points3d_c1, getSecond), 
00140             transformF<Vector3d>(tmp, getSecond));
00141     scaled_T_c1c2 = SE3(T_c1c2.rotation_matrix(), T_c1c2.translation() * scale);
00142     for(unsigned int i=0 ; i < points3d_c1.size(); i++){
00143         points3d_c1[i] *= scale;
00144     }
00145 }
00146 
00147 void computeScale( const Points3dSTL& points1, const Points3dSTL& points2, 
00148         double& low, double& mid, double& hi){
00149     assert(points1.size() >= 3);
00150     assert(points1.size() == points2.size());
00151     vector<double> ratios;
00152     for(unsigned int i = 0; i < points1.size(); i++){
00153         ratios.push_back(points1[i].norm() / (points2[i]).norm());
00154     }
00155     std::sort(ratios.begin(), ratios.end());
00156     //for(int i=0; i<ratios.size(); i++) cout << ratios[i] << endl;
00157     int idx = ratios.size() / 2;
00158     low = ratios[idx-1];
00159     mid = ratios[idx];
00160     hi = ratios[idx+1];
00161     ROS_INFO_STREAM_NAMED("SFM:", "scale ratios around median (low, mid, hi):" << low << " " << mid << " " << hi);
00162 }
00163 
00164 double computeScale( const Points3dSTL& points1, const Points3dSTL& points2){
00165     double low, mid, hi;
00166     computeScale(points1, points2, low, mid, hi);
00167     return mid;
00168 }
00169 
00170 //extracts possible transforms from E up to a scale.
00171 ALIGNED<SE3>::vector extractRtFromE(const Matrix3d & E){
00172     Eigen::JacobiSVD<Eigen::Matrix3d> svd(E, Eigen::ComputeFullU | Eigen::ComputeFullV);
00173     Matrix3d U, V;
00174     U=svd.matrixU();
00175     V=svd.matrixV();
00176 
00177     //XXX a am not sure if i can do that...
00178     if(U.determinant() < 0) U = (-U).eval(); 
00179     if(V.determinant() < 0) V = (-V).eval();
00180     assert(isApprox(U.determinant(), 1.0, 0.0001));
00181     assert(isApprox(V.determinant(), 1.0, 0.0001));
00182     
00183     
00184     Matrix3d W = Matrix3d::Zero();
00185     W(0,1) = -1; W(1,0) = 1; W(2,2) = 1;
00186     Matrix3d Z = Matrix3d::Zero();
00187     Z(0,1) = 1; Z(1,0) = -1;
00188 
00189     Matrix3d R1 = U * W * V.transpose();
00190     Matrix3d R2 = U * W.transpose() * V.transpose();
00191 
00192     Matrix3d Sigma = Matrix3d::Zero(); Sigma(0,0) = 1; Sigma(1,1) = 1;
00193     Vector3d t = SO3::vee(U * Z * U.transpose());
00194 
00195     ALIGNED<SE3>::vector transforms;
00196     transforms.push_back(SE3(R1,t));
00197     transforms.push_back(SE3(R2,t));
00198     return transforms;
00199 }
00200 
00201 
00202 
00203 //extracts possible transforms from E and image matches used to compute E up to a positive scale.
00204 bool extractTransformFromE( const ImageMatchVec & image_matches, const Matrix3d & E, SE3 & res_tr){
00205     using std::tr1::signbit;
00206     ALIGNED<SE3>::vector transforms = extractRtFromE(E);
00207     BOOST_FOREACH(SE3 transform, transforms){ 
00208         bool assigned = true;
00209         VectorXd lambda_1;
00210         computeStructure0(transform, image_matches, lambda_1);
00211         if(lambda_1(0) < 0){
00212             res_tr = SE3(transform.rotation_matrix(), -transform.translation());
00213             lambda_1 = (-lambda_1).eval();
00214         } else{
00215             res_tr = transform;
00216         }
00217         for(Points3dSTL::size_type i=0; i < image_matches.size(); i++){
00218             if (lambda_1(i) < 0){
00219                 assigned=false;
00220                 break;
00221             }
00222             Vector3d a, b;
00223             a=res_tr * (image_matches[i].first * lambda_1(i));
00224             b=image_matches[i].second;
00225 
00226             for(int j=0; j<3; j++){
00227                 if(signbit(a(j)) != signbit(b(j))){
00228                     i=image_matches.size();
00229                     assigned=false;
00230                     break;
00231                 }
00232             }
00233         }
00234         if(assigned) return true;
00235     }
00236     return false;
00237 }
00238 
00239 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines


pose_estimation
Author(s): Jiri Divis/jiridivis@gmail.com
autogenerated on Wed Mar 27 2013 21:00:12