// Imagine++ project // Project: Fundamental // Author: Pascal Monasse // Date: 2013/10/08 #include "./Imagine/Features.h" #include #include #include #include #include using namespace Imagine; using namespace std; static const float BETA = 0.01f; // Probability of failure struct Match { float x1, y1, x2, y2; }; // Display SIFT points and fill vector of point correspondences void algoSIFT(Image I1, Image I2, vector& matches) { // Find interest points SIFTDetector D; D.setFirstOctave(-1); Array feats1 = D.run(I1); drawFeatures(feats1, Coords<2>(0,0)); cout << "Im1: " << feats1.size() << flush; Array feats2 = D.run(I2); drawFeatures(feats2, Coords<2>(I1.width(),0)); cout << " Im2: " << feats2.size() << flush; const double MAX_DISTANCE = 100.0*100.0; for(size_t i=0; i < feats1.size(); i++) { SIFTDetector::Feature f1=feats1[i]; for(size_t j=0; j < feats2.size(); j++) { double d = squaredDist(f1.desc, feats2[j].desc); if(d < MAX_DISTANCE) { Match m; m.x1 = f1.pos.x(); m.y1 = f1.pos.y(); m.x2 = feats2[j].pos.x(); m.y2 = feats2[j].pos.y(); matches.push_back(m); } } } } // 8 points method if inliers is of size 8 // Otherwise, solve the minimization problem "min ||Af||2 subject to ||f|| = 1" FMatrix computeSingleF(const vector& matches, const vector& inliers){ assert(inliers.size() >= 8); // create normalization matrix FMatrix N(0.0); N(0,0)=N(1,1)=0.001; N(2,2)=1; // create A Matrix A(max(9,(int)inliers.size()), 9); Match m; for(size_t ii=0; ii S; Matrix U, Vt; svd(A,U,S,Vt); // Copy F from Vt; FMatrix F; F(0,0) = Vt(8,0); F(0,1) = Vt(8,1); F(0,2) = Vt(8,2); F(1,0) = Vt(8,3); F(1,1) = Vt(8,4); F(1,2) = Vt(8,5); F(2,0) = Vt(8,6); F(2,1) = Vt(8,7); F(2,2) = Vt(8,8); return N*F*N; } // Finds inliers from a list of matches vector findInliers (vector& matches, FMatrix& F, float d){ vector inliers; for(size_t ii=0; ii x(m.x1,m.y1,1); FVector y(m.x2,m.y2,1); FVector Fy = F*y; if( abs(x*Fy) / sqrt(Fy[0]*Fy[0] + Fy[1]*Fy[1]) < d) inliers.push_back(ii); } return inliers; } // RANSAC algorithm to compute F from point matches (8-point algorithm) // Parameter matches is filtered to keep only inliers as output. FMatrix computeF(vector& matches) { const float distMax = 1.5f; // Pixel error for inlier/outlier discrimination int Niter=100000; // Adjusted dynamically FMatrix bestF; vector bestInliers; FMatrix F; for(int ii=0; ii inliers; while(inliers.size()<8){ int kk = rand() % matches.size(); if(find(inliers.begin(), inliers.end(), kk) == inliers.end()) inliers.push_back(kk); } F = computeSingleF(matches, inliers); inliers = findInliers(matches, F, distMax); if(inliers.size()> bestInliers.size()){ bestInliers = inliers; Niter = (int)ceil(log(BETA)/log(1-pow((float)inliers.size()/(float)matches.size(), 8))); } } cout << bestInliers.size() << " inliers" << endl; cout << Niter << " iterations" << endl; // refine F with all the inliers bestF = computeSingleF(matches, bestInliers); // Updating matches with inliers only vector all=matches; matches.clear(); for(size_t i=0; i I1, Image I2, const FMatrix& F) { while(true) { int x,y; if(getMouse(x,y) == 3) break; drawCircle(x, y, 5, RED); drawCircle(x, y, 4, GREEN); if(x>I1.width()){ FVector Y((float)x - I1.width(),(float)y,1.0); FVector FY = F*Y; drawLine(0,-FY[2]/FY[1], I1.width(),-(FY[2]+FY[0]*I1.width())/FY[1], RED); } else{ FVector X((float)x,(float)y,1.0); FVector FtX = transpose(F)*X; drawLine(I1.width(), (-1)*(FtX[2])/FtX[1], 2*I1.width(), (-1)*(FtX[2]+FtX[0]*I1.width())/FtX[1], RED); } } } int main(int argc, char* argv[]) { srand((unsigned int)time(0)); const char* s1 = argc>1? argv[1]: srcPath("im1.jpg"); const char* s2 = argc>2? argv[2]: srcPath("im2.jpg"); // Load and display images Image I1, I2; if( ! load(I1, s1) || ! load(I2, s2) ) { cerr<< "Unable to load images" << endl; return 1; } int w = I1.width(); openWindow(2*w, I1.height()); display(I1,0,0); display(I2,w,0); vector matches; algoSIFT(I1, I2, matches); cout << " matches: " << matches.size() << endl; click(); FMatrix F = computeF(matches); cout << "F="<< endl << F; // Redisplay with matches display(I1,0,0); display(I2,w,0); for(size_t i=0; i