fit_zernike — 3D curvilinear op

• Data kinds: image2d → table

• Call: import fullseye as fs; fs.ledger.fit_zernike(disk_image, n_max=6, device='cpu', nr=48, nt=72, center=None, radius=None) (to call the implementation directly, import match3d; match3d.fit_zernike(disk_image, n_max=6, device='cpu', nr=48, nt=72, center=None, radius=None); from the registry, ops3d.get("fit_zernike"))

• GPU: this op has a GPU path (device="cuda")

Usage

A disc image → Zernike coefficients (the polar-coordinate surface fit of optics and wavefront metrology). Returns {(n,m): coef}.

Reduces a surface on a disc (wavefront aberration, lens shape) to a few coefficients with orthogonal polynomials. tilt/defocus/astigmatism/ coma/spherical etc. correspond to specific (n,m), and rotation mixes m (band = rotation invariant).

The pupil (unit disc ρ=1) is placed by default at the image centre ((H-1)/2, (W-1)/2) with radius min(H, W)/2 - 1 pixels. If the pupil in the image differs from this, pass center=(row, col) and radius (pixels) —— if you do not, the radius mismatch leaks directly into the low-order modes (reading a pure defocus with pupil radius (H-1)/2 at 129×129 with the defaults gives (2,0)=0.984 / (0,0)=−0.015; passing radius=(H-1)/2 gives 0.999999). A center / radius whose pupil circle sticks out of the image is a ValueError.

Honest disclosure (corrected 2026-10-07): this used to say "crosstalk of up to ~10% from discrete sampling (nr=48, nt=72); raising nr/nt reduces it", but the cause was not the resolution. If the pupil radius and centre match and the image continues beyond the pupil, the coefficients return to almost 1 (0.999999 at 129×129) with the default nr/nt. The actual causes of the leakage are

(1) the pupil radius/centre mismatch above (raising nr/nt does not reduce it by even 1 order of magnitude), and (2) in images that are 0 outside the pupil,

the outermost ring (ρ=1) sits on the edge and bilinear interpolation sucks in the 0 outside (measured in examples/poc_zernike_aberrations.py).

Raises ValueError: input not 2-D, smaller than 2x2, NaN/Inf/float32 overflow, or the pupil sticking out of the image.

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)

• curvilinear_proj — py -3.11 examples_3d/curvilinear_proj.py

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

fuse_to_voxel · mesh_select_lod

Same category (curvilinear)

polar_unwrap · cylinder_unwrap


*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.