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;
}
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;
}
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);
}
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);
}
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;
}
Aggregations