Skip to content

Commit 86ccfd5

Browse files
committed
Merge remote-tracking branch 'upstream/maint/1.2.x'
2 parents 9e79db8 + bc0b4d7 commit 86ccfd5

File tree

2 files changed

+53
-15
lines changed

2 files changed

+53
-15
lines changed

niworkflows/interfaces/images.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -349,31 +349,37 @@ def _run_interface(self, runtime):
349349
xyz_unit = "mm"
350350

351351
# Set a 0.05mm threshold to performing rescaling
352-
atol = {"meter": 1e-5, "mm": 0.01, "micron": 10}[xyz_unit]
353-
354-
# Rescale => change zooms
355-
# Resize => update image dimensions
356-
rescale = not np.allclose(zooms, target_zooms, atol=atol)
352+
atol_gross = {"meter": 5e-5, "mm": 0.05, "micron": 50}[xyz_unit]
353+
# if 0.01 > difference > 0.001mm, freesurfer won't be able to merge the images
354+
atol_fine = {"meter": 1e-6, "mm": 0.001, "micron": 1}[xyz_unit]
355+
356+
# Update zooms => Modify affine
357+
# Rescale => Resample to resized voxels
358+
# Resize => Resample to new image dimensions
359+
update_zooms = not np.allclose(zooms, target_zooms, atol=atol_fine, rtol=0)
360+
rescale = not np.allclose(zooms, target_zooms, atol=atol_gross, rtol=0)
357361
resize = not np.all(shape == target_shape)
358-
if rescale or resize:
359-
if rescale:
362+
resample = rescale or resize
363+
if resample or update_zooms:
364+
# Use an affine with the corrected zooms, whether or not we resample
365+
if update_zooms:
360366
scale_factor = target_zooms / zooms
361-
target_affine[:3, :3] = reoriented.affine[:3, :3].dot(
362-
np.diag(scale_factor)
363-
)
367+
target_affine[:3, :3] = reoriented.affine[:3, :3] @ np.diag(scale_factor)
364368

365369
if resize:
366370
# The shift is applied after scaling.
367371
# Use a proportional shift to maintain relative position in dataset
368372
size_factor = target_span / (zooms * shape)
369373
# Use integer shifts to avoid unnecessary interpolation
370-
offset = (
371-
reoriented.affine[:3, 3] * size_factor - reoriented.affine[:3, 3]
372-
)
374+
offset = reoriented.affine[:3, 3] * size_factor - reoriented.affine[:3, 3]
373375
target_affine[:3, 3] = reoriented.affine[:3, 3] + offset.astype(int)
374376

375-
data = nli.resample_img(reoriented, target_affine, target_shape).dataobj
376-
conform_xfm = np.linalg.inv(reoriented.affine).dot(target_affine)
377+
conform_xfm = np.linalg.inv(reoriented.affine) @ target_affine
378+
379+
# Create new image
380+
data = reoriented.dataobj
381+
if resample:
382+
data = nli.resample_img(reoriented, target_affine, target_shape).dataobj
377383
reoriented = reoriented.__class__(data, target_affine, reoriented.header)
378384

379385
# Image may be reoriented, rescaled, and/or resized

niworkflows/interfaces/tests/test_images.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,35 @@ def test_IntraModalMerge(tmpdir, shape, mshape):
180180
merged_data = nb.load(merged).get_fdata(dtype="float32")
181181
new_mshape = (*mshape[:3], 2 if len(mshape) == 3 else mshape[3] * 2)
182182
assert merged_data.shape == new_mshape
183+
184+
185+
def test_conform_resize(tmpdir):
186+
fname = str(tmpdir / "test.nii")
187+
188+
random_data = np.random.random(size=(5, 5, 5))
189+
img = nb.Nifti1Image(random_data, np.eye(4))
190+
img.to_filename(fname)
191+
conform = pe.Node(im.Conform(), name="conform", base_dir=str(tmpdir))
192+
conform.inputs.in_file = fname
193+
conform.inputs.target_zooms = (1, 1, 1.5)
194+
conform.inputs.target_shape = (5, 5, 5)
195+
res = conform.run()
196+
197+
out_img = nb.load(res.outputs.out_file)
198+
assert out_img.header.get_zooms() == conform.inputs.target_zooms
199+
200+
201+
def test_conform_set_zooms(tmpdir):
202+
fname = str(tmpdir / "test.nii")
203+
204+
random_data = np.random.random(size=(5, 5, 5))
205+
img = nb.Nifti1Image(random_data, np.eye(4))
206+
img.to_filename(fname)
207+
conform = pe.Node(im.Conform(), name="conform", base_dir=str(tmpdir))
208+
conform.inputs.in_file = fname
209+
conform.inputs.target_zooms = (1, 1, 1.002)
210+
conform.inputs.target_shape = (5, 5, 5)
211+
res = conform.run()
212+
213+
out_img = nb.load(res.outputs.out_file)
214+
assert np.allclose(out_img.header.get_zooms(), conform.inputs.target_zooms)

0 commit comments

Comments
 (0)