Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

findEssentialMat for coplanar points

[this is a copy of a [question I just posted on StackOverflow](http://stackoverflow.com/questions/36844139/opencv-findessentialmat)]

I came to a conclusion that OpenCV's findEssentialMat is not working properly for coplanar points. The documentation specifies that it uses Nister's 5 point algorithm, and the corresponding paper declares that the algorithm works fine for coplanar points.

void main() {
    ofstream log;
    log.open("errorLog.txt");

    srand((time(NULL) % RAND_MAX) * RAND_MAX);

    /******* camera properties *******/
    Mat camMat = Mat::eye(3, 3, CV_64F);
    Mat distCoeffs = Mat::zeros(4, 1, CV_64F);

    /******* pose 1 *******/
    Mat rVec1 = (Mat_<double>(3, 1) << 0, 0, 0); 
    Mat tVec1 = (Mat_<double>(3, 1) << 0, 0, 1);
    /******* pose 2 *******/
    Mat rVec2 = (Mat_<double>(3, 1) << 0.0, 0.0, 0); 
    Mat tVec2 = (Mat_<double>(3, 1) << 0.2, 0, 1); // 2nd camera pose is just a pose1 translated by 0.2 along the X axis


    int iterCount = 50;
    int N = 40;
    for (int j = 0; j < iterCount; j++)
    {
        /******* generate 3D points *******/
        vector<Point3f> points3d = generatePlanarPoints(N);

        /******* project 3D points from pose 1 *******/
        vector<Point2f> points2d1;
        projectPoints(points3d, rVec1, tVec1, camMat, distCoeffs, points2d1);
        /******* project 3D points from pose 2 *******/
        vector<Point2f> points2d2;
        projectPoints(points3d, rVec2, tVec2, camMat, distCoeffs, points2d2);


        /******* add noise to 2D points *******/
        std::default_random_engine generator;
        double noise = 1.0 / 640;

        if (noise > 0.0) {
            std::normal_distribution<double> distribution(0.0, noise);
            for (int i = 0; i < N; i++)
            {
                points2d1[i].x += distribution(generator);
                points2d1[i].y += distribution(generator);
                points2d2[i].x += distribution(generator);
                points2d2[i].y += distribution(generator);
            }
        }



        /******* find transformation from 2D - 2D correspondences *******/
        double threshold = 2.0 / 640;
         Mat essentialMat = findEssentialMat(points2d1, points2d2, 1.0, Point(0,0), RANSAC, 0.999, threshold);
         Mat estimatedRMat1, estimatedRMat2, estimatedTVec;
         decomposeEssentialMat(essentialMat, estimatedRMat1, estimatedRMat2, estimatedTVec);
         Mat estimatedRVec1, estimatedRVec2;
         Rodrigues(estimatedRMat1, estimatedRVec1);
         Rodrigues(estimatedRMat2, estimatedRVec2);
         double minError = min(norm(estimatedRVec1 - rVec2), norm(estimatedRVec2 - rVec2));

        log << minError << endl; // logging errors 

    }

    log.flush();
    log.close();
    return;
}

The points are generated like this:

vector<Point3f> generatePlanarPoints(int N) {
    float span = 5.0;

    vector<Point3f> points3d;
    for (int i = 0; i < N; i++)
    {
        float x = ((float)rand() / RAND_MAX - 0.5) * span;
        float y = ((float)rand() / RAND_MAX - 0.5) * span;
        float z = 0;
        Point3f point3d(x,y,z);
        points3d.push_back(point3d);
    }
    return points3d;
}

Excerpt from errorLog.txt file:

0
0.199337
0.199337
0.199337
0.199338
0
0.199337
0
0
0.199337
0.199337

This shows us that algorithm sometimes performs good (error == 0), and sometimes something weird happens (error == 0.199337). Is there any other explanation for this?

I also experimented with different prob and threshold parameters for findEssentialMat. And I tried using more/less points and different camera poses... same thing is happening.

findEssentialMat for coplanar points

[this is a copy of a [question I just posted on StackOverflow](http://stackoverflow.com/questions/36844139/opencv-findessentialmat)]

I came to a conclusion that OpenCV's findEssentialMat is not working properly for coplanar points. The documentation specifies that it uses Nister's 5 point algorithm, and the corresponding paper declares that the algorithm works fine for coplanar points.

void main() {
    ofstream log;
    log.open("errorLog.txt");

    srand((time(NULL) % RAND_MAX) * RAND_MAX);

    /******* camera properties *******/
    Mat camMat = Mat::eye(3, 3, CV_64F);
    Mat distCoeffs = Mat::zeros(4, 1, CV_64F);

    /******* pose 1 *******/
    Mat rVec1 = (Mat_<double>(3, 1) << 0, 0, 0); 
    Mat tVec1 = (Mat_<double>(3, 1) << 0, 0, 1);
    /******* pose 2 *******/
    Mat rVec2 = (Mat_<double>(3, 1) << 0.0, 0.0, 0); 
    Mat tVec2 = (Mat_<double>(3, 1) << 0.2, 0, 1); // 2nd camera pose is just a pose1 translated by 0.2 along the X axis


    int iterCount = 50;
    int N = 40;
    for (int j = 0; j < iterCount; j++)
    {
        /******* generate 3D points *******/
        vector<Point3f> points3d = generatePlanarPoints(N);

        /******* project 3D points from pose 1 *******/
        vector<Point2f> points2d1;
        projectPoints(points3d, rVec1, tVec1, camMat, distCoeffs, points2d1);
        /******* project 3D points from pose 2 *******/
        vector<Point2f> points2d2;
        projectPoints(points3d, rVec2, tVec2, camMat, distCoeffs, points2d2);


        /******* add noise to 2D points *******/
        std::default_random_engine generator;
        double noise = 1.0 / 640;

        if (noise > 0.0) {
            std::normal_distribution<double> distribution(0.0, noise);
            for (int i = 0; i < N; i++)
            {
                points2d1[i].x += distribution(generator);
                points2d1[i].y += distribution(generator);
                points2d2[i].x += distribution(generator);
                points2d2[i].y += distribution(generator);
            }
        }



        /******* find transformation from 2D - 2D correspondences *******/
        double threshold = 2.0 / 640;
         Mat essentialMat = findEssentialMat(points2d1, points2d2, 1.0, Point(0,0), RANSAC, 0.999, threshold);
         Mat estimatedRMat1, estimatedRMat2, estimatedTVec;
         decomposeEssentialMat(essentialMat, estimatedRMat1, estimatedRMat2, estimatedTVec);
         Mat estimatedRVec1, estimatedRVec2;
         Rodrigues(estimatedRMat1, estimatedRVec1);
         Rodrigues(estimatedRMat2, estimatedRVec2);
         double minError = min(norm(estimatedRVec1 - rVec2), norm(estimatedRVec2 - rVec2));

        log << minError << endl; // logging errors 

    }

    log.flush();
    log.close();
    return;
}

The points are generated like this:

vector<Point3f> generatePlanarPoints(int N) {
    float span = 5.0;

    vector<Point3f> points3d;
    for (int i = 0; i < N; i++)
    {
        float x = ((float)rand() / RAND_MAX - 0.5) * span;
        float y = ((float)rand() / RAND_MAX - 0.5) * span;
        float z = 0;
        Point3f point3d(x,y,z);
        points3d.push_back(point3d);
    }
    return points3d;
}

Excerpt from errorLog.txt file:

0
0.199337
0.199337
0.199337
0.199338
0
0.199337
0
0
0.199337
0.199337

This shows us that algorithm sometimes performs good (error == 0), and sometimes something weird happens (error == 0.199337). Is there any other explanation for this?

Obviously, the algorithm is deterministic and error 0.199337 will appear for a specific configuration of points. What is this configuration, I wasn't able to figure out.

I also experimented with different prob and threshold parameters for findEssentialMat. And I tried using more/less points and different camera poses... same thing is happening.