moment_invariants — 3D moment_invariant op

• Data kinds: points → descriptor

• Call: import fullseye as fs; fs.ledger.moment_invariants(points) -> 'np.ndarray' (to call the implementation directly, import moments3d; moments3d.moment_invariants(points) -> 'np.ndarray'; from the registry, ops3d.get("moment_invariants"))

Usage

A shape feature vector invariant to translation, rotation and scale (Sadjadi–Hall style, plus higher-order radial distributions).

★The input is an (N,3) point cloud. When you want quantities of the same kind from a 2-D region (image), use the HALCON-style moments_region_2nd_invar / moments_region_central_invar / moments_region_3rd_invar (Hu moments) instead of this op. The names are similar and easy to mix up; passing (H,W) fails with "points must be a point cloud of shape (N,3)" (2026-09-09, actually hit while writing poc_rotation_invariance_audit).

Recipe:

1. Centroid centring (removes translation).

2. Scale normalisation by dividing by the RMS radius R = sqrt(mean‖p-c‖²) (R→1). After this, the normalised central 2nd-order moments do not depend on a uniform scale s.

3. List the principal invariants (coefficients of the characteristic polynomial) of the normalised covariance C̃:

λ̂1 >= λ̂2 >= λ̂3 … eigenvalues of C̃ (= normalised principal 2nd-order moments,

Σλ̂ = 1, rotation invariant)

J2 = λ̂1λ̂2 + λ̂1λ̂3 + λ̂2λ̂3 (Sadjadi–Hall 2nd invariant = sum of 2×2 principal minors)

J3 = λ̂1λ̂2λ̂3 (3rd invariant = det C̃)

4. Normalised 4th-order radial moment m4 = mean(‖p̂-c‖⁴) (= mean(r⁴)/mean(r²)²). r = distance from the centroid, so it is rotation + translation invariant, and scale invariant after RMS normalisation.

The returned vector is [λ̂1, λ̂2, λ̂3, J2, J3, m4] (length 6). The 1st invariant J1 = Σλ̂ is always 1 after normalisation and does not help discrimination, so it is omitted. J2,J3 are symmetric functions of the eigenvalues (redundant), but are included for compatibility with the Sadjadi–Hall algebraic invariant signature.

Breakdown of discriminative power (honest):

• λ̂1,λ̂2,λ̂3 (and the symmetric functions J2,J3) derive only from the 2nd-order moments (covariance eigenvalues), and have only 2 independent degrees of freedom, the principal-axis aspect ratios. With these alone, shapes whose 2nd order is isotropic (solid cube and solid sphere both have λ̂≈(1/3,1/3,1/3)) cannot be distinguished.

• m4 is the 4th-order moment of the radial distribution, and captures higher-order shape differences that collapse at 2nd order. A uniform solid sphere has m4=75/63≈1.190 and a uniform solid cube has m4=19/15≈1.267, which differ, so the two can be separated.

A sphere gives roughly (1/3, 1/3, 1/3, 1/3, 1/27, 1.190), and a long thin rod approaches (≈1, ≈0, ≈0, ≈0, ≈0, large).

Returns

np.ndarray, shape (6,)

Feature vector invariant to translation, rotation and scale.

Notes:

• Input is (N,3), N >= 2. Invalid shape, non-finite values or all points coincident (spread of 0 after centring) raise ValueError. The degeneracy test is scale-relative (rms <= 1e-12 × max|centered|), so a point cloud whose coordinates are merely tiny is not rejected.

• Returns float64 (6,). λ̂ is clipped at 0, Σλ̂ = 1.

• It is invariant only to translation, rotation and uniform scale. It is also invariant to reflection (mirroring) (eigenvalues and the radial distribution do not change under reflection), so mirror images cannot be distinguished. Non-uniform scale and bias in point density (dense/sparse sampling) change the values.

• For uses sensitive to point density, even out the density beforehand with voxel_grid_downsample. For comparison use shape_distance (ledger op, distance between descriptor vectors of the same length).

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)

• moment_invariants — py -3.11 examples_3d/moment_invariants.py

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

fuse_to_voxel · shape_distance

Same category (moment_invariant)

principal_moments · central_moments · inertia_tensor


*Provenance: moments3d.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.