Search in sources :

Example 1 with Circle2D_F64

use of georegression.struct.trig.Circle2D_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)

Example 2 with Circle2D_F64

use of georegression.struct.trig.Circle2D_F64 in project BoofCV by lessthanoptimal.

the class ShapeFittingOps method averageCircle_I32.

/**
 * Computes a circle which has it's center at the mean position of the provided points and radius is equal to the
 * average distance of each point from the center.  While fast to compute the provided circle is not a best
 * fit circle by any reasonable metric, except for special cases.
 *
 * @param points (Input) Set of unordered points. Not modified.
 * @param optional (Optional) Used internally to store the distance of each point from the center.  Can be null.
 * @param outputStorage (Output/Optional) Storage for results.  If null then a new circle instance will be returned.
 * @return The found circle fit.
 */
public static FitData<Circle2D_F64> averageCircle_I32(List<Point2D_I32> points, GrowQueue_F64 optional, FitData<Circle2D_F64> outputStorage) {
    if (outputStorage == null) {
        outputStorage = new FitData<>(new Circle2D_F64());
    }
    if (optional == null) {
        optional = new GrowQueue_F64();
    }
    Circle2D_F64 circle = outputStorage.shape;
    int N = points.size();
    // find center of the circle by computing the mean x and y
    int sumX = 0, sumY = 0;
    for (int i = 0; i < N; i++) {
        Point2D_I32 p = points.get(i);
        sumX += p.x;
        sumY += p.y;
    }
    optional.reset();
    double centerX = circle.center.x = sumX / (double) N;
    double centerY = circle.center.y = sumY / (double) N;
    double meanR = 0;
    for (int i = 0; i < N; i++) {
        Point2D_I32 p = points.get(i);
        double dx = p.x - centerX;
        double dy = p.y - centerY;
        double r = Math.sqrt(dx * dx + dy * dy);
        optional.push(r);
        meanR += r;
    }
    meanR /= N;
    circle.radius = meanR;
    // compute radius variance
    double variance = 0;
    for (int i = 0; i < N; i++) {
        double diff = optional.get(i) - meanR;
        variance += diff * diff;
    }
    outputStorage.error = variance / N;
    return outputStorage;
}
Also used : Circle2D_F64(georegression.struct.trig.Circle2D_F64) Point2D_I32(georegression.struct.point.Point2D_I32) GrowQueue_F64(org.ddogleg.struct.GrowQueue_F64)

Example 3 with Circle2D_F64

use of georegression.struct.trig.Circle2D_F64 in project BoofCV by lessthanoptimal.

the class TestShapeFittingOps method averageCircle_F64.

@Test
public void averageCircle_F64() {
    List<Point2D_F64> points = new ArrayList<>();
    points.add(new Point2D_F64(0, 0));
    points.add(new Point2D_F64(10, 0));
    points.add(new Point2D_F64(5, 5));
    points.add(new Point2D_F64(5, -5));
    FitData<Circle2D_F64> found = ShapeFittingOps.averageCircle_F64(points, null, null);
    assertEquals(5, found.shape.center.x, 1e-5);
    assertEquals(0, found.shape.center.y, 1e-5);
    assertEquals(5, found.shape.radius, 1e-5);
    assertEquals(0, found.error, 1e-5);
    // Pass in storage and see if it fails
    found.error = 23;
    found.shape.center.x = 3;
    GrowQueue_F64 optional = new GrowQueue_F64();
    optional.push(4);
    ShapeFittingOps.averageCircle_F64(points, optional, found);
    assertEquals(5, found.shape.center.x, 1e-5);
    assertEquals(0, found.shape.center.y, 1e-5);
    assertEquals(5, found.shape.radius, 1e-5);
    assertEquals(0, found.error, 1e-5);
    // now make it no longer a perfect fit
    points.get(0).x = -1;
    found = ShapeFittingOps.averageCircle_F64(points, null, null);
    assertTrue(found.error > 0);
}
Also used : Circle2D_F64(georegression.struct.trig.Circle2D_F64) Point2D_F64(georegression.struct.point.Point2D_F64) ArrayList(java.util.ArrayList) GrowQueue_F64(org.ddogleg.struct.GrowQueue_F64) Test(org.junit.Test)

Example 4 with Circle2D_F64

use of georegression.struct.trig.Circle2D_F64 in project BoofCV by lessthanoptimal.

the class TestShapeFittingOps method averageCircle_I32.

@Test
public void averageCircle_I32() {
    List<Point2D_I32> points = new ArrayList<>();
    points.add(new Point2D_I32(0, 0));
    points.add(new Point2D_I32(10, 0));
    points.add(new Point2D_I32(5, 5));
    points.add(new Point2D_I32(5, -5));
    FitData<Circle2D_F64> found = ShapeFittingOps.averageCircle_I32(points, null, null);
    assertEquals(5, found.shape.center.x, 1e-5);
    assertEquals(0, found.shape.center.y, 1e-5);
    assertEquals(5, found.shape.radius, 1e-5);
    assertEquals(0, found.error, 1e-5);
    // Pass in storage and see if it fails
    found.error = 23;
    found.shape.center.x = 3;
    GrowQueue_F64 optional = new GrowQueue_F64();
    optional.push(4);
    ShapeFittingOps.averageCircle_I32(points, optional, found);
    assertEquals(5, found.shape.center.x, 1e-5);
    assertEquals(0, found.shape.center.y, 1e-5);
    assertEquals(5, found.shape.radius, 1e-5);
    assertEquals(0, found.error, 1e-5);
    // now make it no longer a perfect fit
    points.get(0).x = -1;
    found = ShapeFittingOps.averageCircle_I32(points, null, null);
    assertTrue(found.error > 0);
}
Also used : Circle2D_F64(georegression.struct.trig.Circle2D_F64) ArrayList(java.util.ArrayList) Point2D_I32(georegression.struct.point.Point2D_I32) GrowQueue_F64(org.ddogleg.struct.GrowQueue_F64) Test(org.junit.Test)

Example 5 with Circle2D_F64

use of georegression.struct.trig.Circle2D_F64 in project BoofCV by lessthanoptimal.

the class ShapeFittingOps method averageCircle_F64.

/**
 * Computes a circle which has it's center at the mean position of the provided points and radius is equal to the
 * average distance of each point from the center.  While fast to compute the provided circle is not a best
 * fit circle by any reasonable metric, except for special cases.
 *
 * @param points (Input) Set of unordered points. Not modified.
 * @param optional (Optional) Used internally to store the distance of each point from the center.  Can be null.
 * @param outputStorage (Output/Optional) Storage for results.  If null then a new circle instance will be returned.
 * @return The found circle fit.
 */
public static FitData<Circle2D_F64> averageCircle_F64(List<Point2D_F64> points, GrowQueue_F64 optional, FitData<Circle2D_F64> outputStorage) {
    if (outputStorage == null) {
        outputStorage = new FitData<>(new Circle2D_F64());
    }
    if (optional == null) {
        optional = new GrowQueue_F64();
    }
    Circle2D_F64 circle = outputStorage.shape;
    int N = points.size();
    // find center of the circle by computing the mean x and y
    double sumX = 0, sumY = 0;
    for (int i = 0; i < N; i++) {
        Point2D_F64 p = points.get(i);
        sumX += p.x;
        sumY += p.y;
    }
    optional.reset();
    double centerX = circle.center.x = sumX / (double) N;
    double centerY = circle.center.y = sumY / (double) N;
    double meanR = 0;
    for (int i = 0; i < N; i++) {
        Point2D_F64 p = points.get(i);
        double dx = p.x - centerX;
        double dy = p.y - centerY;
        double r = Math.sqrt(dx * dx + dy * dy);
        optional.push(r);
        meanR += r;
    }
    meanR /= N;
    circle.radius = meanR;
    // compute radius variance
    double variance = 0;
    for (int i = 0; i < N; i++) {
        double diff = optional.get(i) - meanR;
        variance += diff * diff;
    }
    outputStorage.error = variance / N;
    return outputStorage;
}
Also used : Circle2D_F64(georegression.struct.trig.Circle2D_F64) Point2D_F64(georegression.struct.point.Point2D_F64) GrowQueue_F64(org.ddogleg.struct.GrowQueue_F64)

Aggregations

Circle2D_F64 (georegression.struct.trig.Circle2D_F64)5 GrowQueue_F64 (org.ddogleg.struct.GrowQueue_F64)4 Point2D_F64 (georegression.struct.point.Point2D_F64)3 Point2D_I32 (georegression.struct.point.Point2D_I32)2 ArrayList (java.util.ArrayList)2 Test (org.junit.Test)2 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