use of georegression.fitting.curves.RefineEllipseEuclideanLeastSquares_F64 in project BoofCV by lessthanoptimal.
the class ShapeFittingOps method fitEllipse_F64.
/**
* Computes the best fit ellipse based on minimizing Euclidean distance. An estimate is initially provided
* using algebraic algorithm which is then refined using non-linear optimization. The amount of non-linear
* optimization can be controlled using 'iterations' parameter. Will work with partial and complete contours
* of objects.
*
* <p>NOTE: To improve speed, make calls directly to classes in Georegression. Look at the code for details.</p>
*
* @param points (Input) Set of unordered points. Not modified.
* @param iterations Number of iterations used to refine the fit. If set to zero then an algebraic solution
* is returned.
* @param computeError If true it will compute the average Euclidean distance error
* @param outputStorage (Output/Optional) Storage for the ellipse. Can be null.
* @return Found ellipse.
*/
public static FitData<EllipseRotated_F64> fitEllipse_F64(List<Point2D_F64> points, int iterations, boolean computeError, FitData<EllipseRotated_F64> outputStorage) {
if (outputStorage == null) {
outputStorage = new FitData<>(new EllipseRotated_F64());
}
// Compute the optimal algebraic error
FitEllipseAlgebraic_F64 algebraic = new FitEllipseAlgebraic_F64();
if (!algebraic.process(points)) {
// could be a line or some other weird case. Create a crude estimate instead
FitData<Circle2D_F64> circleData = averageCircle_F64(points, null, null);
Circle2D_F64 circle = circleData.shape;
outputStorage.shape.set(circle.center.x, circle.center.y, circle.radius, circle.radius, 0);
} else {
UtilEllipse_F64.convert(algebraic.getEllipse(), outputStorage.shape);
}
// Improve the solution from algebraic into Euclidean
if (iterations > 0) {
RefineEllipseEuclideanLeastSquares_F64 leastSquares = new RefineEllipseEuclideanLeastSquares_F64();
leastSquares.setMaxIterations(iterations);
leastSquares.refine(outputStorage.shape, points);
outputStorage.shape.set(leastSquares.getFound());
}
// compute the average Euclidean error if the user requests it
if (computeError) {
ClosestPointEllipseAngle_F64 closestPoint = new ClosestPointEllipseAngle_F64(1e-8, 100);
closestPoint.setEllipse(outputStorage.shape);
double total = 0;
for (Point2D_F64 p : points) {
closestPoint.process(p);
total += p.distance(closestPoint.getClosest());
}
outputStorage.error = total / points.size();
} else {
outputStorage.error = 0;
}
return outputStorage;
}
Aggregations