4

How can I get inliers/outliers of matched kyepoints using homography or some other method in C#?

I am working on SURF example provided on http://www.emgu.com/wiki/index.php/SURF_feature_detector_in_CSharp.

I got matchedFeature. Code uses HomographyMatrix (homography). I want to separate inliers and outliers.

In C++:

bgroup({findFundamentalMat})

int cvFindFundamentalMat(const CvMat* points1, const CvMat* points2, 
    CvMat* fundamentalMatrix, int method=CV_FM_RANSAC, double param1=1., 
    double param2=0.99, CvMat* status=NULL)

returns inliers. Can I see similiar code also in C#.

Again I just need outliers/inliers separation.

casperOne
  • 73,706
  • 19
  • 184
  • 253
Shahgee
  • 3,303
  • 8
  • 49
  • 81

3 Answers3

7

If you want inliers/outliers separation and you already have your matches try this:

//**RANSAC OUTLIER REMOVAL **//
Mat status;
vector<Point2f> trainMatches;
vector<Point2f> queryMatches;
vector<DMatch> inliers; 

    for( int i = 0; i < goodmatches.size(); i++ )
    {
        //-- Get the keypoints from the good matches
        trainMatches.push_back( cv::Point2f(keypointsB[ goodmatches[i].trainIdx ].pt.x/640.0f, keypointsB[ goodmatches[i].trainIdx ].pt.y/480.0f) );
        queryMatches.push_back( cv::Point2f(keypointsA[ goodmatches[i].queryIdx ].pt.x/640.0f, keypointsA[ goodmatches[i].queryIdx ].pt.y/480.0f) );
    }   

    Mat _homography;    
    Mat h = cv::findHomography(trainMatches,queryMatches,CV_RANSAC,0.005, status);

    for(size_t i = 0; i < queryMatches.size(); i++) 
    {
        if(status.at<char>(i) != 0) 
        {
            inliers.push_back(goodmatches[i]);
        }
    }

Note that I normalized the points so Homography estimation is more robust.

Jav_Rock
  • 22,059
  • 20
  • 123
  • 164
5

Your question is not so clear because if you are using emgucv homography computation is estimated using CameraCalibration.FindHomography() function using RANSAC if there are more than 10 matching pairs. I'm working on these topics for my thesis so i will post some relevant code that should fully reply to you and serve also to others.

result = MatchingRefinement.VoteForSizeAndOrientation(result, 1.5, 20);
homography = MatchingRefinement.
    GetHomographyMatrixFromMatchedFeatures(result, 
        HomographyDirection.DIRECT, HOMOGRAPHY_METHOD.LMEDS);
inverseHomography = MatchingRefinement.GetHomographyMatrixFromMatchedFeatures(
    result, HomographyDirection.INVERSE, HOMOGRAPHY_METHOD.LMEDS);

PointF[] pts1 = new PointF[result.Length];
PointF[] pts1_t = new PointF[result.Length];
PointF[] pts2 = new PointF[result.Length];

for (int i = 0; i < result.Length; i++)
{
    pts1[i] = result[i].ObservedFeature.KeyPoint.Point;
    pts1_t[i] = result[i].ObservedFeature.KeyPoint.Point;
    pts2[i] = result[i].SimilarFeatures[0].Feature.KeyPoint.Point;
}

// Project model features according to homography
homography.ProjectPoints(pts1_t);

Image<Bgr, Byte> finalCorrespondance = inputImage.Copy();

matchedInliersFeatures = new List<MatchedImageFeature>();

for (int i1 = 0; i1 < pts1_t.Length; i1++)
{
    if (Math.Sqrt(Math.Pow(pts2[i1].X - pts1_t[i1].X, 2d) + 
        Math.Pow(pts2[i1].Y - pts1_t[i1].Y, 2d)) <4d) // Inlier
    {
        PointF p_t = pts1_t[i1];
        PointF p = pts1[i1];
        finalCorrespondance.Draw(new CircleF(p, 2f), 
            new Bgr(Color.Yellow), 2);
        finalCorrespondance.Draw(new CircleF(p_t, 2f), 
            new Bgr(Color.Black), 2);
        finalCorrespondance.Draw(new LineSegment2DF(p, p_t), 
            new Bgr(Color.Blue), 1);

        MatchedImageFeature feature = new MatchedImageFeature();
        feature.SimilarFeatures = new SimilarFeature[] { 
            result[i1].SimilarFeatures[0] 
        };
        feature.ObservedFeature = result[i1].ObservedFeature;
        matchedInliersFeatures.Add(feature);
    }
}

List<ImageFeature> inliers = new List<ImageFeature>();
foreach (MatchedImageFeature match in matchedInliersFeatures)
{
    inliers.Add(match.ObservedFeature);
    inliers.Add(match.SimilarFeatures[0].Feature);
}
casperOne
  • 73,706
  • 19
  • 184
  • 253
Luca Del Tongo
  • 2,702
  • 16
  • 18
1

The signature of cvFindFundamentalMat in C# would look like this:

int cvFindFundamentalMat(CvMat points1, CvMat points2, CvMat fundamentalMatrix, 
     CV_FM method, double param1, double param2, CvMat status);

Parameter defaults was introduced in C# 4.0. I assume that Emgu CV does not support .Net 4.0 yet (correct me if I'm wrong), thus an overload providing the default values could be made:

int cvFindFundamentalMat(CvMat points1, CvMat points2, CvMat fundamentalMatrix)
{
    return cvFindFundamentalMat(points1, points2, fundamentalMatrix,
           CV_FM.CV_FM_RANSAC, 1.0, 0.99, null);
}

Note: as commenters also have stated, it is hard to be sure what you're asking for. Here, I have just guessed that some of your question is how the provided C++ code would look like in C#.

Peter Lillevold
  • 33,668
  • 7
  • 97
  • 131
  • Thanx, for this help. I need explaination why you are using status (Null). I have in example PointF format of points. Do I have to make matrix from them. Matrix circles = new Matrix(length, 1, 2); or Matrix circles = new Matrix(length, 2, 1); – Shahgee Jan 09 '11 at 20:21
  • status==null was just because the default value from the C++ signature was null. – Peter Lillevold Jan 10 '11 at 08:12
  • But yes, if you have `PointF` data you would have to convert them into a `CvMat` structure first. – Peter Lillevold Jan 10 '11 at 08:14