Skip to content

Commit 9ebee75

Browse files
committed
enh+ref: allow generation of multiple median files
1 parent 5b06c8e commit 9ebee75

File tree

2 files changed

+60
-18
lines changed

2 files changed

+60
-18
lines changed

nipype/algorithms/misc.py

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,13 +1381,15 @@ def merge_rois(in_files, in_idxs, in_ref,
13811381

13821382

13831383
class CalculateMedianInputSpec(BaseInterfaceInputSpec):
1384-
in_file = InputMultiPath(File(exists=True, mandatory=True,
1384+
in_files = InputMultiPath(File(exists=True, mandatory=True,
13851385
desc="One or more realigned Nifti 4D timeseries"))
1386-
median_file = traits.Str('median.nii.gz', usedefault=True,
1387-
desc="Filename to store median image")
1386+
median_file = traits.Str(desc="Filename prefix to store median images")
1387+
median_per_file = traits.Bool(False, usedefault=True,
1388+
desc="Calculate a median file for each Nifti")
13881389

13891390
class CalculateMedianOutputSpec(TraitedSpec):
1390-
median_file = File(exists=True)
1391+
median_files = OutputMultiPath(File(exists=True),
1392+
desc="One or more median images")
13911393

13921394
class CalculateMedian(BaseInterface):
13931395
"""
@@ -1398,32 +1400,73 @@ class CalculateMedian(BaseInterface):
13981400
13991401
>>> from nipype.algorithms.misc import CalculateMedian
14001402
>>> mean = CalculateMedian()
1401-
>>> mean.inputs.in_file = 'functional.nii'
1403+
>>> mean.inputs.in_files = 'functional.nii'
14021404
>>> mean.run() # doctest: +SKIP
14031405
14041406
"""
14051407
input_spec = CalculateMedianInputSpec
14061408
output_spec = CalculateMedianOutputSpec
14071409

1410+
def __init__(self, *args, **kwargs):
1411+
super(CalculateMedian, self).__init__(*args, **kwargs)
1412+
self._median_files = []
1413+
1414+
def _gen_fname(self, suffix, idx=None, ext=None):
1415+
if idx:
1416+
in_file = self.inputs.in_files[idx]
1417+
else:
1418+
if isinstance(self.inputs.in_files, list):
1419+
in_file = self.inputs.in_files[0]
1420+
else:
1421+
in_file = self.inputs.in_files
1422+
fname, in_ext = op.splitext(op.basename(in_file))
1423+
if in_ext == '.gz':
1424+
fname, in_ext2 = op.splitext(fname)
1425+
in_ext = in_ext2 + in_ext
1426+
if ext is None:
1427+
ext = in_ext
1428+
if ext.startswith('.'):
1429+
ext = ext[1:]
1430+
if self.inputs.median_file:
1431+
outname = self.inputs.median_file
1432+
else:
1433+
outname = '{}_{}'.format(fname, suffix)
1434+
if idx:
1435+
outname += str(idx)
1436+
return op.abspath('{}.{}'.format(outname, ext))
1437+
14081438
def _run_interface(self, runtime):
14091439
total = None
1410-
for idx, fname in enumerate(filename_to_list(self.inputs.in_file)):
1440+
self._median_files = []
1441+
for idx, fname in enumerate(filename_to_list(self.inputs.in_files)):
14111442
img = nb.load(fname, mmap=NUMPY_MMAP)
14121443
data = np.median(img.get_data(), axis=3)
1413-
if total is None:
1414-
total = data
1444+
if self.inputs.median_per_file:
1445+
self._median_files.append(self._write_nifti(img, data, idx))
14151446
else:
1416-
total += data
1417-
median_img = nb.Nifti1Image(total/(idx + 1), img.affine, img.header)
1418-
filename = os.path.join(os.getcwd(), self.inputs.median_file)
1419-
median_img.to_filename(filename)
1447+
if total is None:
1448+
total = data
1449+
else:
1450+
total += data
1451+
if not self.inputs.median_per_file:
1452+
self._median_files.append(self._write_nifti(img, total, idx))
14201453
return runtime
14211454

14221455
def _list_outputs(self):
14231456
outputs = self._outputs().get()
1424-
outputs['median_file'] = os.path.abspath(self.inputs.median_file)
1457+
outputs['median_files'] = self._median_files
14251458
return outputs
14261459

1460+
def _write_nifti(self, img, data, idx, suffix='median'):
1461+
if self.inputs.median_per_file:
1462+
median_img = nb.Nifti1Image(data, img.affine, img.header)
1463+
filename = self._gen_fname(suffix, idx=idx)
1464+
else:
1465+
median_img = nb.Nifti1Image(data/(idx+1), img.affine, img.header)
1466+
filename = self._gen_fname(suffix)
1467+
median_img.to_filename(filename)
1468+
return filename
1469+
14271470

14281471
# Deprecated interfaces ------------------------------------------------------
14291472

nipype/algorithms/tests/test_misc.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from nipype.utils.filemanip import fname_presuffix
1111
from nipype.testing.fixtures import create_analyze_pair_file_in_directory
1212
from nipype.utils import NUMPY_MMAP
13+
from nipype.testing import example_data
1314

1415

1516
def test_CreateNifti(create_analyze_pair_file_in_directory):
@@ -36,14 +37,12 @@ def test_CreateNifti(create_analyze_pair_file_in_directory):
3637

3738
def test_CalculateMedian(create_analyze_pair_file_in_directory):
3839

39-
filelist, outdir = create_analyze_pair_file_in_directory
40-
4140
mean = misc.CalculateMedian()
4241

4342
with pytest.raises(TypeError): mean.run()
4443

45-
mean.inputs.in_file = filelist[0]
44+
mean.inputs.in_files = example_data('ds003_sub-01_mc.nii.gz')
4645
eg = mean.run()
4746

48-
assert os.path.exists(eg.outputs.median_file)
49-
assert nb.load(eg.outputs.median_file, mmap=NUMPY_MMAP)
47+
assert os.path.exists(eg.outputs.median_files)
48+
assert nb.load(eg.outputs.median_files, mmap=NUMPY_MMAP)

0 commit comments

Comments
 (0)