00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
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 
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 
00153 
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   
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   
00203   
00204   { 
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   
00217   decomposition.dp = s * dPrime_PM;
00218   for(int signs=0; signs<4; signs++)
00219   {
00220     
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     
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   
00253   decomposition.dp = s * -dPrime_PM;
00254   for(int signs=0; signs<4; signs++)
00255   {
00256     
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     
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   
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     
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   
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       
00379       
00380       if(dVisibilityTest > 0.0)
00381         nPositive++;
00382     };
00383     decomposition.score = -nPositive;
00384 
00385     
00386   }
00387 
00388   sort(decompositions.begin(), decompositions.end());
00389 
00390   
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   
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   
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   
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   
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   
00539   
00540   
00541   
00542   double ratio = (double) decompositions[1].score / (double) decompositions[0].score;
00543 
00544   if(ratio < 0.9) 
00545   {
00546 
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     
00558   }
00559   
00560 
00561   
00562 
00563   if(decompositions.size() == 1)
00564   {
00565     return epipolar_error[0];
00566   }
00567 
00568 
00569 #if 0
00570   const double minAvgEpipolarError = 1.0;
00571   if( epipolar_error[0] < minAvgEpipolarError &&
00572       epipolar_error[1] < minAvgEpipolarError) 
00573   {
00574     
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   
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 
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 
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   
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   
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   
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   
00757   filterVector(cloud, valid);
00758 
00759   printf("%d points left after filtering\n", (int)cloud.size());
00760   
00761 
00762   
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   
00771 
00772   
00773 
00774   
00775   
00776 
00777   
00778   
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   
00798   
00799 
00800   Mat intrinsics_inv = intrinsics.inv();
00801 
00802   
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 
00815     vector<Point2f> sample1, sample2;
00816     Mat H = randomHomography(points1, points2, sample1, sample2);
00817 
00818     
00819 
00820     vector<HomographyDecomposition> decompositions, _decompositions;
00821     bool ret = homographyDecompose(intrinsics, H, decompositions);
00822     _decompositions = decompositions;
00823     if(!ret) continue;
00824 
00825     
00826     
00827     
00828 
00829 
00830 
00831     
00832     vector<Point2f> inliers1;
00833     vector<Point2f> inliers2;
00834     computeHomographyInliers(points1, points2, H, inliers1, inliers2, reprojectionError);
00835     maxInlierCount = max(maxInlierCount, (int)inliers1.size());
00836 
00837     
00838     filterDecompositionsVisibility(decompositions, H, inliers1, inliers2);
00839 
00840 
00841 
00842     
00843     
00844     
00845 
00846     
00847     double error = filterDecompositionsEpipolar(intrinsics, intrinsics_inv, decompositions, points1, points2);
00848 
00849     
00850     
00851 
00852 
00853 
00854     
00855 
00856 
00857 
00858     if(i % 1000 == 0)
00859     {
00860       
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         
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   
00904   vector<Point2f> points1, points2;
00905   matchesFromIndices(set1, set2, indices, points1, points2);
00906 
00907   
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   
00917   vector<Point2f> inliers1, inliers2;
00918   computeHomographyInliers(points1, points2, H, inliers1, inliers2, reprojectionError);
00919 
00920   
00921   vector<HomographyDecomposition> decompositions;
00922   homographyDecompose(intrinsics, H, decompositions);
00923 
00924   
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   
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   
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   
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 
00995 
00996 
00997 
00998 
00999 
01000 
01001 
01002 
01003 
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   
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   
01020   
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   
01031   
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       
01045       valid[i] = false;
01046 
01047 
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   
01066   prj.err -= prj.kp;
01067   
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       
01084       if(prj.ndi != cam) continue;
01085       double err = calcNodeErr(prj, sba.nodes[prj.ndi], sba.tracks[i].point);
01086       
01087       
01088       
01089       cost += err;
01090       
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   
01102   sba::SysSBA sba0;
01103   sba0.verbose = 0;
01104 
01105   
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   
01124   
01125 
01126   sba0.nodes.push_back(nd0);
01127   sba0.nodes.push_back(nd1);
01128 
01129   
01130   for (size_t i=0; i<points.size(); i++)
01131   {
01132     
01133     sba0.addPoint(Vector4d(points[i].x, points[i].y, points[i].z, 1.0));
01134     
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   
01151   sba0.nFixed = 1;
01152   sba0.printStats();
01153   
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   
01161   Eigen::Vector3d trans = sba0.nodes[1].trans.head(3);
01162   printf("trans = %f %f %f\n", trans(0), trans(1), trans(2));
01163   
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 }