use of georegression.struct.curve.EllipseRotated_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.curve.EllipseRotated_F64 in project BoofCV by lessthanoptimal.
the class CommonDetectCalibrationApp method renderShapes.
protected void renderShapes(Graphics2D g2, double scale) {
List<Polygon2D_F64> squares = getFoundPolygons();
for (int i = 0; i < squares.size(); i++) {
Polygon2D_F64 p = squares.get(i);
// if (isInGrids(p)) TODO fix broken method isInGrids
// continue;
g2.setColor(Color.cyan);
g2.setStroke(new BasicStroke(4));
drawPolygon(p, g2, scale);
g2.setColor(Color.blue);
g2.setStroke(new BasicStroke(2));
drawPolygon(p, g2, scale);
drawCornersInside(g2, scale, p);
}
List<EllipseRotated_F64> ellipses = getFoundEllipses();
AffineTransform rotate = new AffineTransform();
for (int i = 0; i < ellipses.size(); i++) {
EllipseRotated_F64 ellipse = ellipses.get(i);
rotate.setToIdentity();
rotate.rotate(ellipse.phi);
double w = scale * ellipse.a * 2;
double h = scale * ellipse.b * 2;
Shape shape = rotate.createTransformedShape(new Ellipse2D.Double(-w / 2, -h / 2, w, h));
shape = AffineTransform.getTranslateInstance(scale * ellipse.center.x, scale * ellipse.center.y).createTransformedShape(shape);
g2.setColor(Color.cyan);
g2.setStroke(new BasicStroke(4));
g2.draw(shape);
g2.setColor(Color.blue);
g2.setStroke(new BasicStroke(2));
g2.draw(shape);
}
}
use of georegression.struct.curve.EllipseRotated_F64 in project BoofCV by lessthanoptimal.
the class DetectCalibrationCircleHexagonalApp method renderGrid.
@Override
protected void renderGrid(Graphics2D g2, double scale) {
List<Grid> grids = detector.getDetector().getGrider().getGrids().toList();
BasicStroke thin = new BasicStroke(3);
BasicStroke thick = new BasicStroke(5);
for (Grid g : grids) {
double x0 = Double.MAX_VALUE;
double x1 = -Double.MAX_VALUE;
double y0 = Double.MAX_VALUE;
double y1 = -Double.MAX_VALUE;
for (int i = 0; i < g.ellipses.size(); i++) {
EllipseRotated_F64 e = g.ellipses.get(i);
if (e == null)
continue;
x0 = Math.min(e.center.x, x0);
x1 = Math.max(e.center.x, x1);
y0 = Math.min(e.center.y, y0);
y1 = Math.max(e.center.y, y1);
}
x0 *= scale;
y0 *= scale;
x1 *= scale;
y1 *= scale;
g2.setColor(Color.WHITE);
g2.setStroke(thick);
VisualizeShapes.drawRectangle(x0, y0, x1, y1, line, g2);
g2.setColor(Color.ORANGE);
g2.setStroke(thin);
VisualizeShapes.drawRectangle(x0, y0, x1, y1, line, g2);
}
renderTangents(g2, scale);
}
use of georegression.struct.curve.EllipseRotated_F64 in project BoofCV by lessthanoptimal.
the class DetectCalibrationCircleHexagonalApp method renderClusters.
@Override
protected void renderClusters(Graphics2D g2, double scale) {
List<EllipseRotated_F64> found = detector.getDetector().getEllipseDetector().getFoundEllipses(null);
List<List<EllipsesIntoClusters.Node>> clusters = detector.getDetector().getClusters();
g2.setStroke(new BasicStroke(2));
int id = 0;
for (List<EllipsesIntoClusters.Node> c : clusters) {
g2.setColor(colorId[Math.min(id++, colorId.length - 1)]);
for (EllipsesIntoClusters.Node n : c) {
EllipseRotated_F64 a = found.get(n.which);
line.x1 = scale * a.center.x;
line.y1 = scale * a.center.y;
for (int i = 0; i < n.connections.size; i++) {
EllipseRotated_F64 b = found.get(n.connections.get(i));
line.x2 = scale * b.center.x;
line.y2 = scale * b.center.y;
g2.draw(line);
}
}
}
}
use of georegression.struct.curve.EllipseRotated_F64 in project BoofCV by lessthanoptimal.
the class DetectCalibrationCircleRegularApp method renderClusters.
@Override
protected void renderClusters(Graphics2D g2, double scale) {
List<BinaryEllipseDetector.EllipseInfo> found = detector.getDetector().getEllipseDetector().getFound().toList();
List<List<EllipsesIntoClusters.Node>> clusters = detector.getDetector().getClusters();
g2.setStroke(new BasicStroke(2));
int id = 0;
for (List<EllipsesIntoClusters.Node> c : clusters) {
g2.setColor(colorId[Math.min(id++, colorId.length - 1)]);
for (EllipsesIntoClusters.Node n : c) {
EllipseRotated_F64 a = found.get(n.which).ellipse;
line.x1 = a.center.x * scale;
line.y1 = a.center.y * scale;
for (int i = 0; i < n.connections.size; i++) {
EllipseRotated_F64 b = found.get(n.connections.get(i)).ellipse;
line.x2 = b.center.x * scale;
line.y2 = b.center.y * scale;
g2.draw(line);
}
}
}
}
Aggregations