Skip to content

Commit 3a9558d

Browse files
committed
ENH: Basic reimplementation of SignalExtraction
1 parent 51145b5 commit 3a9558d

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

fmriprep/interfaces/images.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,3 +572,70 @@ def nii_ones_like(in_file, value, dtype, newpath=None):
572572
nii.to_filename(out_file)
573573

574574
return out_file
575+
576+
577+
class SignalExtractionInputSpec(BaseInterfaceInputSpec):
578+
in_file = File(exists=True, mandatory=True, desc='4-D fMRI nii file')
579+
label_files = InputMultiPath(
580+
File(exists=True),
581+
mandatory=True,
582+
desc='a 3-D label image, with 0 denoting '
583+
'background, or a list of 3-D probability '
584+
'maps (one per label) or the equivalent 4D '
585+
'file.')
586+
class_labels = traits.List(
587+
mandatory=True,
588+
desc='Human-readable labels for each segment '
589+
'in the label file, in order. The length of '
590+
'class_labels must be equal to the number of '
591+
'segments (background excluded). This list '
592+
'corresponds to the class labels in label_file '
593+
'in ascending order')
594+
out_file = File(
595+
'signals.tsv',
596+
usedefault=True,
597+
exists=False,
598+
desc='The name of the file to output to. '
599+
'signals.tsv by default')
600+
601+
602+
class SignalExtractionOutputSpec(TraitedSpec):
603+
out_file = File(
604+
exists=True,
605+
desc='tsv file containing the computed '
606+
'signals, with as many columns as there are labels and as '
607+
'many rows as there are timepoints in in_file, plus a '
608+
'header row with values from class_labels')
609+
610+
611+
class SignalExtraction(SimpleInterface):
612+
input_spec = SignalExtractionInputSpec
613+
output_spec = SignalExtractionOutputSpec
614+
615+
def _run_interface(self, runtime):
616+
mask_imgs = [nb.load(fname) for fname in self.inputs.label_files]
617+
if len(mask_imgs) == 1:
618+
mask_imgs = nb.four_to_three(mask_imgs[0])
619+
620+
masks = [mask_img.get_data().astype(np.bool) for mask_img in mask_imgs]
621+
622+
n_masks = len(masks)
623+
624+
if n_masks != len(self.inputs.class_labels):
625+
raise ValueError("Number of masks must match number of labels")
626+
627+
img = nb.load(self.inputs.in_file)
628+
629+
series = np.zeros((img.shape[3], n_masks))
630+
631+
data = img.get_data()
632+
for j in range(n_masks):
633+
series[:, j] = data[masks[j], :].mean(axis=0)
634+
635+
output = np.vstack((self.inputs.class_labels, series.astype(str)))
636+
self._results['out_file'] = os.path.join(runtime.cwd,
637+
self.inputs.out_file)
638+
np.savetxt(
639+
self._results['out_file'], output, fmt=b'%s', delimiter='\t')
640+
641+
return runtime

0 commit comments

Comments
 (0)