Fit Ellipse
Earlier this month, I was looking for a quick way to fit an ellipse for a set of points. I did some searching around and this paper looked most promising. The explanation looked fairly interesting.
The best part, however, is that the paper provides a MATLAB implementation for the algorithm that Fits an ellipse in Canonical form
$$ Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0 $$
The program gives the estimates for parameters A..F.
The algorithm looks fairly straightforward to implement. The only wrinkle is the calculation of the eigenvalues and vectors for a matrix. So, in order to avoid re-inventing the wheel, I used the excellent library Meta.Numerics available at codeplex.
So here is the class that does it all
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Meta.Numerics.Matrices;
using Meta.Numerics;
namespace FitEllipse
{
public class EllipseFit
{
public Matrix Fit(PointCollection points)
{
int numPoints = points.Count;
Matrix D1 = new Matrix(numPoints, 3);
Matrix D2 = new Matrix(numPoints, 3);
SquareMatrix S1 = new SquareMatrix(3);
SquareMatrix S2 = new SquareMatrix(3);
SquareMatrix S3 = new SquareMatrix(3);
SquareMatrix T = new SquareMatrix(3);
SquareMatrix M = new SquareMatrix(3);
SquareMatrix C1 = new SquareMatrix(3);
Matrix a1 = new Matrix(3, 1);
Matrix a2 = new Matrix(3, 1);
Matrix result = new Matrix(6, 1);
Matrix temp;
C1[0, 0] = 0;
C1[0, 1] = 0;
C1[0, 2] = 0.5;
C1[1, 0] = 0;
C1[1, 1] = -1;
C1[1, 2] = 0;
C1[2, 0] = 0.5;
C1[2, 1] = 0;
C1[2, 2] = 0;
//2 D1 = [x .ˆ 2, x .* y, y .ˆ 2]; % quadratic part of the design matrix
//3 D2 = [x, y, ones(size(x))]; % linear part of the design matrix
for (int xx = 0; xx < points.Count; xx++)
{
Point p = points[xx];
D1[xx, 0] = p.X * p.X;
D1[xx, 1] = p.X * p.Y;
D1[xx, 2] = p.Y * p.Y;
D2[xx, 0] = p.X;
D2[xx, 1] = p.Y;
D2[xx, 2] = 1;
}
//4 S1 = D1’ * D1; % quadratic part of the scatter matrix
temp = D1.Transpose() * D1;
for (int xx = 0; xx < 3; xx++)
for (int yy = 0; yy < 3; yy++)
S1[xx, yy] = temp[xx, yy];
//5 S2 = D1’ * D2; % combined part of the scatter matrix
temp = D1.Transpose() * D2;
for (int xx = 0; xx < 3; xx++)
for (int yy = 0; yy < 3; yy++)
S2[xx, yy] = temp[xx, yy];
//6 S3 = D2’ * D2; % linear part of the scatter matrix
temp = D2.Transpose() * D2;
for (int xx = 0; xx < 3; xx++)
for (int yy = 0; yy < 3; yy++)
S3[xx, yy] = temp[xx, yy];
//7 T = - inv(S3) * S2’; % for getting a2 from a1
T = -1 * S3.Inverse() * S2.Transpose();
//8 M = S1 + S2 * T; % reduced scatter matrix
M = S1 + S2 * T;
//9 M = [M(3, :) ./ 2; - M(2, :); M(1, :) ./ 2]; % premultiply by inv(C1)
M = C1 * M;
//10 [evec, eval] = eig(M); % solve eigensystem
ComplexEigensystem eigenSystem = M.Eigensystem();
//11 cond = 4 * evec(1, :) .* evec(3, :) - evec(2, :) .ˆ 2; % evaluate a’Ca
//12 a1 = evec(:, find(cond > 0)); % eigenvector for min. pos. eigenvalue
for (int xx = 0; xx < eigenSystem.Dimension; xx++)
{
Vector<Complex> vector = eigenSystem.Eigenvector(xx);
Complex condition = 4 * vector[0] * vector[2] - vector[1] * vector[1];
if (condition.Im == 0 && condition.Re > 0)
{
// Solution is found
Console.WriteLine("\nSolution Found!");
for (int yy = 0; yy < vector.Count(); yy++)
{
Console.Write("{0}, ", vector[yy]);
a1[yy, 0] = vector[yy].Re;
}
}
}
//13 a2 = T * a1; % ellipse coefficients
a2 = T * a1;
//14 a = [a1; a2]; % ellipse coefficients
result[0, 0] = a1[0, 0];
result[1, 0] = a1[1, 0];
result[2, 0] = a1[2, 0];
result[3, 0] = a2[0, 0];
result[4, 0] = a2[1, 0];
result[5, 0] = a2[2, 0];
return result;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FitEllipse
{
public class Point
{
public double X { get; set; }
public double Y {get; set; }
}
public class PointCollection : List<Point>
{
}
}
Read other posts