Tutorial: Crater Ellipse Fitting
This software is made available under the MIT license. See SONIC/LICENSE for details.
In this example, we will be using SONIC to perform crater ellipse fitting using an image of Ceres, as captured by the Dawn spacecraft. We will first pull in the crater image and the extracted points around the crater rim. Then, we will use the EllipseFitter class in SONIC to fit an ellipse to the crater points. In an OPNAV routine, after performing crater identification, we can leverage estimated crater ellipse fits in the captured image and performing matching with a crater database (e.g., Robbins crater database) to extract pose information and perform triangulation.
Load Image and Extracted Crater Rim Points
First, we read in the image we are going to be analyzing as well as the series of points along the extracted crater rims, defined as 2D points in pixel space.
imgPath = '+examples/+data/FC21B0043185_15267083218F1E.png';
load('+examples/+data/craterRimPoints.mat');
Show Image of Raw Crater Rim Points
We next display the captured image of the surface of Ceres, overlayed with the raw points of two extracted crater rims in the image.
imshow(imgPath); hold on; title('Surface Craters on Ceres');
xlabel('x'); ylabel('y');
ncraters = length(xcraterPtsAll);
xcraterPts = xcraterPtsAll{i}; ycraterPts = ycraterPtsAll{i};
plot(xcraterPts, ycraterPts, '.');
Perform Various Ellipse Fitting Methods
For each crater, we create and save SONIC Points2 objects for the extracted points along each crater rim.
craterPts = cell(1,ncraters);
xcraterPts = xcraterPtsAll{i}; ycraterPts = ycraterPtsAll{i};
XYorig = sonic.Points2([xcraterPts' ; ycraterPts']);
Perform Various Ellipse Fitting Methods
Now, we will obtain crater ellipse fits using various fitting techniques. In particular, we will use traditional least squares as well as two unbiased ellipse fitting methods: semi-hyper least squares and hyper least squares [1].
First, we define the fitting methods we are interested in using. 'ls' denotes least squares, 'shls' denotes semi-hyper least squares, and 'hls' denotes hyper least squares. Then, for each crater, we provide the corresponding Points2 object of the crater points to the fitEllipse function to get our fit. We provide the fit in multiple formats, including as a Conic object, a 6D vector for the implicit representation of the conic, as well as a 5D vector of the explicit representation.
fitMthds = {'ls', 'shls', 'hls'};
nfitMthds = length(fitMthds);
explSolnsAll = cell(ncraters,nfitMthds);
[conicObj, implSoln, explSoln] = sonic.EllipseFitter.fitEllipse(XYorig,fitMthds{j});
explSolnsAll{i,j} = explSoln;
Plot Close-Up of Fitting Methods
Let's now plot and take a closer look at the different ellipse fitting methods, to see how they compare.
imshow(imgPath); hold on; title('Close-up on Ceres craters and ellipse fits');
xlabel('x'); ylabel('y'); fitColors = {'y','b','g'};
[xfit, yfit] = getEllipse(explSolnsAll{i,j});
plot(xfit,yfit, 'color', fitColors{j});
plot(xcraterPtsAll{i},ycraterPtsAll{i},'.','MarkerSize', 9,'color','r');
xlim([300,600]); ylim([780,900]);
lgObj = legend({'least squares', 'semi-hyper least squares', ...
'hyper least squares', 'crater points'},'Position', [0.62 0.23 0.25 0.09]);
References
[1] K. Kanatani and P. Rangarajan, “Hyper least squares fitting of circles and ellipses,” Computational Statistics & Data Analysis, vol. 55, no. 6, pp. 2197–2208, 2011.
%% helper function for computing ellipse locus
function [xf, yf] = getEllipse(explicitVals)
% specify theta values to plot
thetaEps = 0.01; nPts = ceil((2*pi)/thetaEps);
thetaVals = linspace(0,2*pi,nPts);
% strech into ellipse shape
finalPts = [cos(psi), -1*sin(psi); sin(psi), cos(psi)] * [x2; y2];