Search in sources :

Example 1 with RefineEllipseEuclideanLeastSquares_F64

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;
}
Also used : Circle2D_F64(georegression.struct.trig.Circle2D_F64) EllipseRotated_F64(georegression.struct.curve.EllipseRotated_F64) Point2D_F64(georegression.struct.point.Point2D_F64) RefineEllipseEuclideanLeastSquares_F64(georegression.fitting.curves.RefineEllipseEuclideanLeastSquares_F64) FitEllipseAlgebraic_F64(georegression.fitting.curves.FitEllipseAlgebraic_F64) ClosestPointEllipseAngle_F64(georegression.fitting.curves.ClosestPointEllipseAngle_F64)

Aggregations

ClosestPointEllipseAngle_F64 (georegression.fitting.curves.ClosestPointEllipseAngle_F64)1 FitEllipseAlgebraic_F64 (georegression.fitting.curves.FitEllipseAlgebraic_F64)1 RefineEllipseEuclideanLeastSquares_F64 (georegression.fitting.curves.RefineEllipseEuclideanLeastSquares_F64)1 EllipseRotated_F64 (georegression.struct.curve.EllipseRotated_F64)1 Point2D_F64 (georegression.struct.point.Point2D_F64)1 Circle2D_F64 (georegression.struct.trig.Circle2D_F64)1