Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions FastSurferCNN/data_loader/conform.py
Original file line number Diff line number Diff line change
Expand Up @@ -1566,10 +1566,15 @@ def conformed_vox_img_size(
target_img_size: IntVector3d | None
MAX_VOX_SIZE = 1.0
MAX_DIMENSION = 256
if vox_eps <= 0:
raise ValueError(f"vox_eps must be > 0, got {vox_eps}.")
# number of decimals to round voxel sizes to, so that vox_eps-sized float noise does not affect
# results; clamp at 0 so that vox_eps > 1 does not round voxel sizes to tens of mm
decimals = max(0, int(np.ceil(-np.log10(vox_eps))))
# this is similar to mri_convert --conform_min, note, vox_size == 'auto' is extra, but not covered by VoxSizeOption
if isinstance(vox_size, str) and (vox_size := cast(VoxSizeOption, vox_size.lower())) in ["min", "auto"]:
# find minimal voxel side length
min_vox_size = np.round(np.min(img.header.get_zooms()[:3]), decimals=int(np.ceil(-np.log10(vox_eps))))
min_vox_size = np.round(np.min(img.header.get_zooms()[:3]), decimals=decimals)
# set to 1 mm if larger than that
_conformed_vox_size = min(min_vox_size, MAX_VOX_SIZE)
if threshold_1mm and _conformed_vox_size > threshold_1mm:
Expand Down Expand Up @@ -1600,9 +1605,18 @@ def conformed_vox_img_size(
if target_vox_size is not None:
# correct sizes for changing voxel size (if voxel size is changing)
# compute field of view dimensions in mm (in native orientation)
fov = np.array(img.header.get_zooms()[:3]) * target_img_size
# compute number of voxels needed to cover field of view
target_img_size = np.ceil((fov / target_vox_size * 10000).astype(int).astype(float) / 10000).astype(int)
fov = np.array(np.round(img.header.get_zooms()[:3], decimals=decimals)) * target_img_size
# number of voxels needed to cover the field of view
n_vox = fov / target_vox_size
# n_vox is integer when the fov is a multiple of the voxel size, but floating-point
Comment thread
m-reuter marked this conversation as resolved.
# error makes it only approximately so. Storing the zoom as float32 leaves a relative
# residual of ~1e-8 that scales with the voxel count, i.e. machine precision rather
# than a voxel-size tolerance. Snap counts that are integer within that relative error
# and round up only genuine partial voxels.
rounded = np.rint(n_vox)
target_img_size = np.where(
np.isclose(n_vox, rounded, rtol=1e-6, atol=0.0), rounded, np.ceil(n_vox)
).astype(int)
# use cube (same size in all directions) with MAX_DIMENSION in each direction as minimum
if _img_size == "auto":
target_img_size = np.full_like(np.maximum(MAX_DIMENSION, target_img_size), np.amax(target_img_size))
Expand Down