Skip to content

Modify fov computation, particullary the decimal precision on the voxel size - #850

Merged
m-reuter merged 4 commits into
Deep-MI:devfrom
santiestrada32:dev
Aug 5, 2026
Merged

Modify fov computation, particullary the decimal precision on the voxel size#850
m-reuter merged 4 commits into
Deep-MI:devfrom
santiestrada32:dev

Conversation

@santiestrada32

Copy link
Copy Markdown
Contributor

the surface pipeline fails during the conform stage when processing orig.mgz. It seems to be related to the FOV calculation and the decimal precision of the voxel size
old recon-surf
recon-surf.log
after fixing decimal points
recon-surf.log

@dkuegler dkuegler left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine to me. I guess it also does not matter if you round first and then multiply with img_size.

@m-reuter

m-reuter commented Aug 4, 2026

Copy link
Copy Markdown
Member

I wonder why there is a discrepancy between our own conforming step and the conforming check later. Both should be based on the same code and therefore give the same result ?

The ceil() that turns field-of-view into a voxel count could round up on
floating-point noise: storing the zoom as float32 leaves a relative residual
(~1e-8) that, scaled by the voxel count, pushed an exact fit just over the
integer (e.g. 320.0000048 -> 321). This is machine precision, not a voxel-size
tolerance, and its absolute size grows with the image, so the previous
fixed-tolerance guard (*10000/int/10000, ~1e-4) was both conceptually wrong and
fragile for large images. Snap counts that are integer within a relative 1e-6
to the nearest integer, and ceil only genuine partial voxels.
@m-reuter

m-reuter commented Aug 5, 2026

Copy link
Copy Markdown
Member

Why this happens

 conform()  and  is_conform()  disagreed on the target image size for this input because  conformed_vox_img_size()  computes the target voxel count from the measured voxel size in the header ( fov = zooms * shape ,  n_vox = fov / target_vox_size ), and headers routinely carry tiny float noise — for example  0.8000005  instead of  0.8 . Tha small difference per voxel, which accumulates over the image extent, is enough to push  n_vox  just over an integer boundary ( 320.0002 ) and make  ceil()  round up to 321 instead of 320.
The reason this doesn't show up during conforming itself but does show up on the second call (the surface-stage  is_conform  check) is geometry-dependent: on the original cuboid input, the noisy axis isn't the largest dimension, so  img_size="auto"  picking the max across axes masks the round-up. Once the image has been conformed to a 320³ cube, the same noisy axis is now full-length and becomes the max, so its round-up is no longer hidden and we get a different answer.

I considered forcing the header after conforming to be exactly .8 on all axes, but that would overwrite the real sizes and loose that information. Headers should stay accurate to what was actually done to the data.

The fix in this PR rounds voxel sizes to the same precision ( vox_eps , already the tolerance the voxel-size check itself uses) before computing the FOV, so the round-up no longer happens in the first place. This keeps  conformed_vox_img_size()  idempotent: the size and voxel-size checks now agree with each other on any input, not just this one, without writing any assumption into the image header.

I will add two changes:

  • re-using decimals and thus also fixing the line-too-long error in ruff CI code-style
  • guard the voxel-count-rounding against float error with a relative tolerance (instead of the existing fixed-tolerance guard with *1000/int/1000.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts how conformed_vox_img_size() computes the field-of-view (FOV)–derived image size during conforming, aiming to avoid failures caused by floating-point precision noise in voxel sizes (notably with orig.mgz during recon-surf’s conform stage).

Changes:

  • Derives a shared decimals rounding precision from vox_eps and uses it to round voxel sizes/zooms consistently.
  • Updates FOV-based target size computation to “snap” near-integer voxel counts instead of always ceil-ing after decimal truncation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread FastSurferCNN/data_loader/conform.py
Comment thread FastSurferCNN/data_loader/conform.py Outdated
@m-reuter
m-reuter merged commit ef190b9 into Deep-MI:dev Aug 5, 2026
3 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.

4 participants