Skip to content

feat(mosaic): LiveStitch placement + smart canvas management#40

Merged
Garrett Bischof (gwbischof) merged 3 commits into
mainfrom
h3/livestitch-canvas
Jun 8, 2026
Merged

feat(mosaic): LiveStitch placement + smart canvas management#40
Garrett Bischof (gwbischof) merged 3 commits into
mainfrom
h3/livestitch-canvas

Conversation

@gwbischof

@gwbischof Garrett Bischof (gwbischof) commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

H3 of the #37 decomposition. Switches the live ViT mosaic from Fourier-shift stitching to LiveStitch (nearest-integer + bbox) and adds the canvas-management fixes from #37. SaveViTResult/MosaicWriterOp are lifted verbatim from #37 (the proven live-mosaic code), re-pointed at ptychoml.stitch per H1.

Changes (vit_inference.py, ptycho_holo.py, mosaic_canvas.py)

  • LiveStitch hot pathSaveViTResult uses ptychoml.stitch.stitch_batch_livestitch_into (nearest-integer placement, returns the touched bbox) instead of stitch_batch_into.
  • Staircase fixMosaicWriterOp writes the full cumulative canvas every batch (latest-wins, capacity-1 + drop policy), not just the bbox. _normalise_full returns (fill_value, array); _normalise_sub removed.
  • Centring bias fix — when the observed range is < 50% of commanded (slow axis hasn't moved when the canvas is first sized), infer the scan direction and centre on the commanded midpoint. Extracted to holoptycho/mosaic_canvas.estimate_canvas_mid so it's unit-testable without the Tiled-bound vit_inference import.
  • NaN-position race fix — ViT batches whose positions are still NaN (position stream lagging) are buffered in _pending_frames and re-stitched once positions arrive, instead of dropped (cap 500).
  • New knobspatch_flip (D4 per patch via ptychoml.apply_d4, default identity), mosaic_min_overlap (0.5), canvas_pad default 64 → 0.

Scope boundary

Only the SaveViTResult/MosaicWriterOp (mosaic) changes. The PtychoViTInferenceOp changes from #37 — orientation autodetect (H5) and ONNX inner-crop / vit-only mode (H4) — are deliberately not here.

Faithful-to-#37 quirks (kept, not changed)

  • The start() warm-up calls stitch_batch_nearest while the hot path is stitch_batch_livestitch_into — harmless (both pure numpy, nothing to JIT).
  • fourier_pad is now an unused vestigial param.

Flagging rather than "fixing" them, since #37 is the working reference.

Tests

tests/test_mosaic_canvas.py covers estimate_canvas_mid (observed-midpoint when well-covered or commanded unknown; direction-inferred midpoint for under-scanned + / − / flat). Stitching itself is covered by ptychoml. The SaveViTResult/MosaicWriterOp operators run only in the live pipeline (per memory, not worth fighting the Tiled/Holoscan harness to exercise).

pixi run test   # 71 passed; the 2 vit_inference/ptycho_holo smoke failures are
                # pre-existing (module load needs a reachable TILED_BASE_URL).

Depends on

NSLS2/ptychoml#11 (merged) — MosaicWriterOp now imports ptychoml.stitch.normalize_mosaic instead of an inline _normalise_full (verified bit-identical). pixi.lock bumped accordingly.

Switch SaveViTResult from the Fourier-shift stitcher to
ptychoml.stitch.stitch_batch_livestitch_into (nearest-integer placement that
returns the touched bbox), and harden the live mosaic:

- MosaicWriterOp writes the full cumulative canvas every batch (latest-wins,
  capacity-1 + drop policy) instead of bbox-only patches — fixes the
  staircase artifact on unidirectional scans. _normalise_full now returns
  (fill_value, array) and _normalise_sub is removed.
- Smart canvas centering: when the observed range is < 50% of commanded (the
  slow axis has barely moved when the canvas is first sized), infer the scan
  direction and centre on the commanded midpoint instead of the biased
  observed one. Extracted to holoptycho/mosaic_canvas.estimate_canvas_mid so
  it's unit-testable without the Tiled-bound vit_inference import.
- Pending-frame buffer: ViT batches whose scan positions are still NaN (the
  position stream lagging the ViT stream) are buffered and re-stitched once
  positions arrive, instead of dropped (cap 500).
- New knobs: patch_flip (D4 on each patch via ptychoml.apply_d4, default
  identity), mosaic_min_overlap (default 0.5), canvas_pad default 64 -> 0.

SaveViTResult/MosaicWriterOp are lifted from PR #37 verbatim (the proven
live-mosaic code), re-pointed at ptychoml.stitch (per H1). Two faithful
pre-existing quirks kept as-is: the start() warm-up calls stitch_batch_nearest
while the hot path is livestitch (harmless, both pure numpy), and fourier_pad
is now an unused vestigial param.

H3 of the #37 decomposition. Stitching correctness is covered
by ptychoml; the new holoptycho centering logic is tested in
tests/test_mosaic_canvas.py.

Co-authored-by: Himanshu Goel <4122621+himanshugoel2797@users.noreply.github.com>
…rmalise_full

ptychoml#11 added normalize_mosaic (the averaging companion to the stitch
accumulators). Replace MosaicWriterOp's inline _normalise_full with it and
bump the ptychoml pin. Verified bit-identical to the inline version across
random (canvas, counts) inputs, so no behavior change.

Co-authored-by: Himanshu Goel <4122621+himanshugoel2797@users.noreply.github.com>
The NaN-position race handling (buffer ViT frames whose scan positions
haven't arrived yet, re-merge once they do) was the most complex untested
piece of H3. Extract the partition step into a pure
mosaic_canvas.partition_pending (behavior-identical to the prior inline
double list-comprehension, and evaluates the finite-position check once per
frame instead of twice) and cover it in tests/test_mosaic_canvas.py:
all-ready, all-waiting-on-NaN, mixed + order preservation, out-of-range
index, partial-NaN row, patch-travels-with-index, and empty input.

Co-authored-by: Himanshu Goel <4122621+himanshugoel2797@users.noreply.github.com>
@gwbischof Garrett Bischof (gwbischof) merged commit 8fbe936 into main Jun 8, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant