FindHomography algorithm : some doubt

asked 2016-04-23 07:46:54 -0600

LBerger gravatar image

Hi,

I have some doubt about FindHomography algorithm. I wrote a program to test it. In this program I have rotated an image look for descriptors in original image and rotated image. After matching I use findHomography to retrieve transformation and calculate square error for RANSAC, LMEDS and RHO method. I wrote algorithm for Levenberg-Marquardt algorithm (using Numerical Recipes ). I can add some noise to point location. NR algorithm is best without noise. Problem is when noise increase. NR is always best and other algorithms (RANSAC LMEDS and RHO) become completly wrong. I fit only six parameters using NR. I think it is like in findHomography.

May be something is wrong in my program. I don't think so. Everybody can check my code here. If you want to check with NR you can download full code on github

#include <opencv2/opencv.hpp> 
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace cv;
using namespace std;

double SquareError(Mat h, vector<Point2d> src,vector<Point2d> dst)
{
    double e=0;
    for (int i = 0; i < src.size(); i++)
    {
        double x = src[i].x*h.at<double>(0,0)+src[i].y*h.at<double>(0,1)+h.at<double>(0,2);
        double y = src[i].x*h.at<double>(1,0)+src[i].y*h.at<double>(1,1)+h.at<double>(1,2);
        e += (x-dst[i].x)*(x-dst[i].x)+(y-dst[i].y)*(y-dst[i].y);
    }

return e;
}

#ifdef GITHUBCODE
vector<double> AjusteHomography(vector<Point2d> x,vector <Point2d> y,vector<double> paramIni);
#endif



vector<KeyPoint> kpts1,kpts2;
vector<vector<DMatch> > couple;
Mat m1;
float maxDist ;
float minDist;
const char* window_name = "Original";
int noiseLevel=0;
static void NoisAmpl(int, void*)
{
    vector<Point2d> src,dst;
    for (int i = 1; i < couple.size(); i++)
        if (couple[i][0].distance < (maxDist + minDist) / 10)
        {
            Point2f p(rand()/double(RAND_MAX)-0.5,rand()/double(RAND_MAX)-0.5);
            src.push_back(kpts1[couple[i][0].queryIdx].pt+noiseLevel/2.0*p);
            dst.push_back(kpts2[couple[i][0].trainIdx].pt);
        }
    cout << "# matches " << src.size() << "\n";
    Mat h=findHomography(src,dst,CV_RANSAC);

    cout<<"RANSAC ="<<h<<endl;
    cout << "Error RANSAC =" << SquareError(h,src,dst)<<endl;
    h=findHomography(src,dst,CV_LMEDS);
    cout<<"LMEDS="<<h<<endl;
    cout << "Error LMEDS =" << SquareError(h,src,dst)<<endl;
    h=findHomography(src,dst,RHO);
    cout<<"RHO="<<h<<endl;
    cout << "Error RHO =" << SquareError(h,src,dst)<<endl;
    Mat m3;
#ifdef GITHUBCODE
    vector<double> paramIni = {0,0,0,0,0,0};
    vector<double> hh=AjusteHomography(src,dst,paramIni);
    for (int i = 0; i<hh.size();i++)
        cout << hh[i] << "\t";
    cout<<endl;
    Mat hhlvb= (Mat_<double>(3,3) << hh[0],hh[1],hh[2],hh[3],hh[4],hh[5],0,0,1);
    cout << "Error NRC" << SquareError(hhlvb,src,dst)<<endl;
    hhlvb.at<double>(0,2) *=2;
    hhlvb.at<double>(1,2) *=2;
    cout<<"H "<<h<<"\n";
    warpPerspective(m1, m3, hhlvb, Size(m1.cols,m1.rows));
    imshow("m3NRC",m3);
#endif
    h.at<double>(0 ...
(more)
edit retag flag offensive close merge delete

Comments

I don't have the mathematical background to help you but here some suggestions/questions:

  • you should add the equations, formulas, some texts that explain the approach you implemented, it would help to understand the code.
  • if you know which approach is implemented in OpenCV and can summarize it, maybe you could try to ask your question with the detail of both approachs on https://math.stackexchange.com/ or a forum of this kind?
  • it seems that you add noise for every points. What happens if you add noise for 30/40% of all the matches (outliers)?
  • it seems that you simulate only affine transformation, what happens with perspective transformation?
Eduardo gravatar imageEduardo ( 2016-04-25 05:01:37 -0600 )edit

Maybe your method is just better? Maybe it would help you if you manage to highlight the main differences between the two approaches: minimization method, the way to solve the homography problem, ...?

Just for my knowledge, how your method handle the noise? Is it like a least square method?

As a side note, if you manage to prove that your method performs better in term of accuracy and or in term of speed, it would be great to have it as a pull request in OpenCV in my opinion.

Eduardo gravatar imageEduardo ( 2016-04-25 07:09:02 -0600 )edit

About first comment I don't think that's changing noise or transform will change results.

Yes my method is always the best one but thta's not mine it is real Levenberg-Marquardt method from NRC p678.

I think there is a bug in LMSolver in opencv...

LBerger gravatar imageLBerger ( 2016-04-25 07:20:29 -0600 )edit