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 }