planarSFM.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2009, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 
00036 #include <cv.h>
00037 #include <iostream>
00038 #include <stdio.h>
00039 #include <limits>
00040 
00041 #include "posest/planarSFM.h"
00042 #include "sba/sba.h"
00043 
00044 using namespace cv;
00045 
00046 //#define DEBUG_CONSOLE
00047 
00048 namespace pe
00049 {
00050 
00051 struct HomographyDecomposition
00052 {
00053   HomographyDecomposition()
00054   {
00055     Rp = Mat::eye(3, 3, CV_32F);
00056     Tp = Mat(3, 1, CV_32F);
00057     Np = Mat(3, 1, CV_32F);
00058   };
00059 
00060   HomographyDecomposition(const HomographyDecomposition& h)
00061   {
00062     h.Rp.copyTo(Rp);
00063     h.Tp.copyTo(Tp);
00064     h.Np.copyTo(Np);
00065     h.R.copyTo(R);
00066     h.T.copyTo(T);
00067     dp = h.dp;
00068     score = h.score;
00069   };
00070 
00071   Mat Rp;
00072   Mat Tp;
00073   Mat Np;
00074   double dp;
00075 
00076   Mat R;
00077   Mat T;
00078 
00079   int score;
00080 };
00081 
00082 void dumpFltMat(const char* name, const Mat& mat)
00083 {
00084   printf("Dumping %s\n", name);
00085   for(int i = 0; i < mat.rows; i++)
00086   {
00087     for(int j = 0; j < mat.cols; j++)
00088     {
00089       printf("%f ", mat.at<float>(i, j));
00090     }
00091 
00092     printf("\n");
00093   }
00094 }
00095 
00096 void dumpDecomposition(const HomographyDecomposition& d)
00097 {
00098   printf("d = %f, score = %d\n", d.dp, d.score);
00099   dumpFltMat("R", d.R);
00100   dumpFltMat("T", d.T);
00101 }
00102 
00103 void dumpDecompositions(const vector<HomographyDecomposition>& decompositions)
00104 {
00105   for(size_t i = 0; i < decompositions.size(); i++)
00106   {
00107     printf("Decomposition %d:\n", (int)i);
00108     dumpDecomposition(decompositions[i]);
00109   }
00110 }
00111 
00112 void keyPoints2Point2f(const vector<KeyPoint>& src, vector<Point2f>& dst)
00113 {
00114   dst.resize(src.size());
00115   for(size_t i = 0; i < src.size(); i++)
00116   {
00117     dst[i] = src[i].pt;
00118   }
00119 }
00120 
00121 void matchesFromIndices(const vector<KeyPoint>& src1, const vector<KeyPoint>& src2, const vector<cv::DMatch>& indices,
00122                         vector<Point2f>& dst1, vector<Point2f>& dst2)
00123 {
00124   dst1.clear();
00125   dst2.clear();
00126   for(size_t i = 0; i < indices.size(); i++)
00127   {
00128     dst1.push_back(src1[indices[i].queryIdx].pt);
00129     dst2.push_back(src2[indices[i].trainIdx].pt);
00130   }
00131 }
00132 
00133 void matchesFromIndices(const vector<Point2f>& set1, const vector<Point2f>& set2, const vector<int>& indices,
00134                         vector<Point2f>& points1, vector<Point2f>& points2)
00135 {
00136   points1 = set1;
00137   vectorSubset(set2, indices, points2);
00138 }
00139 
00140 void matchesFromIndices(const vector<KeyPoint>& _set1, const vector<KeyPoint>& _set2, const vector<int>& indices,
00141                         vector<Point2f>& points1, vector<Point2f>& points2)
00142 {
00143   assert(_set1.size() == indices.size());
00144 
00145   vector<Point2f> set1, set2;
00146   keyPoints2Point2f(_set1, set1);
00147   keyPoints2Point2f(_set2, set2);
00148 
00149   matchesFromIndices(set1, set2, indices, points1, points2);
00150 }
00151 
00152 // Computes homography from its decomposition. Can be used for testing
00153 // decomposition integrity
00154 Mat homographyFromDecomposition(const HomographyDecomposition& decomposition)
00155 {
00156   Mat Rd = decomposition.R*decomposition.dp + decomposition.T*decomposition.Np.t();
00157   return Rd;
00158 }
00159 
00163 bool homographyDecompose(const Mat& intrinsics, const Mat& _H, vector<HomographyDecomposition>& hd)
00164 {
00165   hd.clear();
00166 
00167   // compensate for intrinsics
00168   Mat H = intrinsics.inv()*_H*intrinsics;
00169 
00170   cv::SVD svd(H);
00171   double d1 = fabs(svd.w.at<float>(0, 0));
00172   double d2 = fabs(svd.w.at<float>(1, 0));
00173   double d3 = fabs(svd.w.at<float>(2, 0));
00174 
00175   Mat u, v;
00176   svd.u.convertTo(u, CV_32F);
00177 
00178   Mat(svd.vt.t()).convertTo(v, CV_32F);
00179 
00180   double s = determinant(svd.u)*determinant(svd.vt.t());
00181 
00182   double dPrime_PM = d2;
00183 
00184   int nCase;
00185   if(d1 != d2 && d2 != d3)
00186     nCase = 1;
00187   else if( d1 == d2 && d2 == d3)
00188     nCase = 3;
00189   else
00190     nCase = 2;
00191 
00192   if(nCase != 1)
00193   {
00194     std::cout << "  Homographyinit: This motion case is not implemented or is degenerate. Try again. " << std::endl;
00195     return false;
00196   }
00197 
00198   double x1_PM;
00199   double x2;
00200   double x3_PM;
00201 
00202   // All below deals with the case = 1 case.
00203   // Case 1 implies (d1 != d3)
00204   { // Eq. 12
00205     x1_PM = sqrt((d1*d1 - d2*d2) / (d1*d1 - d3*d3));
00206     x2    = 0;
00207     x3_PM = sqrt((d2*d2 - d3*d3) / (d1*d1 - d3*d3));
00208   };
00209 
00210   double e1[4] = {1.0,-1.0,1.0,-1.0};
00211   double e3[4] = {1.0, 1.0, -1.0,-1.0};
00212 
00213   Mat Np(3, 1, CV_32F);
00214   HomographyDecomposition decomposition;
00215 
00216   // Case 1, d' > 0:
00217   decomposition.dp = s * dPrime_PM;
00218   for(int signs=0; signs<4; signs++)
00219   {
00220     // Eq 13
00221     decomposition.Rp = Mat::eye(3, 3, CV_32F);
00222     double dSinTheta = (d1 - d3) * x1_PM * x3_PM * e1[signs] * e3[signs] / d2;
00223     double dCosTheta = (d1 * x3_PM * x3_PM + d3 * x1_PM * x1_PM) / d2;
00224     decomposition.Rp.at<float>(0, 0) = dCosTheta;
00225     decomposition.Rp.at<float>(0, 2) = -dSinTheta;
00226     decomposition.Rp.at<float>(2, 0) = dSinTheta;
00227     decomposition.Rp.at<float>(2, 2) = dCosTheta;
00228 
00229     // Eq 14
00230     decomposition.Tp.at<float>(0, 0) = (d1 - d3) * x1_PM * e1[signs];
00231     decomposition.Tp.at<float>(1, 0) = 0.0;
00232     decomposition.Tp.at<float>(2, 0) = (d1 - d3) * -x3_PM * e3[signs];
00233 
00234     Np.at<float>(0, 0) = x1_PM * e1[signs];
00235     Np.at<float>(1, 0) = x2;
00236     Np.at<float>(2, 0) = x3_PM * e3[signs];
00237 
00238     decomposition.R = s * u * decomposition.Rp * v.t();
00239     decomposition.T = u * decomposition.Tp;
00240     decomposition.Np = v * Np;
00241 
00242 #if defined(DEBUG_CONSOLE)
00243     printf("Dumping decomposition %d\n", (int)hd.size());
00244     dumpDecomposition(decomposition);
00245     Mat L = decomposition.Rp*dPrime_PM + decomposition.Tp*Np.t();
00246     dumpFltMat("L", L);
00247 #endif //DEBUG_CONSOLE
00248 
00249     hd.push_back(decomposition);
00250   }
00251 
00252   // Case 1, d' < 0:
00253   decomposition.dp = s * -dPrime_PM;
00254   for(int signs=0; signs<4; signs++)
00255   {
00256     // Eq 15
00257     decomposition.Rp = -Mat(Mat::eye(3, 3, CV_32F));
00258     double dSinPhi = (d1 + d3) * x1_PM * x3_PM * e1[signs] * e3[signs] / d2;
00259     double dCosPhi = (d3 * x1_PM * x1_PM - d1 * x3_PM * x3_PM) / d2;
00260     decomposition.Rp.at<float>(0, 0) = dCosPhi;
00261     decomposition.Rp.at<float>(0, 2) = dSinPhi;
00262     decomposition.Rp.at<float>(2, 0) = dSinPhi;
00263     decomposition.Rp.at<float>(2, 2) = -dCosPhi;
00264 
00265     // Eq 16
00266     decomposition.Tp.at<float>(0, 0) = (d1 + d3) * x1_PM * e1[signs];
00267     decomposition.Tp.at<float>(1, 0) = 0.0;
00268     decomposition.Tp.at<float>(2, 0) = (d1 + d3) * x3_PM * e3[signs];
00269 
00270     Np.at<float>(0, 0) = x1_PM * e1[signs];
00271     Np.at<float>(1, 0) = x2;
00272     Np.at<float>(2, 0) = x3_PM * e3[signs];
00273 
00274     decomposition.R = s * u * decomposition.Rp * v.t();
00275     decomposition.T = u * decomposition.Tp;
00276     decomposition.Np = v * Np;
00277 
00278 #if defined(DEBUG_CONSOLE)
00279     printf("Dumping decomposition %d\n", (int)hd.size());
00280     dumpDecomposition(decomposition);
00281     Mat L = decomposition.Rp*dPrime_PM + decomposition.Tp*Np.t();
00282     dumpFltMat("L", L);
00283 #endif //DEBUG_CONSOLE
00284 
00285     hd.push_back(decomposition);
00286   }
00287 
00288   return true;
00289 }
00290 
00298 void computeHomographyInliers(const vector<Point2f>& src1, const vector<Point2f>& src2, const Mat& H,
00299                               vector<Point2f>& inliers1, vector<Point2f>& inliers2, float maxProjError = 2.0f)
00300 {
00301   vector<Point2f> src1_mapped;
00302   src1_mapped.resize(src1.size());
00303   Mat _src1_mapped(src1_mapped);
00304   perspectiveTransform(Mat(src1), _src1_mapped, H);
00305   for(size_t i = 0; i < src1.size(); i++)
00306   {
00307     float dist = norm(src2[i] - src1_mapped[i]);
00308     if(dist < maxProjError)
00309     {
00310       inliers1.push_back(src1[i]);
00311       inliers2.push_back(src2[i]);
00312     }
00313   }
00314 }
00315 
00320 static double SampsonusError(const Mat& essential, Point2f pl, Point2f pr)
00321 {
00322   Point3f Pl(pl.x, pl.y, 1.0f);
00323   Point3f Pr(pr.x, pr.y, 1.0f);
00324   Mat _Pl(1, 3, CV_32F, &Pl);
00325   Mat _Pr(3, 1, CV_32F, &Pr);
00326 
00327   //    float error = Mat(_Pl * essential * _Pr).at<float>(0, 0);
00328 
00329   Point3f fPr = *(Point3f*)Mat(essential * _Pr).ptr(0);
00330   Point3f fPl = *(Point3f*)Mat(essential.t() * _Pl.t()).ptr(0);
00331   float error = Pl.dot(fPr);
00332 
00333   Point2f fPrPlane(fPr.x, fPr.y);
00334   Point2f fPlPlane(fPl.x, fPl.y);
00335 
00336   return error*error/(fPrPlane.dot(fPrPlane) + fPlPlane.dot(fPlPlane));
00337 }
00338 
00340 void computeEpipolarInliers(const Mat& essential, const vector<Point2f>& points1, const vector<Point2f>& points2,
00341                             vector<bool>& inliers, double maxError)
00342 {
00343   assert(points1.size() == points2.size());
00344 
00345   inliers.resize(points1.size());
00346   const double maxErrorSquared = maxError*maxError;
00347   for(size_t i = 0; i < points1.size(); i++)
00348   {
00349     double error = SampsonusError(essential, points2[i], points1[i]);
00350     //        printf("i = %d, p1 = %f %f, p2 = %f %f, Epipolar error = %f\n", (int)i, points1[i].x, points1[i].y, points2[i].x, points2[i].y, error);
00351     if(error < maxErrorSquared)
00352     {
00353       inliers[i] = true;
00354     }
00355     else
00356     {
00357       inliers[i] = false;
00358     }
00359   }
00360 }
00361 
00362 
00363 void filterDecompositionsVisibility(vector<HomographyDecomposition>& decompositions, const Mat& H, const vector<Point2f>& inliers1, const vector<Point2f>& inliers2)
00364 {
00365   assert(decompositions.size() == 8);
00366 
00367   // First, filter out 4 solutions using a visibility constraint (First Eq from Prop.4)
00368   for(unsigned int i = 0; i < decompositions.size(); i++)
00369   {
00370     HomographyDecomposition &decomposition = decompositions[i];
00371     int nPositive = 0;
00372     for(unsigned int m=0; m<inliers1.size(); m++)
00373     {
00374       Point3f inlier(inliers1[m].x, inliers1[m].y, 1.0f);
00375       Mat _inlier(3, 1, CV_32F, &inlier);
00376       double dVisibilityTest = Mat(H*_inlier).at<float>(2, 0)/decomposition.dp;
00377 
00378       //            printf("inlier1: %f %f, inlier2: %f %f\n", inliers1[m].x, inliers1[m].y, inliers2[m].x, inliers2[m].y);
00379       //            printf("H*inlier1.z = %f\n", Mat(H*_inlier).at<float>(2, 0));
00380       if(dVisibilityTest > 0.0)
00381         nPositive++;
00382     };
00383     decomposition.score = -nPositive;
00384 
00385     //        printf("Decomposition %d: score %d\n", i, decomposition.score);
00386   }
00387 
00388   sort(decompositions.begin(), decompositions.end());
00389 
00390   // include at least 4 decompositions and filter out the rest with higher score
00391   size_t k;
00392   for(k = 3; k < decompositions.size(); k++)
00393   {
00394     if(decompositions[k].score > decompositions[3].score)
00395       break;
00396   }
00397   decompositions.resize(k);
00398 
00399 #if defined(DEBUG_CONSOLE)
00400   printf("\n\nDumping decompositions after step 1:\n");
00401   dumpDecompositions(decompositions);
00402 #endif //DEBUG_CONSOLE
00403 
00404   // Now filter out two more solutions using visibility constraint (second Eq from Prop 4)
00405   for(unsigned int i=0; i<decompositions.size(); i++)
00406   {
00407     HomographyDecomposition &decomposition = decompositions[i];
00408     int nPositive = 0;
00409     for(unsigned int m=0; m<inliers1.size(); m++)
00410     {
00411       Point3f inlier(inliers1[m].x, inliers1[m].y, 1);
00412       double dVisibilityTest = inlier.dot(*(Point3f*)decomposition.Np.ptr(0))/decomposition.dp;
00413       if(dVisibilityTest > 0.0)
00414         nPositive++;
00415     };
00416     decomposition.score = -nPositive;
00417   }
00418 
00419   sort(decompositions.begin(), decompositions.end());
00420 
00421 #if defined(DEBUG_CONSOLE)
00422   printf("\n\nDumping decompositions after step 2 before filtering:\n");
00423   dumpDecompositions(decompositions);
00424 #endif //DEBUG_CONSOLE
00425 
00426   // include at least 2 decompositions and filter out the rest with higher score
00427   for(k = 1; k < decompositions.size(); k++)
00428   {
00429     if(decompositions[k].score > decompositions[1].score)
00430       break;
00431   }
00432   decompositions.resize(k);
00433 
00434 #if defined(DEBUG_CONSOLE)
00435   printf("\n\nDumping decompositions after step 2 filtering:\n");
00436   dumpDecompositions(decompositions);
00437 #endif //DEBUG_CONSOLE
00438 
00439 }
00440 
00441 Mat calcEssentialMatrix(const Mat& intrinsics_inv, const Mat& R, const Mat& T)
00442 {
00443   Mat essential(3, 3, CV_32F);
00444 #if 0 // possible bug
00445   for(int j = 0; j < 3; j++)
00446   {
00447     Point3f R_row = *(Point3f*)R.ptr(j);
00448     Point3f t = *(Point3f*)T.ptr(0);
00449     *(Point3f*)essential.ptr(j) = crossProduct(R_row, t);
00450   }
00451 #else
00452 #if 0 // also not correct
00453   for(int j = 0; j < 3; j++)
00454   {
00455     Mat Rt = R.t();
00456     Point3f R_col = *(Point3f*)Rt.ptr(j);
00457     Point3f t = *(Point3f*)T.ptr(0);
00458     *(Point3f*)essential.ptr(j) = crossProduct(t, R_col);
00459   }
00460 
00461   essential = essential.t();
00462 #else
00463   Mat Rt = R.t();
00464   Mat Tx = Rt*T;
00465   for(int j = 0; j < 3; j++)
00466   {
00467     Point3f R_row = *(Point3f*)R.ptr(j);
00468     Point3f tx = *(Point3f*)Tx.ptr(0);
00469     *(Point3f*)essential.ptr(j) = crossProduct(R_row, tx);
00470   }
00471 #endif
00472 #endif
00473 
00474   essential = intrinsics_inv.t()*essential*intrinsics_inv;
00475   //    dumpFltMat("intrinsics @ essential matrix", intrinsics_inv);
00476   return essential;
00477 }
00478 
00479 double avgSampsonusError(const Mat& essential, const vector<Point2f>& points1, const vector<Point2f>& points2, double max_error, bool verbose)
00480 {
00481   assert(points1.size() == points2.size());
00482 
00483   double error_limit  = max_error*max_error*4;
00484   double sum_error = 0;
00485   for(unsigned int m = 0; m < points1.size(); m++ )
00486   {
00487     double d = SampsonusError(essential, points2[m], points1[m]);
00488     if(verbose)
00489     {
00490       printf("%d %f\n", m, d);
00491     }
00492     if(d > error_limit)
00493       d = error_limit;
00494     sum_error += d;
00495   }
00496 
00497   return sum_error/points1.size();
00498 }
00499 
00500 double filterDecompositionsZ(vector<HomographyDecomposition>& decompositions, const vector<Point2f>& points1, const vector<Point2f>& points2,
00501                              const Mat& intrinsics, const Mat& intrinsics_inv)
00502 {
00503   printf("Called filterDecompositionsZ\n");
00504   int max_idx = -1;
00505   int max_score = -1;
00506   for(size_t i = 0; i < decompositions.size(); i++)
00507   {
00508     vector<Point3f> cloud;
00509     vector<bool> valid;
00510     reprojectPoints(intrinsics, decompositions[i].R, decompositions[i].T, points1, points2, cloud, valid);
00511 
00512     const double reprojectionError = 1.0f;
00513     filterInliers(cloud, points1, points2, decompositions[i].R, decompositions[i].T, intrinsics, reprojectionError, valid);
00514 
00515     int score = 0;
00516     for(size_t j = 0; j < valid.size(); j++) score += int(valid[j]);
00517     printf("  decomposition %d: score = %d\n", (int)i, score);
00518     if(score > max_score)
00519     {
00520       max_score = score;
00521       max_idx = i;
00522     }
00523   }
00524 
00525   //  printf("decompositions size: %d, chosen %d with score %d\n", (int)decompositions.size(), max_idx, max_score);
00526   vector<HomographyDecomposition> filtered;
00527   filtered.push_back(decompositions[max_idx]);
00528   decompositions = filtered;
00529 
00530   Mat essential = calcEssentialMatrix(intrinsics_inv, decompositions[0].R, decompositions[0].T);
00531   double epipolar_error = avgSampsonusError(essential, points1, points2);
00532   return epipolar_error;
00533 }
00534 
00535 double filterDecompositionsEpipolar(const Mat& intrinsics, const Mat& intrinsics_inv, vector<HomographyDecomposition>& decompositions,
00536                                     const vector<Point2f>& points1, const vector<Point2f>& points2)
00537 {
00538   // According to Faugeras and Lustman, ambiguity exists if the two scores are equal
00539   // but in practive, better to look at the ratio!
00540   //  printf("\nEpipolar decompositions:\n");
00541   //  dumpDecompositions(decompositions);
00542   double ratio = (double) decompositions[1].score / (double) decompositions[0].score;
00543 
00544   if(ratio < 0.9) // no ambiguity!
00545   {
00546 //    printf("Returning with ratio = %f\n", ratio);
00547     decompositions.erase(decompositions.begin() + 1);
00548   }
00549 
00550   vector<double> epipolar_error;
00551   epipolar_error.resize(decompositions.size());
00552   for(size_t i = 0; i < decompositions.size(); i++)
00553   {
00554     Mat essential = calcEssentialMatrix(intrinsics_inv, decompositions[i].R, decompositions[i].T);
00555 
00556     epipolar_error[i] = avgSampsonusError(essential, points1, points2);
00557     //        printf("%f ", epipolar_error[i]);
00558   }
00559   //    printf("\n");
00560 
00561   // filter out higher epipolar
00562 
00563   if(decompositions.size() == 1)
00564   {
00565     return epipolar_error[0];
00566   }
00567 
00568 //  printf("Decomposition epipolar errors: %f %f\n", epipolar_error[0], epipolar_error[1]);
00569 #if 0
00570   const double minAvgEpipolarError = 1.0;
00571   if( epipolar_error[0] < minAvgEpipolarError &&
00572       epipolar_error[1] < minAvgEpipolarError) //at least two small epipolar errors
00573   {
00574     // filter decompositions based on epipolar error
00575     vector<HomographyDecomposition> _decompositions;
00576     for(size_t i = 0; i < epipolar_error.size(); i++)
00577     {
00578       if(epipolar_error[i] < minAvgEpipolarError)
00579       {
00580         _decompositions.push_back(decompositions[i]);
00581       }
00582     }
00583     decompositions = _decompositions;
00584     double error = filterDecompositionsZ(decompositions, points1, points2, intrinsics, intrinsics_inv);
00585     return error;
00586   }
00587 #endif
00588 
00589   // choose the smallest epipolar error
00590   vector<double>::iterator maxIt = std::max_element(epipolar_error.begin(), epipolar_error.end());
00591   double error = *maxIt;
00592   vector<HomographyDecomposition> _decompositions;
00593   _decompositions.push_back(decompositions[maxIt - epipolar_error.begin()]);
00594   decompositions = _decompositions;
00595 
00596   return error;
00597 }
00598 
00606 void selectDecomposition(vector<HomographyDecomposition>& decompositions, const Mat& H, const vector<Point2f>& points1, const vector<Point2f>& points2,
00607                          const vector<Point2f>& inliers1, const vector<Point2f>& inliers2, const Mat& intrinsics, const Mat& intrinsics_inv)
00608 {
00609   assert(decompositions.size() == 8);
00610   filterDecompositionsVisibility(decompositions, H, inliers1, inliers2);
00611 
00612   assert(decompositions.size() == 2);
00613   filterDecompositionsEpipolar(intrinsics, intrinsics_inv, decompositions, points1, points2);
00614 }
00615 
00616 void logDecompositions(std::string filename, const vector<HomographyDecomposition>& decompositions)
00617 {
00618   FileStorage fs(filename, FileStorage::WRITE);
00619   for(size_t i = 0; i < decompositions.size(); i++)
00620   {
00621     fs << std::string("R") << decompositions[i].R;
00622     fs << std::string("T") << decompositions[i].T;
00623   }
00624 }
00625 
00626 bool operator<(const HomographyDecomposition lhs, const HomographyDecomposition rhs)
00627 {
00628   return lhs.score < rhs.score;
00629 }
00630 
00631 //selects a subset of indices without replacement in the region [0, max_index-1].
00632 void sample(int max_index, int count, vector<int>& sample_indices)
00633 {
00634   sample_indices.clear();
00635   for(int i = 0; i < count; i++)
00636   {
00637     int index;
00638     while(1)
00639     {
00640       index = rand()%max_index;
00641       if(std::find(sample_indices.begin(), sample_indices.end(), index) == sample_indices.end())
00642       {
00643         break;
00644       }
00645     }
00646 
00647     sample_indices.push_back(index);
00648     if((int)sample_indices.size() == max_index)
00649     {
00650       break;
00651     }
00652   }
00653 }
00654 
00655 // selects four random pair of points and runs homography calculation on them
00656 Mat randomHomography(const vector<Point2f>& points1, const vector<Point2f>& points2,
00657                      vector<Point2f>& sample1, vector<Point2f>& sample2)
00658 {
00659   vector<int> indices;
00660 
00661   sample(points1.size(), 4, indices);
00662   vectorSubset(points1, indices, sample1);
00663   vectorSubset(points2, indices, sample2);
00664 
00665   Mat _H = getPerspectiveTransform(&sample1.front(), &sample2.front());
00666   Mat H;
00667   _H.convertTo(H, CV_32F);
00668   return H;
00669 }
00670 
00671 double SFMwithSBA(const Mat& intrinsics, const vector<KeyPoint>& set1, const vector<KeyPoint>& set2,
00672                   const vector<int>& indices, Mat& rvec, Mat& T, double reprojectionError)
00673 {
00674   vector<Point2f> points1, points2;
00675   matchesFromIndices(set1, set2, indices, points1, points2);
00676 
00677   return SFMwithSBA(intrinsics, points1, points2, rvec, T, reprojectionError);
00678 }
00679 
00680 void _filterInliers(const vector<Point3f>& obj_pts, const vector<Point2f>& img_pts,
00681                     const Mat& R, const Mat& T, const Mat& intrinsics, const Mat& distortion,
00682                     double reprojectionError, vector<bool>& valid)
00683 {
00684   assert(valid.size() == img_pts.size());
00685   vector<Point2f> img_pts_proj;
00686   img_pts_proj.resize(img_pts.size());
00687   Mat _R, _T;
00688   R.convertTo(_R, CV_64F);
00689   T.convertTo(_T, CV_64F);
00690   projectPoints(Mat(obj_pts), _R, _T, intrinsics, distortion, img_pts_proj);
00691 
00692   int count = 0;
00693   for(size_t i = 0; i < img_pts.size(); i++)
00694   {
00695     if(!valid[i]) continue;
00696 
00697     float error = norm(img_pts[i] - img_pts_proj[i]);
00698     if(error > reprojectionError)
00699     {
00700       valid[i] = false;
00701     }
00702     else
00703     {
00704       count++;
00705     }
00706   }
00707   //    std::cout << "Total number of valid points: " << count << std::endl;
00708 }
00709 
00710 void filterInliers(const vector<Point3f>& obj_pts, const vector<Point2f>& img1_pts, const vector<Point2f>& img2_pts,
00711                    const Mat& R, const Mat& T, const Mat& intrinsics, double reprojectionError, vector<bool>& valid)
00712 {
00713   Mat distortion = Mat::zeros(5, 1, CV_32F);
00714   Mat R0 = Mat::eye(3, 3, CV_32F);
00715   Mat T0 = Mat::zeros(3, 1, CV_32F);
00716 
00717   _filterInliers(obj_pts, img1_pts, R0, T0, intrinsics, distortion, reprojectionError, valid);
00718   _filterInliers(obj_pts, img2_pts, R, T, intrinsics, distortion, reprojectionError, valid);
00719 }
00720 
00721 double SFMwithSBA(const Mat& intrinsics, vector<Point2f>& points1, vector<Point2f>& points2,
00722                   Mat& rvec, Mat& T, double reprojectionError)
00723 {
00724   if(points1.size() < 4 || points2.size() < 4)
00725   {
00726     printf("SFMwithSBA called with %d points, exiting...\n", (int)points1.size());
00727     return -1.0;
00728   }
00729 
00730   Mat R, H;
00731   double error = SFM(intrinsics, points1, points2, R, T);
00732   //    printf("SFM completed with reprojection error %f\n", error);
00733   T = T*10.0;
00734   Mat _r(3, 1, CV_32F);
00735   Rodrigues(R, _r);
00736   dumpFltMat("SFM returned r", _r);
00737   dumpFltMat("SFM return T", T);
00738 
00739   Mat essential = calcEssentialMatrix(intrinsics.inv(), R, T);
00740   vector<bool> inliers;
00741   computeEpipolarInliers(essential, points1, points2, inliers, 10.0);
00742   filterVector(points1, inliers);
00743   filterVector(points2, inliers);
00744   //    filterVector(points, inliers);
00745   int inliersSum = 0;
00746   for(size_t i = 0; i < inliers.size(); i++) {inliersSum += inliers[i] ? 1 : 0;};
00747   cout << "The number of epipolar inliers: " << inliersSum << endl;
00748 
00749   vector<Point3f> cloud;
00750   vector<bool> valid;
00751   reprojectPoints(intrinsics, R, T, points1, points2, cloud, valid);
00752 
00753   printf("%d points before filtering\n", (int)cloud.size());
00754   filterVector(points1, valid);
00755   filterVector(points2, valid);
00756   //    filterVector(points, valid);
00757   filterVector(cloud, valid);
00758 
00759   printf("%d points left after filtering\n", (int)cloud.size());
00760   //    float error0 = calcScaledPointCloudDistance(cloud, points);
00761 
00762   //    Mat rvec;
00763   Rodrigues(R, rvec);
00764 
00765   sba(intrinsics, rvec, T, cloud, points1, points2);
00766   findNaNPoints(cloud, valid);
00767   filterVector(points1, valid);
00768   filterVector(points2, valid);
00769   filterVector(cloud, valid);
00770   //    filterVector(points, valid);
00771 
00772   //    float error1 = calcScaledPointCloudDistance(cloud, points);
00773 
00774   //    dumpFltMat("rvec", rvec);
00775   //    dumpFltMat("tvec", T);
00776 
00777   //    printf("%d points left after sba\n3D error after SFM: %f\n 3D error after sba: %f\n",
00778   //        cloud.size(), error0, error1);
00779   printf("%d points left after sba\n", (int)cloud.size());
00780 
00781   return error;
00782 }
00783 
00784 double SFM(const Mat& intrinsics, const vector<KeyPoint>& set1, const vector<KeyPoint>& set2,
00785            const vector<int>& indices, Mat& R, Mat& T, double reprojectionError)
00786 {
00787   vector<Point2f> points1, points2;
00788   matchesFromIndices(set1, set2, indices, points1, points2);
00789 
00790   return SFM(intrinsics, points1, points2, R, T, reprojectionError);
00791 }
00792 
00793 double SFM(const Mat& intrinsics, const vector<Point2f>& points1, const vector<Point2f>& points2,
00794            Mat& R, Mat& T, double reprojectionError)
00795 {
00796   vector<Point2f> full1 = points1, full2 = points2;
00797   //    points1.resize(100);
00798   //    points2.resize(100);
00799 
00800   Mat intrinsics_inv = intrinsics.inv();
00801 
00802   // ransac iteration
00803   const int ransac_count = 10000;
00804   double min_error = 1e10;
00805 
00806   const int min_acceptable_inlier_count = points1.size()*0.8;
00807   const double min_acceptable_error = 1.0;
00808 
00809   HomographyDecomposition best_decomposition;
00810   vector<HomographyDecomposition> best_decompositions;
00811   int maxInlierCount = 0;
00812   for(int i = 0; i < ransac_count; i++)
00813   {
00814 //    int64 _t1 = cvGetTickCount();
00815     vector<Point2f> sample1, sample2;
00816     Mat H = randomHomography(points1, points2, sample1, sample2);
00817 
00818     //        dumpFltMat("H", H);
00819 
00820     vector<HomographyDecomposition> decompositions, _decompositions;
00821     bool ret = homographyDecompose(intrinsics, H, decompositions);
00822     _decompositions = decompositions;
00823     if(!ret) continue;
00824 
00825     //        printf("\nDecompositions:\n");
00826     //        dumpDecompositions(decompositions);
00827     //        printf("\n\n");
00828 
00829 //    int64 _t2 = cvGetTickCount();
00830 
00831     // compute planar inliers
00832     vector<Point2f> inliers1;// = sample1;
00833     vector<Point2f> inliers2;// = sample2;
00834     computeHomographyInliers(points1, points2, H, inliers1, inliers2, reprojectionError);
00835     maxInlierCount = max(maxInlierCount, (int)inliers1.size());
00836 
00837     // filter out 6 decompositions using visibility constraint
00838     filterDecompositionsVisibility(decompositions, H, inliers1, inliers2);
00839 
00840 //    int64 _t3 = cvGetTickCount();
00841 
00842     //        printf("\nEpipolar decompositions:\n");
00843     //        dumpDecompositions(decompositions);
00844     //        printf("\n\n");
00845 
00846     // filter out the rest two decompositions using epipolar reprojection error
00847     double error = filterDecompositionsEpipolar(intrinsics, intrinsics_inv, decompositions, points1, points2);
00848 
00849     //        dumpDecompositions(decompositions);
00850     //        printf("Error = %f\n", error);
00851 
00852 //    int64 _t4 = cvGetTickCount();
00853 
00854     /*        printf("Time elapsed in ms:\n homography %f\n inliers/visiblility %f\n epipolar error %f\n",
00855                 1e-3*(_t2 - _t1)/cvGetTickFrequency(), 1e-3*(_t3 - _t2)/cvGetTickFrequency(),
00856                 1e-3*(_t4 - _t3)/cvGetTickFrequency());*/
00857 
00858     if(i % 1000 == 0)
00859     {
00860       //            printf("Iteration %d: minimum error %f\n", i, min_error);
00861     }
00862     if(error < min_error)
00863     {
00864       min_error = error;
00865       best_decomposition = decompositions[0];
00866       best_decompositions = _decompositions;
00867 
00868       if(error < min_acceptable_error && (int)inliers1.size() > min_acceptable_inlier_count)
00869       {
00870         printf("Finishing after iteration %d, inlier count %d\n", i, (int)inliers1.size());
00871         //                dumpFltMat("H", H);
00872         break;
00873       }
00874     }
00875   }
00876 
00877 #if defined(DEBUG_CONSOLE)
00878   cout << "Max inlier count " << maxInlierCount << endl;
00879 
00880   dumpDecompositions(best_decompositions);
00881 #endif //DEBUG_CONSOLE
00882 
00883   R = best_decomposition.R;
00884   T = best_decomposition.T;
00885 
00886 #if defined(DEBUG_CONSOLE)
00887   dumpFltMat("best R", R);
00888   dumpFltMat("best T", T);
00889 #endif //DEBUG_CONSOLE
00890 
00891   Mat E = calcEssentialMatrix(intrinsics_inv, R, T);
00892   double final_error = avgSampsonusError(E, full1, full2, std::numeric_limits<double>::max());
00893   printf("Final error: %f\n", final_error);
00894 
00895   return min_error;
00896 }
00897 
00898 void planarSFM(Mat& intrinsics, const vector<KeyPoint>& set1, const vector<KeyPoint>& set2, const vector<int>& indices,
00899                Mat& H, Mat& R, Mat& T, double reprojectionError)
00900 {
00901   Mat intrinsics_inv = intrinsics.inv();
00902 
00903   // Extract correspondences
00904   vector<Point2f> points1, points2;
00905   matchesFromIndices(set1, set2, indices, points1, points2);
00906 
00907   // find homography
00908   vector<Point2f> points1s, points2s;
00909   points1s = points1;
00910   points2s = points2;
00911   points1s.resize(4);
00912   points2s.resize(4);
00913   Mat _H = findHomography(Mat(points1s), Mat(points2s), CV_RANSAC, reprojectionError);
00914   _H.convertTo(H, CV_32F);
00915 
00916   // Compute inliers
00917   vector<Point2f> inliers1, inliers2;
00918   computeHomographyInliers(points1, points2, H, inliers1, inliers2, reprojectionError);
00919 
00920   // decompose homography to obtain 8 possible solutions
00921   vector<HomographyDecomposition> decompositions;
00922   homographyDecompose(intrinsics, H, decompositions);
00923 
00924   // select one solution from 8
00925   selectDecomposition(decompositions, H, points1, points2, inliers1, inliers2, intrinsics, intrinsics_inv);
00926 
00927   assert(decompositions.size() == 1);
00928   R = decompositions[0].R;
00929   T = decompositions[0].T;
00930 }
00931 
00932 void initNode(const Mat& intrinsics, const Mat& rvec, const Mat& tvec, sba::Node& node)
00933 {
00934   // rvec to quaternion
00935   double alpha = norm(rvec);
00936   double s;
00937   if(fabs(alpha) < std::numeric_limits<double>::epsilon())
00938   {
00939     s = 0.5;
00940   }
00941   else
00942   {
00943     s = sin(alpha*0.5)/alpha;
00944   }
00945 
00946   node.qrot = Vector4d(rvec.at<float>(0, 0)*s, rvec.at<float>(0, 1)*s, rvec.at<float>(0, 2)*s, cos(alpha*0.5));
00947   node.trans = Vector4d(tvec.at<float>(0, 0), tvec.at<float>(0, 1), tvec.at<float>(0, 2), 1);
00948   node.setTransform();
00949 
00950   fc::CamParams cp;
00951   cp.fx = intrinsics.at<float>(0, 0);
00952   cp.fy = intrinsics.at<float>(1, 1);
00953   cp.cx = intrinsics.at<float>(0, 2);
00954   cp.cy = intrinsics.at<float>(1, 2);
00955   // TBD should I set tx here?
00956       node.setKcam(cp);
00957 
00958       cout << "Node projection matrix" << endl << node.w2i << endl;
00959 
00960       node.setDri();
00961 
00962 }
00963 
00964 Point3f mult(const Mat& M, const Point3f& p)
00965 {
00966   Mat r = M*Mat(3, 1, CV_32F, const_cast<Point3f*>(&p));
00967   return *r.ptr<Point3f>(0);
00968 }
00969 
00970 Point3f multh(const Mat& M, const Point2f& p)
00971 {
00972   Point3f ph(p.x, p.y, 1.0f);
00973   return mult(M, ph);
00974 }
00975 
00976 void findRayIntersection(Point3f k1, Point3f b1, Point3f k2, Point3f b2, Point3f& p)
00977 {
00978   Point3f n = crossProduct(k1, k2);
00979 
00980   // find the closest point in 3D between two rays
00981   Mat A(3, 3, CV_32F), B(3, 1, CV_32F);
00982   *A.ptr<Point3f>(0) = -k1;
00983   *A.ptr<Point3f>(1) = k2;
00984   *A.ptr<Point3f>(2) = -n;
00985   A = A.t();
00986   *B.ptr<Point3f>(0) = b1 - b2;
00987 
00988   Mat X;
00989   solve(A, B, X);
00990 
00991   float s1 = X.at<float>(0, 0);
00992   float s2 = X.at<float>(1, 0);
00993   /*
00994     Point3f cross1 = k1*s1 + b1;
00995     Point3f cross2 = k2*s2 + b2;
00996 
00997     printf("k1: %f %f %f\n", k1.x, k1.y, k1.z);
00998     printf("k2: %f %f %f\n", k2.x, k2.y, k2.z);
00999     printf("b1: %f %f %f\n", b1.x, b1.y, b1.z);
01000     printf("b2: %f %f %f\n", b2.x, b2.y, b2.z);
01001     printf("s1: %f, s2: %f\n", s1, s2);
01002     printf("cross1: %f %f %f\n", cross1.x, cross1.y, cross1.z);
01003     printf("cross2: %f %f %f\n", cross2.x, cross2.y, cross2.z);
01004    */
01005   p = (k1*s1 + b1 + k2*s2 + b2)*0.5f;
01006 }
01007 
01010 void reprojectPoint(const Mat& R, const Mat& T, Point3f p1, Point3f p2, Point3f& p)
01011 {
01012   // find two rays in the form p(s) = k*s + b
01013   Point3f k1 = p1;
01014   Point3f b1(0.0f, 0.0f, 0.0f);
01015   Point3f k2 = mult(R.t(), p2);
01016   Mat tnew = -Mat(R.t()*T);
01017   Point3f b2 = *tnew.ptr<Point3f>(0);
01018 
01019   //    printf("k1 = %f %f %f, b1 = %f %f %f, k2 = %f %f %f, b2 = %f %f %f\n", k1.x, k1.y, k1.z,
01020   //           b1.x, b1.y, b1.z, k2.x, k2.y, k2.z, b2.x, b2.y, b2.z);
01021 
01022   findRayIntersection(k1, b1, k2, b2, p);
01023 }
01024 
01025 void reprojectPoints(const Mat& intrinsics, const Mat& R, const Mat& T, const vector<Point2f>& p1, const vector<Point2f>& p2,
01026                      vector<Point3f>& p, vector<bool>& valid)
01027 {
01028   Mat intrinsics_inv = intrinsics.inv();
01029 
01030   //    dumpFltMat("Reprojecting with R", R);
01031   //    dumpFltMat("Reprojecting with T", T);
01032 
01033   p.resize(p1.size());
01034   valid.resize(p1.size());
01035   assert(p1.size() == p2.size());
01036   for(size_t i = 0; i < p1.size(); i++)
01037   {
01038     Point3f rp1 = multh(intrinsics_inv, p1[i]);
01039     Point3f rp2 = multh(intrinsics_inv, p2[i]);
01040 
01041     reprojectPoint(R, T, rp1, rp2, p[i]);
01042     if(p[i].z < 0)
01043     {
01044       // filter this point out
01045       valid[i] = false;
01046 //      printf("Filtering point (%f %f), (%f %f), \n(%f %f), (%f %f), (%f %f %f) out\n",
01047 //             p1[i].x, p1[i].y, p2[i].x, p2[i].y, rp1.x, rp1.y, rp2.x, rp2.y, p[i].x, p[i].y, p[i].z);
01048     }
01049     else
01050     {
01051       valid[i] = true;
01052     }
01053   }
01054 }
01055 
01056 inline double calcNodeErr(sba::Proj& prj, const sba::Node &nd, const sba::Point &pt)
01057 {
01058   Eigen::Vector3d p1 = nd.w2i * pt;
01059   prj.err = p1.head(2)/p1(2);
01060   if (p1(2) <= 0.0)
01061   {
01062     prj.err = Vector3d(0.0,0.0,0.0);
01063     return 0.0;
01064   }
01065   //    printf("Projection: %f %f, gt: %f %f, ", prj.err(0), prj.err(1), prj.kp(0), prj.kp(1));
01066   prj.err -= prj.kp;
01067   //  printf("dist: %f\n", prj.err.squaredNorm());
01068   return prj.err.squaredNorm();
01069 }
01070 
01071 double calcCamProjCost(sba::SysSBA& sba, int cam)
01072 {
01073   double cost = 0.0;
01074   printf("sba.tracks.size = %d\n", (int)sba.tracks.size());
01075   for(size_t i=0; i<sba.tracks.size(); i++)
01076   {
01077     sba::ProjMap &prjs = sba.tracks[i].projections;
01078     if (prjs.size() == 0) continue;
01079     for(sba::ProjMap::iterator itr = prjs.begin(); itr != prjs.end(); itr++)
01080     {
01081       sba::Proj &prj = itr->second;
01082       if (!prj.isValid) continue;
01083       //            printf("ndi = %d\n", prj.ndi);
01084       if(prj.ndi != cam) continue;
01085       double err = calcNodeErr(prj, sba.nodes[prj.ndi], sba.tracks[i].point);
01086       //          if (err < 0.0)
01087       //            prj.isValid = false;
01088       //          else
01089       cost += err;
01090       //            printf("prj.pti = %d, err = %f, cost = %f\n", prj.pti, err, cost);
01091     }
01092   }
01093 
01094   printf("costProj done \n");
01095   return cost/sba.tracks.size();
01096 }
01097 
01098 void sba(const Mat& intrinsics, Mat& rvec, Mat& tvec, vector<Point3f>& points, const vector<Point2f>& points1, const vector<Point2f>& points2)
01099 {
01100   printf("sba got %d points\n", (int)points.size());
01101   // system
01102   sba::SysSBA sba0;
01103   sba0.verbose = 0;
01104 
01105   // set up nodes
01106   sba::Node nd0,nd1;
01107   Mat rvec0 = Mat::zeros(3, 1, CV_32F);
01108   Mat tvec0 = Mat::zeros(3, 1, CV_32F);
01109   initNode(intrinsics, rvec0, tvec0, nd0);
01110   nd0.isFixed = true;
01111 
01112   Mat sbaRvec = rvec;
01113   Mat sbaTvec = tvec;
01114   Mat sbaR;
01115   Rodrigues(sbaRvec, sbaR);
01116   sbaR = sbaR.t();
01117   sbaTvec = -sbaR*tvec;
01118   sbaRvec = -sbaRvec;
01119 
01120   initNode(intrinsics, sbaRvec, sbaTvec, nd1);
01121   nd1.isFixed = false;
01122 
01123   //    dumpFltMat("Initialized with rvec", sbaRvec);
01124   //    dumpFltMat("Initialized with tvec", sbaTvec);
01125 
01126   sba0.nodes.push_back(nd0);
01127   sba0.nodes.push_back(nd1);
01128 
01129   // set up projections
01130   for (size_t i=0; i<points.size(); i++)
01131   {
01132     // add point
01133     sba0.addPoint(Vector4d(points[i].x, points[i].y, points[i].z, 1.0));
01134     //        printf("%f %f %f\n", points[i].x, points[i].y, points[i].z);
01135 
01136     Vector2d p1(points1[i].x, points1[i].y);
01137     Vector2d p2(points2[i].x, points2[i].y);
01138 
01139     sba0.addMonoProj(0, (int)i, p1);
01140     sba0.addMonoProj(1, (int)i, p2);
01141 
01142   }
01143 
01144   printf("Added %d points, %d tracks\n", (int)sba0.tracks.size(), (int)sba0.tracks.size());
01145 
01146   double error1 = calcCamProjCost(sba0, 0);
01147   double error2 = calcCamProjCost(sba0, 1);
01148   printf("Errors after sba initialization: %f %f\n", error1, error2);
01149 
01150   //    sba.A.setZero(6, 6);
01151   sba0.nFixed = 1;
01152   sba0.printStats();
01153   // cout << "oldpoints.size() = " << sba0.oldpoints.size() << endl;
01154   printf("sba pointer: %p\n", &sba0);
01155   sba0.doSBA(5,10e-5,false);
01156   int nbad = sba0.removeBad(2.0);
01157   cout << endl << "Removed " << nbad << " projections > 2 pixels error" << endl;
01158   sba0.doSBA(5,10e-5,false);
01159 
01160   //        cout << endl << sba.nodes[1].trans.transpose().start(3) << endl;
01161   Eigen::Vector3d trans = sba0.nodes[1].trans.head(3);
01162   printf("trans = %f %f %f\n", trans(0), trans(1), trans(2));
01163   // do the convertion manually as there are
01164   *sbaTvec.ptr<Point3f>(0) = Point3f(trans(0), trans(1), trans(2));
01165 
01166   Quaterniond q1;
01167   q1 = sba0.nodes[1].qrot;
01168   Matrix3d rot = q1.toRotationMatrix();
01169   for(int i = 0; i < 3; i++)
01170   {
01171     *sbaR.ptr<Point3f>(i) = Point3f(rot(i, 0), rot(i, 1), rot(i, 2));
01172   }
01173   sbaR = sbaR.t();
01174   sbaTvec = -sbaR*sbaTvec;
01175   Rodrigues(sbaR, rvec);
01176 
01177   for(size_t i = 0; i < points.size(); i++)
01178   {
01179     points[i] = Point3f(sba0.tracks[i].point(0), sba0.tracks[i].point(1), sba0.tracks[i].point(2));
01180 #if defined(_DEBUG_CONSOLE)
01181     printf("%f %f %f\n", points[i].x, points[i].y, points[i].z);
01182 #endif
01183   }
01184 }
01185 
01186 float calcOptimalPointCloudScale(const vector<Point3f>& points1, const vector<Point3f>& points2)
01187 {
01188   assert(points1.size() == points2.size());
01189 
01190   float sum1 = 0.0f, sum2 = 0.0f;
01191   for(size_t i = 0; i < points1.size(); i++)
01192   {
01193     sum1 += points1[i].dot(points2[i]);
01194     sum2 += points1[i].dot(points1[i]);
01195   }
01196 
01197   return sum1/sum2;
01198 }
01199 
01200 float calcScaledPointCloudDistance(const vector<Point3f>& points1, const vector<Point3f>& points2)
01201 {
01202   assert(points1.size() == points2.size());
01203 
01204   float s = calcOptimalPointCloudScale(points1, points2);
01205 
01206   printf("Optimal scale = %f\n", s);
01207   float sum = 0.0f;
01208   for(size_t i = 0; i < points1.size(); i++)
01209   {
01210     Point3f d = points1[i]*s - points2[i];
01211     sum += d.dot(d);
01212 
01213     printf("Pair %d: (%f %f %f) vs (%f %f %f), dist = %f\n", (int)i, points1[i].x*s, points1[i].y*s,
01214            points1[i].z*s, points2[i].x, points2[i].y, points2[i].z, sqrt(d.dot(d)));
01215   }
01216 
01217   return sqrt(sum/points1.size());
01218 }
01219 
01220 void findNaNPoints(const vector<Point3f>& points, vector<bool>& valid)
01221 {
01222   valid.resize(points.size());
01223   for(size_t i = 0; i < points.size(); i++)
01224   {
01225     if(cvIsNaN(points[i].x) || cvIsNaN(points[i].y) || cvIsNaN(points[i].z))
01226     {
01227       valid[i] = false;
01228     }
01229     else
01230     {
01231       valid[i] = true;
01232     }
01233   }
01234 }
01235 
01236 void calcRelativeRT(const Mat& R1, const Mat& T1, const Mat& R2, const Mat& T2, Mat& dR, Mat& dT)
01237 {
01238   assert(R1.cols == R2.cols && R1.rows == R2.rows);
01239   Mat _R1, _R2;
01240 
01241   if(R1.cols == 1 || R1.rows == 1)
01242   {
01243     Rodrigues(R1, _R1);
01244     Rodrigues(R2, _R2);
01245   }
01246   else
01247   {
01248     _R1 = R1;
01249     _R2 = R2;
01250   }
01251 
01252   Mat R1inv = _R1.inv();
01253   Mat _dR = _R2*R1inv;
01254 
01255   dT = T2 - _R2*R1inv*T1;
01256 
01257   if(R1.cols == 1 || R1.rows == 1)
01258   {
01259     Rodrigues(_dR, dR);
01260   }
01261   else
01262   {
01263     dR = _dR;
01264   }
01265 }
01266 
01267 }


posest
Author(s): Kurt Konolige
autogenerated on Thu Jan 2 2014 12:12:17