surface opzscan → depthimport fullseye as fs; fs.ledger.csi_height_map(stack, z_step_um=0.05, z_start_um=0.0, wavelength_um=0.6, mode='gaussian', remove_bias=True, min_visibility=0.3, max_edge_envelope=0.05, carrier_tolerance=2.0, on_invalid='raise', fill_value=nan) (実装を直接呼ぶなら import interferometry; interferometry.csi_height_map(stack, z_step_um=0.05, z_start_um=0.0, wavelength_um=0.6, mode='gaussian', remove_bias=True, min_visibility=0.3, max_edge_envelope=0.05, carrier_tolerance=2.0, on_invalid='raise', fill_value=nan)、台帳から引くなら opsinterferometry.get("csi_height_map"))Height map from a (Z, H, W) coherence-scanning stack — the CSI inversion.
The per-pixel :func:csi_peak_position, vectorised. The scan axis is
first; see :func:csi_stack_simulate for why that is checked rather than
inferred.
A pixel is invalid when any of three things is true, and all three are the same trap in different shapes — each would otherwise yield a finite, plausible, wrong height:
_edge_level.What happens then is a decision, not a default:
on_invalid="raise" (the default) — raise, naming how many pixels
failed which of the three checks. Fail-closed: a height map with silently
wrong pixels in it is worse than no height map.on_invalid="fill" — write fill_value (default NaN) at those pixels
and return. Opt in to this when you intend to mask afterwards; a NaN
height poisons every downstream reduction, which is precisely why it is
not the default.There is deliberately no third option that quietly reports the boundary plane.
Returns a float64 (H, W) height map, in the units of z_start_um /
z_step_um.
Ground truth (measured, 32x32 pixels, 241 planes x 0.05 um, 0.60 um
wavelength, 2.83 um envelope FWHM). On a tilted plane spanning 5.0-7.0 um,
i.e. comfortably inside a 0-12 um scan, the RMS height error is 1.42e-02 um
for "peak", 3.81e-05 um for "centroid", 4.02e-06 um for
"parabolic" and 2.08e-06 um for "gaussian". Widen the same plane to
2.0-10.0 um — pixels now within 2 um of the ends of the scan — and the
errors become 1.91e-02 / 5.98e-02 / 7.06e-03 / 7.06e-03 um: the local fits
lose three decades and the centroid loses four, entirely to envelope
truncation at the scan ends. Accuracy here is a property of the scan layout,
not of the estimator, and this is the number to look at when a real
measurement disappoints.
On that same surface, phase-shifting interferometry via :mod:fringe is exact
below a lambda/4 = 0.15 um step and wrong by exact multiples of
lambda/2 = 0.30 um above it.
Raises ValueError: a non-3-D stack, fewer than 3 planes, an empty
spatial extent, a stack over :data:MAX_STACK_ELEMENTS (checked before the
float64 promotion), a non-finite / complex / masked stack, an unknown mode
or on_invalid, a min_visibility / max_edge_envelope outside [0, 1],
a z_step_um at or past the wavelength_um/4 Nyquist ceiling, a
non-numeric fill_value, and — under the default on_invalid="raise" —
any invalid pixel.
py -3.11 examples/coherence_scanning.pypy -3.11 examples/poc_focus_stacking.pypy -3.11 examples/poc_interferometry_step.pydepth を入力に取れる)surface)Provenance: interferometry.py — INTERFEROMETRY operator registry. この per-op ノートは tools/opdocs.py md が自動生成(手編集しない)。
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.