public static MatrixH Homography(PointF[] points1, PointF[] points2)
{
// Initial argument checks
if (points1.Length != points2.Length)
throw new ArgumentException("The number of points should be equal.");
if (points1.Length < 4)
throw new ArgumentException("At least four points are required to fit an homography");
int N = points1.Length;
MatrixH T1, T2; // Normalize input points
points1 = Tools.Normalize(points1, out T1);
points2 = Tools.Normalize(points2, out T2);
// Create the matrix A
var A = new float[3 * N, 9];
for (int i = 0; i < N; i++)
{
PointF X = points1[i];
float x = points2[i].X;
float y = points2[i].Y;
int r = 3 * i;
A[r, 0] = 0;
A[r, 1] = 0;
A[r, 2] = 0;
A[r, 3] = -X.X;
A[r, 4] = -X.Y;
A[r, 5] = -1;
A[r, 6] = y * X.X;
A[r, 7] = y * X.Y;
A[r, 8] = y;
r++;
A[r, 0] = X.X;
A[r, 1] = X.Y;
A[r, 2] = 1;
A[r, 3] = 0;
A[r, 4] = 0;
A[r, 5] = 0;
A[r, 6] = -x * X.X;
A[r, 7] = -x * X.Y;
A[r, 8] = -x;
r++;
A[r, 0] = -y * X.X;
A[r, 1] = -y * X.Y;
A[r, 2] = -y;
A[r, 3] = x * X.X;
A[r, 4] = x * X.Y;
A[r, 5] = x;
A[r, 6] = 0;
A[r, 7] = 0;
A[r, 8] = 0;
}
// Create the singular value decomposition
SingularValueDecompositionF svd = new SingularValueDecompositionF(A,
computeLeftSingularVectors: false, computeRightSingularVectors: true,
autoTranspose: false, inPlace: true);
float[,] V = svd.RightSingularVectors;
// Extract the homography matrix
MatrixH H = new MatrixH(V[0, 8], V[1, 8], V[2, 8],
V[3, 8], V[4, 8], V[5, 8],
V[6, 8], V[7, 8], V[8, 8]);
// Denormalize
H = T2.Inverse().Multiply(H.Multiply(T1));
return H;
}
#endregion