Skip to content

SVR 3D viewer: memory safety + offline tumor segmentation (ONNX)#5

Open
blader wants to merge 16 commits intomainfrom
svr-frontend-plan
Open

SVR 3D viewer: memory safety + offline tumor segmentation (ONNX)#5
blader wants to merge 16 commits intomainfrom
svr-frontend-plan

Conversation

@blader
Copy link
Owner

@blader blader commented Feb 2, 2026

Summary

This PR hardens the SVR 3D volume workflow for power-user (large maxVolumeDim) cases by reducing peak allocations, making GPU usage budget-aware, and tightening segmentation tooling so it fails safely instead of crashing the tab.

It also upgrades seeded 3D region-growing segmentation to be interactive (live tolerance preview + ROI guidance), so you can iterate quickly without committing labels on every slider tweak.

Key user-visible changes:

  • The 3D viewer now has a GPU-budgeted render LOD path (Auto) that can downsample render textures to fit a configurable budget.
  • Label rendering no longer allocates full-size zero buffers when labels are disabled.
  • Seeded 3D region grow no longer allocates a full-volume mask.
  • Seeded 3D region grow now supports auto-preview updates (debounced + cancellable) while adjusting tolerance/target, and supports an ROI box (guide or hard) drawn on the slice inspector.
  • ONNX tumor segmentation is preflight-guarded for huge volumes (blocked by default with an explicit unsafe override).
  • The legacy SVR 3D modal is now a thin wrapper around the shared 3D viewer so improvements apply everywhere.

What’s in this PR

SVR + 3D viewer memory/stability

  • GPU-budgeted render LOD (Auto quality): compute a render plan that chooses render dims + texture mode (f32 vs u8) to fit a budget.
  • Label texture allocation is lazy: keep a 1×1×1 placeholder texture when labels are disabled/missing; allocate full 3D label texture only when needed.
  • Downsample labels for rendering when render LOD is active (nearest) so label overlays don’t force full-res GPU allocations.
  • Single code path for 3D viewing: SvrVolume3DModal now renders SvrVolume3DViewer instead of maintaining a separate WebGL implementation.

Interactive seeded 3D region growing (seed + live tolerance + ROI)

  • Slice inspector interactions:
    • Click to set the seed voxel.
    • Drag to draw an ROI box (interpreted as an axis-aligned 3D box spanning the full depth along the current inspector axis).
  • Controls:
    • Auto preview toggle.
    • ROI mode selector: guide (default) vs hard.
    • Outside scale slider (enabled in guide mode) to tighten tolerance outside the ROI.
    • Target label + tolerance changes trigger auto-preview re-grows (debounced; in-flight grows are cancelled for responsiveness).
  • Clear seed / clear seg cancels in-flight grows and resets preview bookkeeping.

regionGrow3D updates

  • Sparse: regionGrow3D() returns a Uint32Array of voxel indices and uses a 1-bit visited bitset (avoids Uint8Array(nvox) masks).
  • Multi-seed: added optional seedIndices?: Uint32Array so users can grow multiple disjoint islands in one operation.
  • ROI support: added optional roi?: { min/max, mode: "hard" | "guide", outsideToleranceScale? }:
    • hard: never accepts voxels outside ROI.
    • guide: accepts outside ROI only if the intensity falls within a tighter (seed-centered) range derived from outsideToleranceScale.
  • Added unit coverage for ROI hard/guide + multi-seed behavior (tests/segmentation3d.test.ts).

ONNX preflight guardrail

  • Full-res ONNX runs are blocked by default when the estimated logits tensor size exceeds a conservative budget. Users can opt in via an “unsafe full-res ONNX” checkbox.
  • This prevents accidental multi-hundred-MiB to multi-GiB allocations on large volumes.

Tooling

  • Added Prettier (config + scripts) for consistent formatting:
    • npm run prettier / npm run prettier:check

Implementation notes

Render LOD plumbing

  • Render planning + resampling utilities were factored into frontend/src/utils/svr/renderLod.ts.
  • The viewer builds a render texture payload via a single helper (buildRenderVolumeTexData) with periodic yields for responsiveness.

regionGrow3D memory model

  • Prior implementation allocated mask = new Uint8Array(nvox).
  • New implementation:
    • visited: Uint32Array((nvox + 31) >>> 5) (1 bit/voxel)
    • queue: Uint32Array(maxVoxels) which is also returned as indices.subarray(0, count)
    • Viewer applies the label by iterating the sparse indices list.

Live preview label overlay

  • The viewer keeps a single working labels buffer and replaces the previous preview by restoring a sparse list of previous values (prevIndices + prevValues) before applying the next preview.
  • This avoids copying a full Uint8Array(nvox) per slider move.

ONNX preflight

  • Preflight uses a lower-bound estimate (float32 logits with C=4 channels) and blocks by default above a conservative logits budget.
  • This is intentionally strict for stability; users can re-run SVR at lower resolution/ROI, or opt into unsafe full-res ONNX.

How to test

From frontend/:

  • npm run lint
  • npm run test

Manual (SVR 3D viewer):

  • Open the 3D viewer and expand the Segmentation panel.
  • Click in the slice inspector to place a seed.
  • With Auto preview enabled, adjust tolerance/target and confirm the segmentation updates.
  • Drag an ROI box; try guide vs hard modes; adjust outside scale and confirm it controls leakage outside the ROI.

Notable unit coverage includes:

  • 3D segmentation utils (tests/segmentation3d.test.ts)
  • ONNX wrappers (tests/onnxTumorSegmentation.test.ts, tests/onnxLogitsToLabels.test.ts)

@vercel
Copy link

vercel bot commented Feb 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
miraviewer Ready Ready Preview, Comment Feb 4, 2026 5:26am

Request Review

…arate modules

This refactoring improves the SVR codebase by:

1. Creating svrUtils.ts - shared utility functions:
   - clamp01: Clamps values to [0,1] range
   - assertNotAborted: Checks abort signal for cancellation
   - yieldToMain: Yields control for UI responsiveness
   - withinTrilinearSupport: Bounds checking for trilinear interpolation
   - clampAbs: Clamps absolute values with NaN handling
   - formatMiB: Human-readable byte formatting
   - quantileSorted: Quantile computation from sorted arrays

2. Creating rigidRegistration.ts - well-documented rigid registration module:
   - Full JSDoc documentation explaining the algorithm
   - Exported types: Mat3, RigidParams, SeriesSamples, BoundsMm, LoadedSlice
   - Matrix utilities: mat3FromEulerXYZ, mat3MulVec3
   - Transform functions: applyRigidToPoint, applyRigidToSeriesSlices
   - Registration scoring: scoreNcc (Normalized Cross-Correlation)
   - Optimization: optimizeRigidNcc (multi-scale coordinate descent)
   - Main function: rigidAlignSeriesInRoi

3. Updating reconstructionCore.ts to use shared utilities:
   - Imports from svrUtils.ts instead of local definitions
   - Reduces code duplication

4. Adding comprehensive test coverage (15 new tests):
   - mat3FromEulerXYZ: identity, 90° rotations, orthonormality
   - applyRigidToPoint: identity, translation, rotation, combined
   - boundsCenterMm: positive and negative coordinates
   - scoreNcc: empty samples, insufficient samples, perfect correlation
@blader blader changed the title SVR tooling: reconstruction + 3D volume viewer SVR tooling + offline tumor segmentation (ONNX + edit + export) Feb 2, 2026
@blader blader changed the title SVR tooling + offline tumor segmentation (ONNX + edit + export) SVR 3D viewer: memory safety + offline tumor segmentation (ONNX) Feb 3, 2026
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