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