Skip to content

feat(napari): add registration panel#216

Open
sdiebolt wants to merge 77 commits into
mainfrom
feat/napari-registration
Open

feat(napari): add registration panel#216
sdiebolt wants to merge 77 commits into
mainfrom
feat/napari-registration

Conversation

@sdiebolt

@sdiebolt sdiebolt commented Jun 26, 2026

Copy link
Copy Markdown
Member

This PR adds a new napari Registration tab for between-scan and within-scan workflows. It supports live previews and progress reporting, cooperative aborts with partial results, transform save/load/apply flows (including manual napari transforms and B-spline control-point grids via Zarr), and the registration parameter controls needed to run the existing ConfUSIus registration backends from the GUI.

Closes #210.
Closes #213.

sdiebolt added 17 commits June 3, 2026 16:18
Add a napari-native progress reporter that streams the resampled
moving image into a live Image layer, complementing the existing
matplotlib plotter.

- register_volume gains a progress_plotter factory argument; when
  show_progress=True, the factory is used in place of the matplotlib
  default. The matplotlib path is unchanged.
- New NapariVolumeProgress plotter + NapariProgressBridge (Qt signal
  bridge) live in confusius._napari._registration._progress. The
  bridge routes per-iteration resampled arrays from the worker
  thread to the GUI thread via a queued connection, so the layer
  can be mutated safely.
- RegistrationPanel._setup_volume_progress wires the panel: the
  fixed layer is tinted red, the moving layer is tinted cyan and
  hidden, and the preview is seeded with the moving image resampled
  onto the fixed grid (identity transform) so the first frame is a
  meaningful unaligned view. Iterations overwrite the preview in
  place. On teardown, the moving layer stays hidden and the preview
  is removed so the final result layer replaces it without leaving
  duplicates.
Add a per-iteration optimizer-metric curve to the registration
progress overlay so users can watch convergence alongside the
red/cyan resampled preview.

- NapariProgressBridge gains a metric_updated(float) signal; the
  worker-side NapariVolumeProgress.update() emits the current
  metric value on every iteration (gated on plot_metric so the
  matplotlib path stays unchanged).
- New RegistrationMetricPlotter widget in
  confusius._napari._registration._metric_plotter renders the
  curve in a bottom-docked matplotlib canvas with a navigation
  toolbar. Rapid iteration events are coalesced through a 16 ms
  QTimer so the canvas redraws at most once per frame.
- RegistrationPanel._ensure_metric_plotter lazily creates and
  docks the widget (mirroring SignalPanel's lazy-dock pattern,
  including the HiDPI click-offset workaround). The plotter is
  reused across runs and reset per run; the dock is kept after
  teardown so the user can inspect the final convergence trace.
- Tests cover the buffer, the 16 ms redraw throttling, the
  plot_metric=False suppression, and the panel-level dock
  creation + bridge wiring.
@sdiebolt sdiebolt requested a review from FelipeCybis June 26, 2026 22:28
@sdiebolt sdiebolt self-assigned this Jun 26, 2026
@sdiebolt sdiebolt added enhancement New feature or request bug Something isn't working labels Jun 26, 2026
@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

sdiebolt and others added 8 commits June 27, 2026 11:22
Clicking abort during within-scan (volumewise) registration froze the GUI
on Windows and never actually cancelled the remaining work. After the abort
event was set, every remaining frame was still dispatched through
register_volume, which only skips SimpleITK's Execute() — the one step that
releases the GIL. The leftover pure-Python/numpy setup and a wasted resample,
multiplied across joblib threads, monopolised the GIL and starved the Qt main
thread (worse on Windows, where GIL hand-off to a waiting thread is far less
fair than on Linux), so the GUI only unfroze once all frames had been
computed.

- Short-circuit _register_one before calling register_volume once aborted,
  returning the original frame with a zero-iteration "aborted" diagnostic.
- Stop dispatching new frames to joblib once the abort event is set.
- Fill aborted/un-started frames with the data minimum (background) instead
  of the unregistered input, so the partial result shows which frames were
  skipped, matching the live preview.
sdiebolt and others added 28 commits July 1, 2026 12:14
Rename the volumewise 'Ref. time' label to 'Reference volume' to match
its spinbox behaviour (clamped to the moving layer's time dimension) and
update the related tooltip and docs copy.

Constrain the width of the reference-volume, learning-rate, and
iterations spinboxes so they don't stretch and align with the rest of
the form fields. In the signals panel, regroup the y min/max spinboxes
on a single row and tighten their width.
…sforms

Rename the remaining noun-style transform helpers to imperative verb
phrases for consistency with the project convention:

- affine_transform_from_payload -> get_affine_transform_from_payload
- bspline_transform_from_payload -> get_bspline_transform_from_payload
- output_grid_from_payload -> get_output_grid_from_payload
- _affine_payload_from_layer -> _get_affine_payload_from_layer
- _spatial_manual_affine_from_layer -> _get_spatial_manual_affine_from_layer

Merge _transforms.py into _panel_transform_helpers.py. The split was
arbitrary: all transform-payload TypedDicts, construction, deserialization,
and I/O helpers, plus the layer-specific helpers, are used exclusively by
the napari registration panel. The merged module removes a cross-import
and an unneeded module boundary.
Rename the remaining noun-style panel utility helpers to imperative verb
phrases for consistency with the project convention:

- _default_dims_for_ndim -> get_default_dims_for_ndim
- _layer_supports_registration_source -> is_registration_source_layer
- _image_display_kwargs_from_layer -> get_image_display_kwargs_from_layer
- _should_reset_gamma -> gamma_needs_reset

Rename _parse_sequence to parse_comma_separated_ints to make the input
format and parsed type explicit, and complete its one-line docstring with
full Parameters and Returns sections. Add missing Parameters and Returns
sections to is_registration_source_layer.
Add the leading underscore back to the five recently renamed panel
utility helpers to keep the file consistent with its existing private
naming convention:

- get_default_dims_for_ndim -> _get_default_dims_for_ndim
- is_registration_source_layer -> _is_registration_source_layer
- get_image_display_kwargs_from_layer -> _get_image_display_kwargs_from_layer
- gamma_needs_reset -> _gamma_needs_reset
- parse_comma_separated_ints -> _parse_comma_separated_ints

The functions remain module-internal to the napari registration module;
only their call sites in _panel.py needed updating.
Move the transform payload and panel-specific transform helpers out of
_panel.py and the previous _panel_transform_helpers.py into a single
_panel_transforms.py module, with docstrings completed in the process.

- Hoist UI callbacks (save, load, apply, refresh transform controls) into
  panel-level lambdas so the panel only owns wiring.
- Update the napari registration panel tests to call the new module-level
  helpers.
- drop trailing ":" from form labels (signals, video, save panels)
- align the signals source dropdowns in one grid column
- let the y-limit spin boxes share the full row width instead of a
  96px cap; Ignored size policy keeps the issue #183 overflow away
# Conflicts:
#	docs/images/gui/generate.py
#	src/confusius/_napari/_signals/_panel.py
#	src/confusius/_napari/_time_overlay.py
#	src/confusius/_napari/_tour.py
#	src/confusius/_napari/_widget.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Default learning rate for register_volumewise is bad register_volume composes centering and initial transforms

2 participants