@@ -561,6 +561,79 @@ def _list_outputs(self):
561
561
outputs ['detrended_file' ] = op .abspath (self .inputs .detrended_file )
562
562
return outputs
563
563
564
+
565
+ class NonSteadyStateDetectorInputSpec (BaseInterfaceInputSpec ):
566
+ in_file = File (exists = True , mandatory = True , desc = '4D NIFTI EPI file' )
567
+
568
+
569
+ class NonSteadyStateDetectorOutputSpec (TraitedSpec ):
570
+ n_volumes_to_discard = traits .Int (desc = 'Number of non-steady state volumes'
571
+ 'detected in the beginning of the scan.' )
572
+
573
+
574
+ class NonSteadyStateDetector (BaseInterface ):
575
+ """
576
+ Returns the number of non-steady state volumes detected at the beginning
577
+ of the scan.
578
+ """
579
+
580
+ input_spec = NonSteadyStateDetectorInputSpec
581
+ output_spec = NonSteadyStateDetectorOutputSpec
582
+
583
+ def _run_interface (self , runtime ):
584
+ in_nii = nb .load (self .inputs .in_plots )
585
+ global_signal = in_nii .get_data ()[:,:,:,:50 ].mean (axis = 0 ).mean (axis = 0 ).mean (axis = 0 )
586
+
587
+ self ._results = {
588
+ 'out_file' : _is_outlier (global_signal )
589
+ }
590
+
591
+ return runtime
592
+
593
+ def _list_outputs (self ):
594
+ return self ._results
595
+
596
+ def _is_outlier (points , thresh = 3.5 ):
597
+ """
598
+ Returns a boolean array with True if points are outliers and False
599
+ otherwise.
600
+
601
+ Parameters:
602
+ -----------
603
+ points : An numobservations by numdimensions array of observations
604
+ thresh : The modified z-score to use as a threshold. Observations with
605
+ a modified z-score (based on the median absolute deviation) greater
606
+ than this value will be classified as outliers.
607
+
608
+ Returns:
609
+ --------
610
+ mask : A numobservations-length boolean array.
611
+
612
+ References:
613
+ ----------
614
+ Boris Iglewicz and David Hoaglin (1993), "Volume 16: How to Detect and
615
+ Handle Outliers", The ASQC Basic References in Quality Control:
616
+ Statistical Techniques, Edward F. Mykytka, Ph.D., Editor.
617
+ """
618
+ if len (points .shape ) == 1 :
619
+ points = points [:, None ]
620
+ median = np .median (points , axis = 0 )
621
+ diff = np .sum ((points - median ) ** 2 , axis = - 1 )
622
+ diff = np .sqrt (diff )
623
+ med_abs_deviation = np .median (diff )
624
+
625
+ modified_z_score = 0.6745 * diff / med_abs_deviation
626
+
627
+ timepoints_to_discard = 0
628
+ for i in range (len (modified_z_score )):
629
+ if modified_z_score [i ] <= thresh :
630
+ break
631
+ else :
632
+ timepoints_to_discard += 1
633
+
634
+ return timepoints_to_discard
635
+
636
+
564
637
def regress_poly (degree , data , remove_mean = True , axis = - 1 ):
565
638
''' returns data with degree polynomial regressed out.
566
639
Be default it is calculated along the last axis (usu. time).
0 commit comments