Skip to content

Warn about coarse input voxel size and clarify resolution requirements - #28

Open
karl-koschutnig wants to merge 1 commit into
Deep-MI:mainfrom
karl-koschutnig:fix/voxel-size-guidance
Open

Warn about coarse input voxel size and clarify resolution requirements#28
karl-koschutnig wants to merge 1 commit into
Deep-MI:mainfrom
karl-koschutnig:fix/voxel-size-guidance

Conversation

@karl-koschutnig

Copy link
Copy Markdown
Contributor

Addresses items 1–3 from #25, per @m-reuter's "you can attempt a fix for the other items in a PR". The --upsample / --make-isotropic renaming is deliberately not included here, since you mentioned that is under internal discussion — the only change to that flag is a log line (see below).

What this changes

The mask filters are parameterised in voxels rather than mm, so their physical strength scales with input voxel size. At ~1 mm the hippocampal ribbon is only ~2 voxels thick and default filtering erodes through it, producing "Surface contains holes" — which then sends users toward manual editing, even though the segmentation is usually fine and it is the resolution that is wrong.

  1. Startup warning when the input voxel edge length exceeds a threshold (voxel_size_threshold = 0.4 mm in cfg/config.py, set just above the native 0.33333 mm so correct input never trips it). For --lut freesurfer it additionally names the .FSvoxelSpace. variant, which is the usual way to hit this.
  2. Extended checkSurface message — when the input is coarse, the "holes" error now says so and suggests checking for a higher-resolution segmentation before editing. When the input is not coarse, the message is unchanged, so genuine segmentation defects still get the original advice.
  3. Docs — the two FreeSurfer output files are now described in TUTORIAL.md (mandatory arguments) and DOCUMENTATION.md (supported segmentations), and the "Holes in the surface" troubleshooting section now lists input resolution as the first thing to check.
  4. --upsample no-op is now logged. It is silently a no-op for isotropic input (every min(vxsz)/vxsz[i] ratio is 1, so the affine is unchanged). Reaching for --upsample is the natural response to the holes error, so the silence is misleading. This is only a log line — no behaviour or naming change.

The voxel size is read once in _check_params and stashed on params.internal, so checkSurface does not have to re-read the image (by that point params.FILENAME has been reassigned several times).

Two decisions I would like your call on

a) Should the FreeSurfer case be a hard error rather than a warning? You suggested "we know that the .333mm file should exist and so we can even stop if we do not get that file passed". I have implemented it as a warning for now, because erroring would break any existing workflow that knowingly runs coarser data, and would want an override flag. Happy to switch it to an error if you prefer — it is a small change. Note I keyed the check off the actual voxel size rather than the filename, so it still works for renamed or copied files.

b) How should this behave for ASHS? As written, the warning fires for any coarse input, so ASHS users will see it on essentially every run — anisotropic voxels are normal there, and the docs already recommend --upsample for them. I left it un-special-cased rather than guess: the input genuinely is coarse and it is only a warning. If you would rather suppress it (or reword it) for the ASHS LUTs, that is a one-line condition on params.LUT and I am happy to add it. You mentioned you were unsure whether ASHS outputs use the anisotropic input resolution — if you can confirm, I can tune the wording accordingly.

Test plan

Tested against a FreeSurfer 8.2 longitudinal cohort, running the pipeline in the Docker image with the modified package mounted in:

  • 1.0 mm .FSvoxelSpace. input, --lut freesurfer — both startup warnings fire, and the holes error carries the new resolution hint.
  • 0.333 mm native input with a genuine segmentation defect — no voxel-size warning and no hint; the original "please edit the segmentation" message stands alone. (This is the case where editing really is the right advice.)
  • 0.333 mm native input, full pipeline incl. QC — zero warnings, Euler 2, 2 boundary loops, Hipsta finished without errors., all three QC PNGs written. No regression.
  • 1.0 mm input with --upsample — logs The image already has isotropic voxels of 1.000 mm, so upsampling ... leaves it unchanged.
  • ruff check . and codespell pass.

Sample output for the first case:

[WARNING: hipsta.py] The input image has a voxel size of 1.000 x 1.000 x 1.000 mm. This method is designed
for segmentations with a voxel edge length of about 0.33 mm; with substantially coarser images, the surface
check will frequently report holes even though the segmentation itself is fine.
[WARNING: hipsta.py] For FreeSurfer input, please make sure to use the native-resolution segmentation
(<lh|rh>.hippoAmygLabels*.mgz) rather than the version that was resampled to the conformed space
(<lh|rh>.hippoAmygLabels*.FSvoxelSpace.mgz).
...
[INFO: check_surface.py] Euler number for <...>/lh.surf.vtk is 0
[INFO: check_surface.py] Surface contains holes. Please edit the corresponding hippocampal segmentation and re-run.
[INFO: check_surface.py] Note that the input image has a voxel size of 1.000 x 1.000 x 1.000 mm, which is coarse
for this method. Holes are common at this resolution even for an otherwise correct segmentation, so please check
whether a higher-resolution version of the segmentation is available before editing it.

Segmentations at ~1 mm rather than the ~0.33 mm this method is designed
for fail checkSurface with "Surface contains holes", which sends users
toward manual editing even though the segmentation is usually fine. The
mask filters are parameterised in voxels, not mm, so their physical
strength scales with the input voxel size.

- Warn at startup when the input voxel edge length exceeds a threshold,
  and for --lut freesurfer additionally point out the .FSvoxelSpace.
  variant, which is the common way to hit this.
- Add the voxel size to the "Surface contains holes" message when the
  input is coarse, so the error itself suggests checking the resolution
  before editing the segmentation.
- Log when --upsample is a no-op, which it silently is for isotropic
  input, since reaching for it is the natural response to the error.
- Document the two FreeSurfer output files and the resolution
  dependency in the tutorial and documentation.

Refs Deep-MI#25
@m-reuter
m-reuter requested a review from kdiers August 6, 2026 10:46
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