#include #include #include #include #include #ifndef _WIN32 #include #endif #include #include "Ops.h" //#define DEBUG_RANSAC using namespace MatVec; using namespace std; using namespace Geometry; using namespace MultiViewGeom; typedef vector, Point2D > > MatchVec2Im; namespace HomogConsistF { // Linear version for use in RANSAC template bool Linear(Matrix &H, MatchT &Matches, const MultiViewGeom::FMatrix &FM) { Matrix EigenVecs(3,3), FT(3,3); // Do FM^{T}*FM double sum; // TransposeT() for (unsigned int i=0;i<3;i++) for (unsigned int k=0;k<3;k++) { sum=FM(i,0)*FM(k,0); for (unsigned int j=1;j<3;j++) sum+=FM(i,j)*FM(k,j); FT(i,k)=sum; } double EigenVals[3]; MatrixOps::EigenValVec_Symmetric(FT, EigenVals, EigenVecs); Homg2DPoint e2(EigenVecs(0,0), EigenVecs(1,0), EigenVecs(2,0)); double norm=1.0/sqrt(e2.x()+e2.y()+e2.w()); e2.x()*=norm; e2.y()*=norm; e2.w()*=norm; const T e2x=e2.x(), e2y=e2.y(), e2w=e2.w(); // Helps numerical stability in some near degenerate cases to at least have a value in a1,a2,a3 T a1=0.3, a2=0.3, a3=0.3; H(0,0)=e2y*FM(2,0)-e2w*FM(1,0)+e2x*a1; H(0,1)=e2y*FM(2,1)-e2w*FM(1,1)+e2x*a2; H(0,2)=e2y*FM(2,2)-e2w*FM(1,2)+e2x*a3; H(1,0)=e2w*FM(0,0)-e2x*FM(2,0)+e2y*a1; H(1,1)=e2w*FM(0,1)-e2x*FM(2,1)+e2y*a2; H(1,2)=e2w*FM(0,2)-e2x*FM(2,2)+e2y*a3; H(2,0)=e2x*FM(1,0)-e2y*FM(0,0)+e2w*a1; H(2,1)=e2x*FM(1,1)-e2y*FM(0,1)+e2w*a2; H(2,2)=e2x*FM(1,2)-e2y*FM(0,2)+e2w*a3; // Build a constraint matrix Matrix A(Matches.size(), 3); double *b=new double[Matches.size()]; for (unsigned int i=0; i, Point2D > &Match, const Matrix &H) { const double px=Match.first[0], py=Match.first[1], pw=1.0; double tx=H(0,0)*px+H(0,1)*py+H(0,2)*pw; double ty=H(1,0)*px+H(1,1)*py+H(1,2)*pw; double tz=H(2,0)*px+H(2,1)*py+H(2,2)*pw; Point2D NP(tx/tz,ty/tz); double xdiff=NP.x()-Match.second.x(), ydiff=NP.y()-Match.second.y(); return xdiff*xdiff+ydiff*ydiff; } // The function itself void RANSAC(const vector, Point2D > > &Matches, vector, Point2D > > &OutlierFree, Matrix &ReturnH, const FMatrix &FM) { // Copy out of the iterator and into a vector so can normalise without destroying callers copy. unsigned int i; vector > Hs; // I know - I know - this is just in this simplified version OutlierFree.clear(); vector, Point2D > >::size_type numm=Matches.size(); if (numm<10) { cerr << "Planar homography RANSAC estimate (consistant with fundamental matrix) must be given at least 10 point matches to work!. So, go away and don't come back until you've got some more!\n" << endl; exit(1); } unsigned int minsample=10; // LMedS style calculation of number of sub-samples unsigned int NumberSubSamples=400; #ifdef DEBUG_RANSAC cerr << "Calculating Planar Homography matrix using LMedS:" << endl; cerr << "Number matches=" << numm << endl; cerr << "Using " << NumberSubSamples << " 4 point subsamples" << endl; #endif // Pre-allocate match vector for the four point algorithm vector, Point2D > > PassThrough(minsample); // So, run the 3 point algorithm on NumberSubSamples subsamples for (i=0;i H(3,3); if (Linear(H, PassThrough, FM)) Hs.push_back(H); } // Now, need to determine the median of the squared residuals, for each image double *residuals=new double[numm], *bestr=new double[numm]; double minhuber=DBL_MAX, bestmaxerr=0.0; double med; int residual; vector >::const_iterator Hs_iter; MatchVec2Im::const_iterator iter; Matrix BestH(3,3); for (Hs_iter=Hs.begin(); Hs_iter!=Hs.end(); ++Hs_iter) { const Matrix &H=*Hs_iter; residual=0; // First run through all matches and evaluate the residual for (iter=Matches.begin();iter!=Matches.end();++iter) // evaluate d(m, Hm')^2 + d(m', H^T m)^2 residuals[residual++]=GetResidual_RANSAC(*iter, H); // Now, find the median of the results. if (residual>0) { med=MiscMath::VectorMedian(residuals, residuals+residual); // Get confidence limit for Huber function double robuststddev=1.4826*(1.0+(5.0/(numm-minsample)))*sqrt(med); double maxerr=3.84*robuststddev*robuststddev; // Now, go through residuals and sum double hubersum=0.0; for (int i=0;i &A, double *EigenVals, Matrix &EigenVecs) { // First, check if it is symmetric unsigned int i,j; size_t N=A.num_rows(); bool Symm=true; if (N!=A.num_cols()) Symm=false; else { for (i=0;i &A, MatVec::Matrix &AInv) { int N = (int)A.num_rows(); if (A.num_rows()!=A.num_cols() || N<1) return false; // Going to use AInv as our workspace AInv=A; // Set up storage int *ipiv = new int[N]; int info; // Call for the LU factorisation dgetrf_(&N, &N, &(AInv(0,0)), &N, ipiv, &info); if (info>0) { std::cerr << "info=" << info << std::endl; delete[] ipiv; return false; } // Set up workspace int lwork = N; double *workd = new double[lwork]; // Now, call for inverse dgetri_(&N, &(AInv(0,0)), &N, ipiv, workd, &lwork, &info); delete[] ipiv; delete[] workd; // If got a singular matrix if (info>0) return false; return true; } } namespace MiscMath { double selectnth_heap(unsigned long m, double *ArrBegin, double *ArrEnd) { typedef double DataT; unsigned long i,j,k,n=(unsigned long)(distance(ArrBegin, ArrEnd)); DataT swap; m=n-m+1; // Since want to find nth lowest value, not nth highest value // const DataT *arr=ArrBegin-1; DataT *heap=new DataT[m+2]; copy(ArrBegin, ArrBegin+m, heap); sort(heap, heap+m); --heap; for (i=m+1;i<=n;++i) { if (ArrBegin[i-1]>heap[1]) { heap[1]=ArrBegin[i-1]; for (j=1;;) { k=j << 1; if (k>m) break; if (k!=m && heap[k] > heap[k+1]) ++k; if (heap[j] <= heap[k]) break; swap=heap[k]; heap[k]=heap[j]; heap[j]=swap; j=k; } } } DataT rval=heap[1]; ++heap; delete[] heap; return rval; } double VectorMedian(double *VecBegin, double *VecEnd) { if (VecBegin==VecEnd) return 0.0; double median; unsigned int size=(unsigned int)(distance(VecBegin, VecEnd)); if (size % 2 == 0) { // Don't use pedants if enough items in the iterator to get away with it if (size>100) median=MiscMath::selectnth_heap(size/2, VecBegin, VecEnd); else median= (MiscMath::selectnth_heap(size/2, VecBegin, VecEnd)+ MiscMath::selectnth_heap((size/2)+1, VecBegin, VecEnd))/2.0; } else // Odd case median=MiscMath::selectnth_heap(((size+1)/2)-1, VecBegin, VecEnd); return median; } } namespace LAPACK { extern "C" { int dgelsy_(int *, int *, int *, double *, int *, double *, int *, int *, double *, int *, double *, int *, int *); } bool LeastSquaresRankDeff(Matrix& A, const double *B, double *X) { int m=(int)A.num_rows(), n=(int)A.num_cols(); int info=1, one=1; int *jpvt=new int[n]; int rank; double rcond=1e-14; int mn=m; if (nlwork) lwork=2*mn+1; double *Work=new double[lwork]; // copy B into temp holder since X is wrong dimensions double *Temp=new double[m]; for (int i=0;i