Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR refactors image/geometry handling to better match FreeSurfer conventions, adds support for 4dfp .img + .ifh sidecars, and extends registration pipelines/CLIs to accept masks (excluding masked voxels rather than zero-filling).
Changes:
- Add a shared
load_image()helper that applies.ifhgeometry overrides for Analyze-style images and migrate call sites to use it. - Centralize tkRAS/voxel/RAS conversion helpers in
neuroreg.image.geometryand reuse them in transform conversions and BBR paths. - Add mask support across IRLS (
robreg), Powell coreg, and GD registration (plus corresponding CLI flags and tests).
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_robreg.py | Adds tests for .ifh affine loading and mask / singleton-4D handling in robreg wrapper. |
| tests/test_lta.py | Adds tests validating tkRAS/vox2tkRAS helpers for NIfTI volume info. |
| tests/test_irls.py | Adds tests for mask filtering in IRLS linear system and empty mask intersections. |
| tests/test_coreg.py | Adds tests ensuring masks are forwarded through coreg (Powell/GD) and 4D singleton handling. |
| tests/test_cli.py | Adds CLI tests verifying --mov-mask/--ref-mask forwarding for robreg/coreg CLIs. |
| tests/test_bbreg.py | Updates bbreg prealignment tests to use mask exclusion instead of zero-filling. |
| neuroreg/transforms/regdat.py | Reuses centralized vox2tkras_from_volume_info() for regdat conversions. |
| neuroreg/transforms/lta.py | Switches header loading from nib.load to load_image() for .ifh support. |
| neuroreg/transforms/fsl.py | Removes duplicated tkRAS computation and reuses centralized geometry helper. |
| neuroreg/segreg/register.py | Replaces local image loader with shared load_image(). |
| neuroreg/segreg/centroids.py | Removes duplicated load_spatial_image in favor of shared load_image(). |
| neuroreg/imreg/robreg.py | Adds mask plumbing + singleton-4D coercion; uses shared load_image(). |
| neuroreg/imreg/reg_model.py | Converts imports to local/relative project imports. |
| neuroreg/imreg/powell.py | Adds optional masks to NMI evaluator + load via load_image/load_mask; supports singleton-4D coercion. |
| neuroreg/imreg/optimize.py | Adds mask-aware loss evaluation via masked_mean and masked NCC/MI/NMI. |
| neuroreg/imreg/losses.py | Adds masked_mean and mask support to NCC/MI/NMI losses. |
| neuroreg/imreg/irls.py | Adds mask-aware voxel filtering in construct_Ab/register_irls and empty-system handling. |
| neuroreg/imreg/gd.py | Adds mask pyramids + forwards masks through GD optimizer/training loop; uses load_image(). |
| neuroreg/imreg/coreg.py | Extends public coreg API to accept and forward masks to backends. |
| neuroreg/image/segmentation.py | Migrates image loading and tkRAS accessors to new shared geometry + loader. |
| neuroreg/image/masking.py | New shared mask loading/coercion/pyramid utilities. |
| neuroreg/image/map.py | Adds coerce_image_data_3d() and uses it in resampling. |
| neuroreg/image/io.py | New shared load_image() with optional 4dfp .ifh affine override. |
| neuroreg/image/geometry.py | New centralized tkRAS/voxel/RAS conversion helpers. |
| neuroreg/image/init.py | Exports new geometry and io helpers. |
| neuroreg/cli/segreg.py | Migrates CLI to local imports + load_image(). |
| neuroreg/cli/robreg.py | Adds --mov-mask/--ref-mask and forwards masks to robreg. |
| neuroreg/cli/lta.py | Migrates to local imports. |
| neuroreg/cli/coreg.py | Adds --mov-mask/--ref-mask and forwards masks to coreg. |
| neuroreg/cli/bbreg.py | Migrates to load_image() and updates prealignment to pass target mask instead of masked reference image. |
| neuroreg/bbreg/register.py | Migrates to load_image() and uses centralized tkRAS geometry helper. |
| neuroreg/bbreg/optimize.py | Updates tkRAS-related error guidance text; minor formatting. |
| neuroreg/bbreg/io.py | Removes duplicated tkRAS helper (now centralized) and adjusts formatting/imports. |
| neuroreg/init.py | Converts package-level imports to relative form. |
Comments suppressed due to low confidence (2)
neuroreg/imreg/irls.py:600
- When
A.shape[0] == 0,w_sqrtis empty, so(w_sqrt == 0).float().mean()producesNaNforzero_pct. This can leak into logs and intoadaptive_satlogic. Guard this case explicitly (e.g., setzero_pct=100.0or0.0whenw_sqrt.numel()==0).
# Solve IRLS on normalised images
if A.shape[0] == 0:
p = torch.zeros(6, dtype=src.dtype, device=src.device)
w_sqrt = torch.zeros(0, dtype=src.dtype, device=src.device)
sigma_val = 0.0
err_val = float('inf')
else:
p, w_sqrt, sigma_val, err_val = irls_inner_loop(
A, b, sat=current_sat, max_iterations=max_irls, verbose=verbose)
info['sigma_hist'].append(sigma_val)
# Check outlier percentage for adaptive sat adjustment
zero_pct = (w_sqrt == 0).float().mean().item() * 100
neuroreg/imreg/losses.py:98
ncc_lossallows 1-D/2-D tensors (preds.dim() > 3check) but then unconditionally callsF.avg_pool3d, which requires 3-D spatial inputs. Either enforcepreds.dim() == target.dim() == 3up front (with a clearer error) or add a 2-D path usingavg_pool2d.
if preds.dim() > 3 or target.dim() > 3:
raise ValueError(
f"ncc_loss expects ≤3-D tensors; got shapes {tuple(preds.shape)} and {tuple(target.shape)}."
)
mask_bool = _mask_to_bool(mask, preds)
# Add batch + channel dims for pooling: (1, 1, D, H, W)
src = preds.unsqueeze(0).unsqueeze(0)
trg = target.unsqueeze(0).unsqueeze(0)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.