Alberto A Alberto A - 5 months ago 105
C++ Question

Testing number of outliers of opencv warpAffine

I'm using opencv to estimate the affine transform between two images (let's call it A and B, and I want to estimate from A to B), and I need to implement RANSAC to get the best estimation possible. So far, my framework for RANSAC (considering I already have the keypoints for both images and the matches between them):

1: Choose 3 random matches, and use the matching points from A and B as input to the function getAffineTransform;

2: Use the function warpAffine to warp the points from A, and compare the results with the points of B., getting the rate of outliers: e;

3: Considering the size of my sample is 3 points (getAffineTransform needs 3 points to find the transform) and I have the rate of outliers e, I can find the number of times I need to run RANSAC to have a high probability of finding a good estimation, which is N times;

4: Rerun steps 1 and 2 N times keeping the transform with the smallest outlier rate;

While the basic Idea seems to be fine, I'm having some trouble with the execution, specifically step 2. My problem is, I'm not sure how I can test for the number of outliers. I thought about mapping the points of A to B with warpAffine, but I'm almost sure it wouldn't work because I believe the function would interpret my Mat of points (which is an Mx2 Mat, with M the number of points and each column the coordinates x and y of the point) as an Image, instead of a set of points I want to map. How can I do this?

I'm using opencv 2.4.2 with c++.


Answering my own question, I actually found a way to do it. I'm not sure it's the best way to do it, but it seems to work fine based on the tests I've done until now.

As explained here,

an affine transformation is a transformation that can be expressed as a multiplication of matrices. So, applying the transformation consists of simply multiplying my points by the matrix I get from getAffineTransform. Before mapping a single point, we need to append a '1' to the point to be mapped and transpose it (so we have column vector), and then map by multiplying it by the transformation matrix. We can easily extend this mapping for every point if We convert the Mx2 point matrix to a 3xM point matrix of the form:

|x1, x2, x3, ...., xM|
|y1, y2, y3, ...., yM|
| 1,  1,  1, ....,  1|

and multiply it by the transformation matrix! I might edit this post later with a simple test program I've made to show how this works.

Also, to append this vector of ones and transposing it, I'm doing the following:

1 - Create a new 3 x M matrix consisting of ones with Mat::ones, named newPtMat
2 - transpose my original point matrix, and keep it in a temp Mat
3 - use temp.copyTo(newPtMat.rowRange(0, 2)

I'm not sure this is the most efficient way to do it, so if anybody has a better suggestion, please leave a comment!