@@ -572,3 +572,77 @@ def nii_ones_like(in_file, value, dtype, newpath=None):
572
572
nii .to_filename (out_file )
573
573
574
574
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
+ """ Extract mean signals from a time series within a set of ROIs
613
+
614
+ This interface is intended to be a memory-efficient alternative to
615
+ nipype.interfaces.nilearn.SignalExtraction.
616
+ Not all features of nilearn.SignalExtraction are implemented at
617
+ this time.
618
+ """
619
+ input_spec = SignalExtractionInputSpec
620
+ output_spec = SignalExtractionOutputSpec
621
+
622
+ def _run_interface (self , runtime ):
623
+ mask_imgs = [nb .load (fname ) for fname in self .inputs .label_files ]
624
+ if len (mask_imgs ) == 1 :
625
+ mask_imgs = nb .four_to_three (mask_imgs [0 ])
626
+
627
+ masks = [mask_img .get_data ().astype (np .bool ) for mask_img in mask_imgs ]
628
+
629
+ n_masks = len (masks )
630
+
631
+ if n_masks != len (self .inputs .class_labels ):
632
+ raise ValueError ("Number of masks must match number of labels" )
633
+
634
+ img = nb .load (self .inputs .in_file )
635
+
636
+ series = np .zeros ((img .shape [3 ], n_masks ))
637
+
638
+ data = img .get_data ()
639
+ for j in range (n_masks ):
640
+ series [:, j ] = data [masks [j ], :].mean (axis = 0 )
641
+
642
+ output = np .vstack ((self .inputs .class_labels , series .astype (str )))
643
+ self ._results ['out_file' ] = os .path .join (runtime .cwd ,
644
+ self .inputs .out_file )
645
+ np .savetxt (
646
+ self ._results ['out_file' ], output , fmt = b'%s' , delimiter = '\t ' )
647
+
648
+ return runtime
0 commit comments