Point, Line and Plane Estimators

This documentation was generated with the assistance of AI. Please report any inaccuracies.

Point2D/Point3D, Line2D and Plane are the three simplest estimator hierarchies in com.irurueta.geometry.estimators. Each one wraps a single closed-form linear-algebra construction — the exact join/meet operations already derived on Points, Lines and Planes — in the same family of five robust variants that Estimators explains once, generically, for all twelve hierarchies in the library. This page does not re-derive either piece: it connects the two. For the join/meet cross products, the signed point-to-line distance and the 4×4-determinant plane construction, see Points, Lines and Planes; for why five robust variants exist at all and the RANSAC/LMedS/MSAC equations behind them, see Estimators (particularly estimators.adoc#non-robust-vs-robust, estimators.adoc#ransac, estimators.adoc#lmeds, estimators.adoc#msac and estimators.adoc#prosac-promeds).

A structural quirk worth flagging up front: unlike Line2D and Plane, there is no non-robust Point2DEstimator/Point3DEstimator class at all — Point2DRobustEstimator/Point3DRobustEstimator are abstract classes with no non-robust sibling, only the five robust wrappers. The minimal-sample closed form (line∩line, or plane∩plane∩plane) is inlined directly inside each concrete RANSACXxx/LMedSXxx/…​ class instead of living in a standalone estimator, exactly as estimators.adoc#non-robust-vs-robust describes for PlaneEstimator (which likewise does not exist as a public class).

Point2D and Point3D: the point that best fits a pencil of lines or planes

Point2DRobustEstimator and Point3DRobustEstimator solve the dual problem to the other two hierarchies below: instead of fitting a line/plane through points, they fit a point through lines/planes. `Point2DRobustEstimator’s own class javadoc reads, verbatim: "This is an abstract class for algorithms to robustly find the best 3D point that intersects in a collection of 2D lines."

That "3D point" is a real, verified copy-paste typo in the source (Point2DRobustEstimator.java:34-37) — the class is unambiguously about Point2D (its estimate() returns Point2D, its MINIMUM_SIZE counts Line2D instances, and `Point3DRobustEstimator’s own javadoc immediately below it correctly says "3D point" for the actual 3D case). It is mentioned here because it is genuinely in the shipped javadoc, not because it changes anything about how the class behaves.

Point2DRobustEstimator Point3DRobustEstimator

Fits

the best 2D point that intersects a collection of Line2D (Point2DRobustEstimator.java:34-38)

the best 3D point that intersects a collection of Plane (Point3DRobustEstimator.java:34-38)

MINIMUM_SIZE

2 lines

3 planes

Closed-form construction

line1.getIntersection(line2) — line∩line meet

plane1.getIntersection(plane2, plane3) — plane∩plane∩plane meet

Concrete subclasses

{RANSAC|LMedS|MSAC|PROSAC|PROMedS}Point2DRobustEstimator

{RANSAC|LMedS|MSAC|PROSAC|PROMedS}Point3DRobustEstimator

The closed-form step is a direct call into the meet operation Points, Lines and Planes already covers under Shared operations: incidence, join, meet: RANSACPoint2DRobustEstimator’s `estimatePreliminarSolutions draws 2 lines from the minimal sample and calls line1.getIntersection(line2) (RANSACPoint2DRobustEstimator.java:254-264, with the actual intersection at line 259); RANSACPoint3DRobustEstimator does the analogous 3-plane version, plane1.getIntersection(plane2, plane3) (RANSACPoint3DRobustEstimator.java:254-265). Both are the same SVD null-space computation used for Line2D.intersection/Plane.intersection — the numerical generalization of the cross-product meet m = l1 × l2.

The residual each robust wrapper scores a candidate point against is not a point-to-point distance — it is the point’s distance to each of the input lines/planes it was not built from, using exactly the signed distance formula already derived on Points, Lines and Planes. Point2DRobustEstimator.residual(Point2D, Line2D) (Point2DRobustEstimator.java:866-871) is:

protected double residual(final Point2D p, final Line2D line) {
    p.normalize();
    line.normalize();
    return Math.abs(line.signedDistance(p));
}

i.e.  — the same Line2D.signedDistance formula Points, Lines and Planes derives from the PhD thesis’s Proof 1.1. Point3DRobustEstimator.residual(Point3D, Plane) (Point3DRobustEstimator.java:865-870) is the 3D analogue, Math.abs(plane.signedDistance(p)), using Plane.signedDistance(Point3D) (Plane.java:515-525) — the same "dot product of homogeneous coordinates, normalized by the coefficient norm" pattern one dimension up, applied to instead of . So a candidate 2D point’s total cost is effectively how far it sits, on average or under a threshold, from every sampled line, not just the two it was built from — exactly the outlier-rejection role estimators.adoc#non-robust-vs-robust describes.

// find the 2D point best explained by a set of (possibly noisy) 2D lines
final var estimator = new RANSACPoint2DRobustEstimator(lines);
estimator.setThreshold(1.0); // 1 pixel, RANSACPoint2DRobustEstimator.DEFAULT_THRESHOLD
final var bestPoint = estimator.estimate();

// the 3D dual: best 3D point explained by a set of 3D planes
final var estimator3D = new RANSACPoint3DRobustEstimator(planes);
estimator3D.setThreshold(1.0); // 1 "voxel", RANSACPoint3DRobustEstimator.DEFAULT_THRESHOLD
final var bestPoint3D = estimator3D.estimate();

Line2D: the line that best fits a set of points

`Line2DRobustEstimator’s own javadoc is exactly the mirror image of the point case above — and correctly worded, unlike `Point2DRobustEstimator’s: "This is an abstract class for algorithms to robustly find the best 2D line that passes through a collection of 2D points."

MINIMUM_SIZE is 2 (Line2DRobustEstimator.java:36). The closed-form step is the join operation Points, Lines and Planes derives as the point-line duality’s cross product, : RANSACLine2DRobustEstimator.estimatePreliminarSolutions (RANSACLine2DRobustEstimator.java:179-189) draws two points from the minimal sample and constructs

final var line = new Line2D(point1, point2, false);

(RANSACLine2DRobustEstimator.java:184). That three-argument constructor delegates to setParametersFromPairOfPoints (Line2D.java:118-120 for the constructor, Line2D.java:330 for the implementation), the same SVD null-space join Points, Lines and Planes describes under Shared operations — the numerical, arbitrary-precision form of l = m1 × m2 that the third noThrow boolean argument guards against throwing a CoincidentPointsException when the two sampled points happen to coincide (the surrounding try/catch at RANSACLine2DRobustEstimator.java:183-188 simply drops that sample and adds no candidate).

The residual is the same signed point-to-line distance used above, just with the roles of point and line swapped: Line2DRobustEstimator.residual(Line2D, Point2D) (Line2DRobustEstimator.java:722-727) is

protected double residual(final Line2D l, final Point2D point) {
    l.normalize();
    point.normalize();
    return Math.abs(l.signedDistance(point));
}

 — literally Line2D.signedDistance(Point2D) (Line2D.java:460), the exact formula Points, Lines and Planes derives via Proof 1.1 of the PhD thesis (projecting onto the line’s director vector). This is the cleanest instance of the pattern in this whole page: the non-robust algorithm (l = m1 × m2) and the residual are both operations Points, Lines and Planes already fully derives — Line2DRobustEstimator and its five concrete subclasses contribute nothing mathematically new, only the sampling/scoring loop from estimators.adoc#shared-architecture.

// find the 2D line best explained by a noisy set of 2D points
final var estimator = new RANSACLine2DRobustEstimator(points);
estimator.setThreshold(1.0); // 1 pixel, RANSACLine2DRobustEstimator.DEFAULT_THRESHOLD
final var bestLine = estimator.estimate();

Plane: the plane that best fits a set of points

`PlaneRobustEstimator’s javadoc reads: "This is an abstract class for algorithms to robustly find the best 3D plane that passes through a collection of 3D points."

MINIMUM_SIZE is 3 (PlaneRobustEstimator.java:36). The closed form is the 3D join Points, Lines and Planes derives from the 4×4-determinant/Laplace-expansion argument: any point coplanar with three others makes a 4×4 coordinate matrix singular, and that matrix’s null-space is the plane’s homogeneous coefficients. RANSACPlaneRobustEstimator.estimatePreliminarSolutions (RANSACPlaneRobustEstimator.java:179-190) draws three points from the minimal sample and constructs

final var plane = new Plane(point1, point2, point3);

(RANSACPlaneRobustEstimator.java:185), catching ColinearPointsException when the three sampled points happen to be collinear (no plane, so no candidate is added for that sample). This constructor is Plane’s "join" analogue to `Line2D.setParametersFromPairOfPoints — the same SVD null-space technique, one dimension up, that Points, Lines and Planes attributes to Plane.setParametersFromThreePoints under Shared operations.

The residual is the point-to-plane signed distance: PlaneRobustEstimator.residual(Plane, Point3D) (PlaneRobustEstimator.java:722-727) is

protected double residual(final Plane plane, final Point3D point) {
    plane.normalize();
    point.normalize();
    return Math.abs(plane.signedDistance(point));
}

i.e. Plane.signedDistance(Point3D) (Plane.java:515-525), the 3D point-plane-duality analogue ( ) of the 2D signed distance Points, Lines and Planes derives in full for the point-line case — the library does not re-derive a separate proof for the plane case in the PhD thesis, but the formula (dot product of homogeneous coordinates over the coefficient vector’s norm) is structurally identical.

// find the 3D plane best explained by a noisy set of 3D points
final var estimator = new RANSACPlaneRobustEstimator(points);
estimator.setThreshold(1.0); // 1 "voxel", RANSACPlaneRobustEstimator.DEFAULT_THRESHOLD
final var bestPlane = estimator.estimate();

Shared configuration and what the five variants buy you here

All four abstract classes above (Point2DRobustEstimator, Point3DRobustEstimator, Line2DRobustEstimator, PlaneRobustEstimator) expose exactly the shared properties estimators.adoc#shared-architecture's table describes generically — MINIMUM_SIZE, confidence (DEFAULT_CONFIDENCE = 0.99), maxIterations (DEFAULT_MAX_ITERATIONS = 5000), progressDelta and a listener — and none of them implement any sampling or scoring logic themselves: every concrete RANSACXxx/LMedSXxx/MSACXxx/PROSACXxx/PROMedSXxx class hands its estimatePreliminarSolutions/computeResidual pair straight to com.irurueta.numerical.robust’s generic `RANSACRobustEstimator<T>, LMedSRobustEstimator<T>, etc., exactly as estimators.adoc#shared-architecture describes for all twelve hierarchies. Point2DRobustEstimator and Point3DRobustEstimator additionally carry a refineResult/refinementCoordinatesType/keepCovariance trio (defaulting to Levenberg-Marquardt refinement over the final inlier set, homogeneous or inhomogeneous) that Line2DRobustEstimator and PlaneRobustEstimator do not expose — the latter two return their robust result directly with no separate refinement step.

What differs between the five variants is exactly what Estimators describes in the abstract, and it is worth making concrete for this specific line/point/plane fitting problem rather than repeating the formulas again:

  • RANSAC/MSAC need a threshold (DEFAULT_THRESHOLD = 1.0 for every one of the ten concrete classes on this page, documented as "1 pixel" for the 2D hierarchies and "1 voxel" for the 3D ones). Fitting a 2D line to a real, noisy point cloud with, say, 1-pixel Gaussian localization error and a handful of gross mismatches, a threshold around 1-2 pixels (estimators.adoc#ransac's for 1 degree of freedom) correctly separates inliers from outliers; setting it too tight starts rejecting genuine inliers as noise pushes them just past the boundary, too loose lets outliers vote for a biased line.

  • LMedS needs no threshold at all — useful exactly when that per-image-source pixel/voxel noise level is unknown — but only while under half the points are outliers; past that, the median residual is itself an outlier’s residual and LMedSLine2DRobustEstimator/LMedSPlaneRobustEstimator degrade, whereas RANSACLine2DRobustEstimator with a well-chosen threshold keeps working.

  • PROSAC/PROMedS need a double[] qualityScores, one entry per line/point/plane (e.g. PROSACLine2DRobustEstimator(List<Point2D> points, double[] qualityScores)), and simply try high-quality-first minimal samples before falling back to RANSAC’s/LMedS’s own scoring — for a line fit from a feature tracker’s point correspondences, feeding the tracker’s own per-point confidence directly in as qualityScores converges to the right line in far fewer of the maxIterations than uniform-random sampling would need.

The number of samples needed for a given confidence still follows estimators.adoc#ransac's eq. 4.18 directly from MINIMUM_SIZE: at s = 2 (Line2D, Point2D) a 99%-confidence RANSAC run needs far fewer trials for a given outlier ratio than the s = 3 case (Plane, Point3D) or the larger-sample hierarchies on Conic and Quadric Estimators/Pinhole Camera Estimators — these three hierarchies are, sample efficiency-wise, the cheapest robust fits in the whole library.

References

No new book or paper citation is introduced on this page. All of the mathematics is either already derived on Points, Lines and Planes (the join/meet cross products behind line1.getIntersection(line2), plane1.getIntersection(plane2, plane3), new Line2D(point1, point2, false), new Plane(point1, point2, point3), and the signed point-to-line distance behind every residual() method above, including its 3D point-to-plane analogue) or already derived on Estimators (the RANSAC/LMedS/MSAC/PROSAC/PROMedS scoring rules and sample-count formula, Hartley & Zisserman chapter 4 and Irurueta’s PhD thesis §2.5). Everything specific to this page — MINIMUM_SIZE values, the exact estimatePreliminarSolutions/computeResidual code, the Point2DRobustEstimator javadoc typo, DEFAULT_THRESHOLD values — is drawn directly from the library’s own source rather than from any of the three source PDFs.

Key classes

The classes exercised by the code examples above, with links to their source and Javadoc:

Class Links

Point2DRobustEstimator

Source
Javadoc

RANSACPoint2DRobustEstimator

Source
Javadoc

Point3DRobustEstimator

Source
Javadoc

RANSACPoint3DRobustEstimator

Source
Javadoc

Line2DRobustEstimator

Source
Javadoc

RANSACLine2DRobustEstimator

Source
Javadoc

PlaneRobustEstimator

Source
Javadoc

RANSACPlaneRobustEstimator

Source
Javadoc

Line2D

Source
Javadoc

Plane

Source
Javadoc