estimate_point_normals — 3D transform op

• Data kinds: points → normals

• Call: import fullseye as fs; fs.ledger.estimate_point_normals(points, k=16, viewpoint=None) (to call the implementation directly, import match3d; match3d.estimate_point_normals(points, k=16, viewpoint=None); from the registry, ops3d.get("estimate_point_normals"))

Usage

Point set (N,3) → unit normals (the smallest eigenvector of the local k-neighbourhood covariance = PCA).

Generates the normals that FPFH/SHOT/point-to-plane ICP need from a raw point cloud. There are 2 orientation conventions:

viewpoint=None (default) = outward from the centroid (for all-round point clouds of closed objects) / viewpoint given = towards the viewpoint (sensor) (Hoppe 1992 / PCL convention. For a single-viewpoint scan, the visible surface facing the sensor side is physically correct. Same convention as pointcloud.estimate_normals). The old version (up to 2026-08-30) used the "away from the viewpoint" sign even with a viewpoint given, so in its intended use, single-viewpoint scans, every point was flipped. Returns normals (N,3).

Procedure: cKDTree takes the k nearest neighbours of each point (including the point itself; truncated to N if k > N), and the smallest eigenvector of their covariance becomes the normal. Returns (N,3) float64 unit vectors. viewpoint is a 3-dimensional coordinate (sensor position). If the neighbour count min(k, N) is below 3 (only 1-2 points, or k < 3), ValueError —— a plane is undetermined with fewer than 3 points (with 1 point not even a covariance can be formed; until 2026-10-07 it crashed with an internal einsum error). If the neighbourhood is collinear, the normal is returned undetermined (no check). A small k is sensitive to noise, a large one rounds off corners.

Downstream: dst_normals of icp_point2plane, normals for render_shaded, normals_to_egi. Same convention as pointcloud.estimate_normals (ledger estimate_normals).

References (sample data, literature)

• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).

• Operator provenance and references — the sources of the research/methods this op family came from.

Runnable examples (verified samples that actually call this op)

• fpfh_correspondence — py -3.11 examples_3d/fpfh_correspondence.py

Ops the type connects to (they accept normals as input)

icp_point2plane · compute_fpfh · shot_descriptor · fuse_to_voxel · reflect · refract · normal_consistency · ransac_cylinder

Same category (transform)

points_to_voxel · gaussians_to_voxel · mesh_to_voxel · mesh_to_points · depth_to_points · voxel_to_mips · voxel_to_mesh · tsdf_from_depth


*Provenance: match3d.py — 3D operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.