Skip to content

Commit ec9da7e

Browse files
committed
better fancier "deobliquing"
1 parent e2abc33 commit ec9da7e

File tree

5 files changed

+22
-21
lines changed

5 files changed

+22
-21
lines changed

fmriprep/__about__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
'scikit-image',
106106
'versioneer',
107107
'pyyaml',
108+
'transforms3d'
108109
]
109110

110111
LINKS_REQUIRES = [

fmriprep/interfaces/images.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
traits, TraitedSpec, BaseInterfaceInputSpec, SimpleInterface,
2222
File, InputMultiPath, OutputMultiPath)
2323
from nipype.interfaces import fsl
24+
from fmriprep.utils.misc import remove_rotation_and_shear
2425

2526
LOGGER = logging.getLogger('nipype.interface')
2627

@@ -293,7 +294,7 @@ def _run_interface(self, runtime):
293294

294295
class ValidateImageInputSpec(BaseInterfaceInputSpec):
295296
in_file = File(exists=True, mandatory=True, desc='input image')
296-
deoblique = traits.Bool(False, usedefault=True)
297+
remove_rotation_and_shear = traits.Bool(False, usedefault=True)
297298

298299

299300
class ValidateImageOutputSpec(TraitedSpec):
@@ -344,13 +345,6 @@ class ValidateImage(SimpleInterface):
344345

345346
def _run_interface(self, runtime):
346347

347-
def deoblique(img):
348-
import nibabel as nb
349-
import numpy as np
350-
affine = img.affine
351-
affine[:3, :3] = np.diag(np.diag(affine[:3, :3]))
352-
return nb.Nifti1Image(np.asanyarray(img.dataobj), affine, img.header)
353-
354348
img = nb.load(self.inputs.in_file)
355349
out_report = os.path.join(runtime.cwd, 'report.html')
356350

@@ -379,10 +373,10 @@ def deoblique(img):
379373

380374
# Both match, qform valid (implicit with match), codes okay -> do nothing, empty report
381375
if matching_affines and qform_code > 0 and sform_code > 0:
382-
if self.inputs.deoblique:
376+
if self.inputs.remove_rotation_and_shear:
383377
out_fname = fname_presuffix(self.inputs.in_file, suffix='_valid',
384378
newpath=runtime.cwd)
385-
img = deoblique(img)
379+
img = remove_rotation_and_shear(img)
386380
img.to_filename(out_fname)
387381
self._results['out_file'] = out_fname
388382
else:
@@ -435,8 +429,8 @@ def deoblique(img):
435429
"""
436430
snippet = '<h3 class="elem-title">%s</h3>\n%s\n' % (warning_txt, description)
437431

438-
if self.inputs.deoblique:
439-
img = deoblique(img)
432+
if self.inputs.remove_rotation_and_shear:
433+
img = remove_rotation_and_shear(img)
440434
# Store new file and report
441435
img.to_filename(out_fname)
442436
with open(out_report, 'w') as fobj:

fmriprep/utils/misc.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,23 @@
77
"""
88

99

10-
def split_and_deoblique_func(in_file):
10+
def remove_rotation_and_shear(img):
11+
from transforms3d.affines import decompose, compose
12+
import numpy as np
13+
14+
T, _, Z, _ = decompose(img.affine)
15+
affine = compose(T=T, R=np.diag([1, 1, 1]), Z=Z)
16+
return img.__class__(np.asanyarray(img.dataobj), affine, img.header)
17+
18+
19+
def split_and_rm_rotshear_func(in_file):
1120
import os
1221
from nilearn.image import iter_img
13-
import nibabel as nb
14-
import numpy as np
1522
out_files = []
1623
for i, img in enumerate(iter_img(in_file)):
1724
out_file = os.path.abspath('vol%04d.nii.gz' % i)
18-
affine = img.affine
19-
affine[:3, :3] = np.diag(np.diag(affine[:3, :3]))
20-
nb.Nifti1Image(np.asanyarray(img.dataobj), affine, img.header).to_filename(out_file)
25+
img = remove_rotation_and_shear(img)
26+
img.to_filename(out_file)
2127
out_files.append(out_file)
2228
return out_files
2329

fmriprep/workflows/bold/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from nipype.pipeline import engine as pe
1919
from nipype.interfaces import utility as niu
2020

21-
from fmriprep.utils.misc import split_and_deoblique_func
21+
from fmriprep.utils.misc import split_and_rm_rotshear_func
2222
from ...interfaces import (
2323
DerivativesDataSink,
2424
GiftiNameSource,
@@ -396,7 +396,7 @@ def init_func_preproc_wf(bold_file, ignore, freesurfer,
396396
omp_nthreads=omp_nthreads, enhance_t2=True)
397397

398398
# Top-level BOLD splitter
399-
bold_split = pe.Node(niu.Function(function=split_and_deoblique_func, input_names=['in_file'],
399+
bold_split = pe.Node(niu.Function(function=split_and_rm_rotshear_func, input_names=['in_file'],
400400
output_names=['out_files']), name='bold_split',
401401
mem_gb=mem_gb['filesize'] * 3)
402402

fmriprep/workflows/bold/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def init_bold_reference_wf(omp_nthreads, bold_file=None, name='bold_reference_wf
104104
gen_ref = pe.Node(EstimateReferenceImage(), name="gen_ref",
105105
mem_gb=1) # OE: 128x128x128x50 * 64 / 8 ~ 900MB.
106106
# Re-run validation; no effect if no sbref; otherwise apply same validation to sbref as bold
107-
validate_ref = pe.Node(ValidateImage(deoblique=True), name='validate_ref',
107+
validate_ref = pe.Node(ValidateImage(remove_rotations_and_shear=True), name='validate_ref',
108108
mem_gb=DEFAULT_MEMORY_MIN_GB)
109109
enhance_and_skullstrip_bold_wf = init_enhance_and_skullstrip_bold_wf(omp_nthreads=omp_nthreads)
110110

0 commit comments

Comments
 (0)