|
33 | 33 | InputMultiPath, OutputMultiPath, |
34 | 34 | BaseInterfaceInputSpec, isdefined, |
35 | 35 | DynamicTraitedSpec, Undefined) |
36 | | -from ..utils.filemanip import fname_presuffix, split_filename |
| 36 | +from ..utils.filemanip import fname_presuffix, split_filename, filename_to_list |
37 | 37 | from ..utils import NUMPY_MMAP |
38 | 38 |
|
39 | 39 | from . import confounds |
@@ -1380,6 +1380,94 @@ def merge_rois(in_files, in_idxs, in_ref, |
1380 | 1380 | return out_file |
1381 | 1381 |
|
1382 | 1382 |
|
| 1383 | +class CalculateMedianInputSpec(BaseInterfaceInputSpec): |
| 1384 | + in_files = InputMultiPath(File(exists=True, mandatory=True, |
| 1385 | + desc="One or more realigned Nifti 4D timeseries")) |
| 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") |
| 1389 | + |
| 1390 | +class CalculateMedianOutputSpec(TraitedSpec): |
| 1391 | + median_files = OutputMultiPath(File(exists=True), |
| 1392 | + desc="One or more median images") |
| 1393 | + |
| 1394 | +class CalculateMedian(BaseInterface): |
| 1395 | + """ |
| 1396 | + Computes an average of the median across one or more 4D Nifti timeseries |
| 1397 | +
|
| 1398 | + Example |
| 1399 | + ------- |
| 1400 | +
|
| 1401 | + >>> from nipype.algorithms.misc import CalculateMedian |
| 1402 | + >>> mean = CalculateMedian() |
| 1403 | + >>> mean.inputs.in_files = 'functional.nii' |
| 1404 | + >>> mean.run() # doctest: +SKIP |
| 1405 | +
|
| 1406 | + """ |
| 1407 | + input_spec = CalculateMedianInputSpec |
| 1408 | + output_spec = CalculateMedianOutputSpec |
| 1409 | + |
| 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 | + |
| 1438 | + def _run_interface(self, runtime): |
| 1439 | + total = None |
| 1440 | + self._median_files = [] |
| 1441 | + for idx, fname in enumerate(filename_to_list(self.inputs.in_files)): |
| 1442 | + img = nb.load(fname, mmap=NUMPY_MMAP) |
| 1443 | + data = np.median(img.get_data(), axis=3) |
| 1444 | + if self.inputs.median_per_file: |
| 1445 | + self._median_files.append(self._write_nifti(img, data, idx)) |
| 1446 | + else: |
| 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)) |
| 1453 | + return runtime |
| 1454 | + |
| 1455 | + def _list_outputs(self): |
| 1456 | + outputs = self._outputs().get() |
| 1457 | + outputs['median_files'] = self._median_files |
| 1458 | + return outputs |
| 1459 | + |
| 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 | + |
| 1470 | + |
1383 | 1471 | # Deprecated interfaces ------------------------------------------------------ |
1384 | 1472 |
|
1385 | 1473 | class Distance(nam.Distance): |
|
0 commit comments