def _check_cw256(in_files): from nibabel.funcs import concat_images if isinstance(in_files, str): in_files = [in_files] if any((s > 256 for s in concat_images(in_files).shape[:3])): return ['-noskullstrip', '-cw256'] return '-noskullstrip'
def nii_concat(in_files): from nibabel.funcs import concat_images import os new_nii = concat_images(in_files, check_affines=False) new_nii.to_filename("merged.nii.gz") return os.path.abspath("merged.nii.gz")
def _check_cw256(in_files): import numpy as np from nibabel.funcs import concat_images if isinstance(in_files, str): in_files = [in_files] summary_img = concat_images(in_files) fov = np.array(summary_img.shape[:3]) * summary_img.header.get_zooms()[:3] if np.any(fov > 256): return ['-noskullstrip', '-cw256'] return '-noskullstrip'
def _detect_outliers_core(self, imgfile, motionfile, runidx, cwd=None): """ Core routine for detecting outliers """ if not cwd: cwd = os.getcwd() # read in functional image if isinstance(imgfile, (str, bytes)): nim = load(imgfile, mmap=NUMPY_MMAP) elif isinstance(imgfile, list): if len(imgfile) == 1: nim = load(imgfile[0], mmap=NUMPY_MMAP) else: images = [load(f, mmap=NUMPY_MMAP) for f in imgfile] nim = funcs.concat_images(images) # compute global intensity signal (x, y, z, timepoints) = nim.shape data = nim.get_data() affine = nim.affine g = np.zeros((timepoints, 1)) masktype = self.inputs.mask_type if masktype == 'spm_global': # spm_global like calculation iflogger.debug('art: using spm global') intersect_mask = self.inputs.intersect_mask if intersect_mask: mask = np.ones((x, y, z), dtype=bool) for t0 in range(timepoints): vol = data[:, :, :, t0] # Use an SPM like approach mask_tmp = vol > \ (np.nanmean(vol) / self.inputs.global_threshold) mask = mask * mask_tmp for t0 in range(timepoints): vol = data[:, :, :, t0] g[t0] = np.nanmean(vol[mask]) if len(find_indices(mask)) < (np.prod((x, y, z)) / 10): intersect_mask = False g = np.zeros((timepoints, 1)) if not intersect_mask: iflogger.info('not intersect_mask is True') mask = np.zeros((x, y, z, timepoints)) for t0 in range(timepoints): vol = data[:, :, :, t0] mask_tmp = vol > \ (np.nanmean(vol) / self.inputs.global_threshold) mask[:, :, :, t0] = mask_tmp g[t0] = np.nansum(vol * mask_tmp) / np.nansum(mask_tmp) elif masktype == 'file': # uses a mask image to determine intensity maskimg = load(self.inputs.mask_file, mmap=NUMPY_MMAP) mask = maskimg.get_data() affine = maskimg.affine mask = mask > 0.5 for t0 in range(timepoints): vol = data[:, :, :, t0] g[t0] = np.nanmean(vol[mask]) elif masktype == 'thresh': # uses a fixed signal threshold for t0 in range(timepoints): vol = data[:, :, :, t0] mask = vol > self.inputs.mask_threshold g[t0] = np.nanmean(vol[mask]) else: mask = np.ones((x, y, z)) g = np.nanmean(data[mask > 0, :], 1) # compute normalized intensity values gz = signal.detrend(g, axis=0) # detrend the signal if self.inputs.use_differences[1]: gz = np.concatenate((np.zeros((1, 1)), np.diff(gz, n=1, axis=0)), axis=0) gz = (gz - np.mean(gz)) / np.std(gz) # normalize the detrended signal iidx = find_indices(abs(gz) > self.inputs.zintensity_threshold) # read in motion parameters mc_in = np.loadtxt(motionfile) mc = deepcopy(mc_in) (artifactfile, intensityfile, statsfile, normfile, plotfile, displacementfile, maskfile) = self._get_output_filenames(imgfile, cwd) mask_img = Nifti1Image(mask.astype(np.uint8), affine) mask_img.to_filename(maskfile) if self.inputs.use_norm: brain_pts = None if self.inputs.bound_by_brainmask: voxel_coords = np.nonzero(mask) coords = np.vstack((voxel_coords[0], np.vstack( (voxel_coords[1], voxel_coords[2])))).T brain_pts = np.dot( affine, np.hstack((coords, np.ones((coords.shape[0], 1)))).T) # calculate the norm of the motion parameters normval, displacement = _calc_norm(mc, self.inputs.use_differences[0], self.inputs.parameter_source, brain_pts=brain_pts) tidx = find_indices(normval > self.inputs.norm_threshold) ridx = find_indices(normval < 0) if displacement is not None: dmap = np.zeros((x, y, z, timepoints), dtype=np.float) for i in range(timepoints): dmap[voxel_coords[0], voxel_coords[1], voxel_coords[2], i] = displacement[i, :] dimg = Nifti1Image(dmap, affine) dimg.to_filename(displacementfile) else: if self.inputs.use_differences[0]: mc = np.concatenate((np.zeros( (1, 6)), np.diff(mc_in, n=1, axis=0)), axis=0) traval = mc[:, 0:3] # translation parameters (mm) rotval = mc[:, 3:6] # rotation parameters (rad) tidx = find_indices( np.sum(abs(traval) > self.inputs.translation_threshold, 1) > 0) ridx = find_indices( np.sum(abs(rotval) > self.inputs.rotation_threshold, 1) > 0) outliers = np.unique(np.union1d(iidx, np.union1d(tidx, ridx))) # write output to outputfile np.savetxt(artifactfile, outliers, fmt=b'%d', delimiter=' ') np.savetxt(intensityfile, g, fmt=b'%.2f', delimiter=' ') if self.inputs.use_norm: np.savetxt(normfile, normval, fmt=b'%.4f', delimiter=' ') if isdefined(self.inputs.save_plot) and self.inputs.save_plot: import matplotlib matplotlib.use(config.get("execution", "matplotlib_backend")) import matplotlib.pyplot as plt fig = plt.figure() if isdefined(self.inputs.use_norm) and self.inputs.use_norm: plt.subplot(211) else: plt.subplot(311) self._plot_outliers_with_wave(gz, iidx, 'Intensity') if isdefined(self.inputs.use_norm) and self.inputs.use_norm: plt.subplot(212) self._plot_outliers_with_wave(normval, np.union1d(tidx, ridx), 'Norm (mm)') else: diff = '' if self.inputs.use_differences[0]: diff = 'diff' plt.subplot(312) self._plot_outliers_with_wave(traval, tidx, 'Translation (mm)' + diff) plt.subplot(313) self._plot_outliers_with_wave(rotval, ridx, 'Rotation (rad)' + diff) plt.savefig(plotfile) plt.close(fig) motion_outliers = np.union1d(tidx, ridx) stats = [ { 'motion_file': motionfile, 'functional_file': imgfile }, { 'common_outliers': len(np.intersect1d(iidx, motion_outliers)), 'intensity_outliers': len(np.setdiff1d(iidx, motion_outliers)), 'motion_outliers': len(np.setdiff1d(motion_outliers, iidx)), }, { 'motion': [ { 'using differences': self.inputs.use_differences[0] }, { 'mean': np.mean(mc_in, axis=0).tolist(), 'min': np.min(mc_in, axis=0).tolist(), 'max': np.max(mc_in, axis=0).tolist(), 'std': np.std(mc_in, axis=0).tolist() }, ] }, { 'intensity': [ { 'using differences': self.inputs.use_differences[1] }, { 'mean': np.mean(gz, axis=0).tolist(), 'min': np.min(gz, axis=0).tolist(), 'max': np.max(gz, axis=0).tolist(), 'std': np.std(gz, axis=0).tolist() }, ] }, ] if self.inputs.use_norm: stats.insert( 3, { 'motion_norm': { 'mean': np.mean(normval, axis=0).tolist(), 'min': np.min(normval, axis=0).tolist(), 'max': np.max(normval, axis=0).tolist(), 'std': np.std(normval, axis=0).tolist(), } }) save_json(statsfile, stats)
def _detect_outliers_core(self, imgfile, motionfile, runidx, cwd=None): """ Core routine for detecting outliers """ if not cwd: cwd = os.getcwd() # read in functional image if isinstance(imgfile, string_types): nim = load(imgfile) elif isinstance(imgfile, list): if len(imgfile) == 1: nim = load(imgfile[0]) else: images = [load(f) for f in imgfile] nim = funcs.concat_images(images) # compute global intensity signal (x, y, z, timepoints) = nim.shape data = nim.get_data() affine = nim.affine g = np.zeros((timepoints, 1)) masktype = self.inputs.mask_type if masktype == 'spm_global': # spm_global like calculation iflogger.debug('art: using spm global') intersect_mask = self.inputs.intersect_mask if intersect_mask: mask = np.ones((x, y, z), dtype=bool) for t0 in range(timepoints): vol = data[:, :, :, t0] # Use an SPM like approach mask_tmp = vol > \ (_nanmean(vol) / self.inputs.global_threshold) mask = mask * mask_tmp for t0 in range(timepoints): vol = data[:, :, :, t0] g[t0] = _nanmean(vol[mask]) if len(find_indices(mask)) < (np.prod((x, y, z)) / 10): intersect_mask = False g = np.zeros((timepoints, 1)) if not intersect_mask: iflogger.info('not intersect_mask is True') mask = np.zeros((x, y, z, timepoints)) for t0 in range(timepoints): vol = data[:, :, :, t0] mask_tmp = vol > \ (_nanmean(vol) / self.inputs.global_threshold) mask[:, :, :, t0] = mask_tmp g[t0] = np.nansum(vol * mask_tmp) / np.nansum(mask_tmp) elif masktype == 'file': # uses a mask image to determine intensity maskimg = load(self.inputs.mask_file) mask = maskimg.get_data() affine = maskimg.affine mask = mask > 0.5 for t0 in range(timepoints): vol = data[:, :, :, t0] g[t0] = _nanmean(vol[mask]) elif masktype == 'thresh': # uses a fixed signal threshold for t0 in range(timepoints): vol = data[:, :, :, t0] mask = vol > self.inputs.mask_threshold g[t0] = _nanmean(vol[mask]) else: mask = np.ones((x, y, z)) g = _nanmean(data[mask > 0, :], 1) # compute normalized intensity values gz = signal.detrend(g, axis=0) # detrend the signal if self.inputs.use_differences[1]: gz = np.concatenate((np.zeros((1, 1)), np.diff(gz, n=1, axis=0)), axis=0) gz = (gz - np.mean(gz)) / np.std(gz) # normalize the detrended signal iidx = find_indices(abs(gz) > self.inputs.zintensity_threshold) # read in motion parameters mc_in = np.loadtxt(motionfile) mc = deepcopy(mc_in) (artifactfile, intensityfile, statsfile, normfile, plotfile, displacementfile, maskfile) = self._get_output_filenames(imgfile, cwd) mask_img = Nifti1Image(mask.astype(np.uint8), affine) mask_img.to_filename(maskfile) if self.inputs.use_norm: brain_pts = None if self.inputs.bound_by_brainmask: voxel_coords = np.nonzero(mask) coords = np.vstack((voxel_coords[0], np.vstack((voxel_coords[1], voxel_coords[2])))).T brain_pts = np.dot(affine, np.hstack((coords, np.ones((coords.shape[0], 1)))).T) # calculate the norm of the motion parameters normval, displacement = _calc_norm(mc, self.inputs.use_differences[0], self.inputs.parameter_source, brain_pts=brain_pts) tidx = find_indices(normval > self.inputs.norm_threshold) ridx = find_indices(normval < 0) if displacement is not None: dmap = np.zeros((x, y, z, timepoints), dtype=np.float) for i in range(timepoints): dmap[voxel_coords[0], voxel_coords[1], voxel_coords[2], i] = displacement[i, :] dimg = Nifti1Image(dmap, affine) dimg.to_filename(displacementfile) else: if self.inputs.use_differences[0]: mc = np.concatenate((np.zeros((1, 6)), np.diff(mc_in, n=1, axis=0)), axis=0) traval = mc[:, 0:3] # translation parameters (mm) rotval = mc[:, 3:6] # rotation parameters (rad) tidx = find_indices(np.sum(abs(traval) > self.inputs.translation_threshold, 1) > 0) ridx = find_indices(np.sum(abs(rotval) > self.inputs.rotation_threshold, 1) > 0) outliers = np.unique(np.union1d(iidx, np.union1d(tidx, ridx))) # write output to outputfile np.savetxt(artifactfile, outliers, fmt='%d', delimiter=' ') np.savetxt(intensityfile, g, fmt='%.2f', delimiter=' ') if self.inputs.use_norm: np.savetxt(normfile, normval, fmt='%.4f', delimiter=' ') if isdefined(self.inputs.save_plot) and self.inputs.save_plot: import matplotlib matplotlib.use(config.get("execution", "matplotlib_backend")) import matplotlib.pyplot as plt fig = plt.figure() if isdefined(self.inputs.use_norm) and self.inputs.use_norm: plt.subplot(211) else: plt.subplot(311) self._plot_outliers_with_wave(gz, iidx, 'Intensity') if isdefined(self.inputs.use_norm) and self.inputs.use_norm: plt.subplot(212) self._plot_outliers_with_wave(normval, np.union1d(tidx, ridx), 'Norm (mm)') else: diff = '' if self.inputs.use_differences[0]: diff = 'diff' plt.subplot(312) self._plot_outliers_with_wave(traval, tidx, 'Translation (mm)' + diff) plt.subplot(313) self._plot_outliers_with_wave(rotval, ridx, 'Rotation (rad)' + diff) plt.savefig(plotfile) plt.close(fig) motion_outliers = np.union1d(tidx, ridx) stats = [{'motion_file': motionfile, 'functional_file': imgfile}, {'common_outliers': len(np.intersect1d(iidx, motion_outliers)), 'intensity_outliers': len(np.setdiff1d(iidx, motion_outliers)), 'motion_outliers': len(np.setdiff1d(motion_outliers, iidx)), }, {'motion': [{'using differences': self.inputs.use_differences[0]}, {'mean': np.mean(mc_in, axis=0).tolist(), 'min': np.min(mc_in, axis=0).tolist(), 'max': np.max(mc_in, axis=0).tolist(), 'std': np.std(mc_in, axis=0).tolist()}, ]}, {'intensity': [{'using differences': self.inputs.use_differences[1]}, {'mean': np.mean(gz, axis=0).tolist(), 'min': np.min(gz, axis=0).tolist(), 'max': np.max(gz, axis=0).tolist(), 'std': np.std(gz, axis=0).tolist()}, ]}, ] if self.inputs.use_norm: stats.insert(3, {'motion_norm': {'mean': np.mean(normval, axis=0).tolist(), 'min': np.min(normval, axis=0).tolist(), 'max': np.max(normval, axis=0).tolist(), 'std': np.std(normval, axis=0).tolist(), }}) save_json(statsfile, stats)
def _detect_outliers_core(self, imgfile, motionfile, runidx, cwd=None): """ Core routine for detecting outliers """ if not cwd: cwd = os.getcwd() # read in motion parameters mc_in = np.loadtxt(motionfile) mc = deepcopy(mc_in) if self.inputs.parameter_source == 'SPM': pass elif self.inputs.parameter_source == 'FSL': mc = mc[:,[3,4,5,0,1,2]] elif self.inputs.parameter_source == 'Siemens': Exception("Siemens PACE format not implemented yet") else: Exception("Unknown source for movement parameters") if self.inputs.use_norm: # calculate the norm of the motion parameters normval = self._calc_norm(mc,self.inputs.use_differences[0]) tidx = find_indices(normval>self.inputs.norm_threshold) ridx = find_indices(normval<0) else: if self.inputs.use_differences[0]: mc = np.concatenate( (np.zeros((1,6)),np.diff(mc_in,n=1,axis=0)) , axis=0) traval = mc[:,0:3] # translation parameters (mm) rotval = mc[:,3:6] # rotation parameters (rad) tidx = find_indices(np.sum(abs(traval)>self.inputs.translation_threshold,1)>0) ridx = find_indices(np.sum(abs(rotval)>self.inputs.rotation_threshold,1)>0) # read in functional image if isinstance(imgfile,str): nim = load(imgfile) elif isinstance(imgfile,list): if len(imgfile) == 1: nim = load(imgfile[0]) else: images = [load(f) for f in imgfile] nim = funcs.concat_images(images) # compute global intensity signal (x,y,z,timepoints) = nim.get_shape() data = nim.get_data() g = np.zeros((timepoints,1)) masktype = self.inputs.mask_type if masktype == 'spm_global': # spm_global like calculation intersect_mask = self.inputs.intersect_mask if intersect_mask: mask = np.ones((x,y,z),dtype=bool) for t0 in range(timepoints): vol = data[:,:,:,t0] mask = mask*(vol>(self._nanmean(vol)/8)) for t0 in range(timepoints): vol = data[:,:,:,t0] g[t0] = self._nanmean(vol[mask]) if len(find_indices(mask))<(np.prod((x,y,z))/10): intersect_mask = False g = np.zeros((timepoints,1)) if not intersect_mask: for t0 in range(timepoints): vol = data[:,:,:,t0] mask = vol>(self._nanmean(vol)/8) g[t0] = self._nanmean(vol[mask]) elif masktype == 'file': # uses a mask image to determine intensity mask = load(self.inputs.mask_file).get_data() mask = mask>0.5 for t0 in range(timepoints): vol = data[:,:,:,t0] g[t0] = self._nanmean(vol[mask]) elif masktype == 'thresh': # uses a fixed signal threshold for t0 in range(timepoints): vol = data[:,:,:,t0] mask = vol>self.inputs.mask_threshold g[t0] = self._nanmean(vol[mask]) else: mask = np.ones((x,y,z)) g = self._nanmean(data[mask>0,:],1) # compute normalized intensity values gz = signal.detrend(g,axis=0) # detrend the signal if self.inputs.use_differences[1]: gz = np.concatenate( (np.zeros((1,1)),np.diff(gz,n=1,axis=0)) , axis=0) gz = (gz-np.mean(gz))/np.std(gz) # normalize the detrended signal iidx = find_indices(abs(gz)>self.inputs.zintensity_threshold) outliers = np.unique(np.union1d(iidx,np.union1d(tidx,ridx))) artifactfile,intensityfile,statsfile,normfile = self._get_output_filenames(imgfile,cwd) # write output to outputfile np.savetxt(artifactfile, outliers, fmt='%d', delimiter=' ') np.savetxt(intensityfile, g, fmt='%.2f', delimiter=' ') if self.inputs.use_norm: np.savetxt(normfile, normval, fmt='%.4f', delimiter=' ') file = open(statsfile,'w') file.write("Stats for:\n") file.write("Motion file: %s\n" % motionfile) file.write("Functional file: %s\n" % imgfile) file.write("Motion:\n") file.write("Number of Motion Outliers: %d\n"%len(np.union1d(tidx,ridx))) file.write("Motion (original):\n") file.write( ''.join(('mean: ',str(np.mean(mc_in,axis=0)),'\n'))) file.write( ''.join(('min: ',str(np.min(mc_in,axis=0)),'\n'))) file.write( ''.join(('max: ',str(np.max(mc_in,axis=0)),'\n'))) file.write( ''.join(('std: ',str(np.std(mc_in,axis=0)),'\n'))) if self.inputs.use_norm: if self.inputs.use_differences[0]: file.write("Motion (norm-differences):\n") else: file.write("Motion (norm):\n") file.write( ''.join(('mean: ',str(np.mean(normval,axis=0)),'\n'))) file.write( ''.join(('min: ',str(np.min(normval,axis=0)),'\n'))) file.write( ''.join(('max: ',str(np.max(normval,axis=0)),'\n'))) file.write( ''.join(('std: ',str(np.std(normval,axis=0)),'\n'))) elif self.inputs.use_differences[0]: file.write("Motion (differences):\n") file.write( ''.join(('mean: ',str(np.mean(mc,axis=0)),'\n'))) file.write( ''.join(('min: ',str(np.min(mc,axis=0)),'\n'))) file.write( ''.join(('max: ',str(np.max(mc,axis=0)),'\n'))) file.write( ''.join(('std: ',str(np.std(mc,axis=0)),'\n'))) if self.inputs.use_differences[1]: file.write("Normalized intensity:\n") else: file.write("Intensity:\n") file.write("Number of Intensity Outliers: %d\n"%len(iidx)) file.write( ''.join(('min: ',str(np.min(gz,axis=0)),'\n'))) file.write( ''.join(('max: ',str(np.max(gz,axis=0)),'\n'))) file.write( ''.join(('mean: ',str(np.mean(gz,axis=0)),'\n'))) file.write( ''.join(('std: ',str(np.std(gz,axis=0)),'\n'))) file.close()
def __init__(self, filenames=['path']): import nibabel.funcs as nb img_conc = nb.concat_images(filenames, check_affines=False, axis=None) self.img = img_conc.get_fdata() self.header = img_conc.header
def _detect_outliers_core(self, imgfile, motionfile, runidx, cwd=None): """ Core routine for detecting outliers """ if not cwd: cwd = os.getcwd() # read in motion parameters mc_in = np.loadtxt(motionfile) mc = deepcopy(mc_in) if self.inputs.parameter_source == 'SPM': pass elif self.inputs.parameter_source == 'FSL': mc = mc[:, [3, 4, 5, 0, 1, 2]] elif self.inputs.parameter_source == 'Siemens': Exception("Siemens PACE format not implemented yet") else: Exception("Unknown source for movement parameters") if self.inputs.use_norm: # calculate the norm of the motion parameters normval = self._calc_norm(mc, self.inputs.use_differences[0]) tidx = find_indices(normval > self.inputs.norm_threshold) ridx = find_indices(normval < 0) else: if self.inputs.use_differences[0]: mc = np.concatenate((np.zeros((1, 6)), np.diff(mc_in, n=1, axis=0)), axis=0) traval = mc[:, 0:3] # translation parameters (mm) rotval = mc[:, 3:6] # rotation parameters (rad) tidx = find_indices(np.sum(abs(traval) > self.inputs.translation_threshold, 1) > 0) ridx = find_indices(np.sum(abs(rotval) > self.inputs.rotation_threshold, 1) > 0) # read in functional image if isinstance(imgfile, str): nim = load(imgfile) elif isinstance(imgfile, list): if len(imgfile) == 1: nim = load(imgfile[0]) else: images = [load(f) for f in imgfile] nim = funcs.concat_images(images) # compute global intensity signal (x, y, z, timepoints) = nim.get_shape() data = nim.get_data() g = np.zeros((timepoints, 1)) masktype = self.inputs.mask_type if masktype == 'spm_global': # spm_global like calculation intersect_mask = self.inputs.intersect_mask if intersect_mask: mask = np.ones((x, y, z), dtype=bool) for t0 in range(timepoints): vol = data[:, :, :, t0] mask = mask * (vol > (self._nanmean(vol) / 8)) for t0 in range(timepoints): vol = data[:, :, :, t0] g[t0] = self._nanmean(vol[mask]) if len(find_indices(mask)) < (np.prod((x, y, z)) / 10): intersect_mask = False g = np.zeros((timepoints, 1)) if not intersect_mask: for t0 in range(timepoints): vol = data[:, :, :, t0] mask = vol > (self._nanmean(vol) / 8) g[t0] = self._nanmean(vol[mask]) elif masktype == 'file': # uses a mask image to determine intensity mask = load(self.inputs.mask_file).get_data() mask = mask > 0.5 for t0 in range(timepoints): vol = data[:, :, :, t0] g[t0] = self._nanmean(vol[mask]) elif masktype == 'thresh': # uses a fixed signal threshold for t0 in range(timepoints): vol = data[:, :, :, t0] mask = vol > self.inputs.mask_threshold g[t0] = self._nanmean(vol[mask]) else: mask = np.ones((x, y, z)) g = self._nanmean(data[mask > 0, :], 1) # compute normalized intensity values gz = signal.detrend(g, axis=0) # detrend the signal if self.inputs.use_differences[1]: gz = np.concatenate((np.zeros((1, 1)), np.diff(gz, n=1, axis=0)), axis=0) gz = (gz - np.mean(gz)) / np.std(gz) # normalize the detrended signal iidx = find_indices(abs(gz) > self.inputs.zintensity_threshold) outliers = np.unique(np.union1d(iidx, np.union1d(tidx, ridx))) artifactfile, intensityfile, statsfile, normfile, plotfile = self._get_output_filenames(imgfile, cwd) # write output to outputfile np.savetxt(artifactfile, outliers, fmt='%d', delimiter=' ') np.savetxt(intensityfile, g, fmt='%.2f', delimiter=' ') if self.inputs.use_norm: np.savetxt(normfile, normval, fmt='%.4f', delimiter=' ') if isdefined(self.inputs.save_plot) and self.inputs.save_plot: fig = plt.figure() if isdefined(self.inputs.use_norm) and self.inputs.use_norm: plt.subplot(211) else: plt.subplot(311) self._plot_outliers_with_wave(gz, iidx, 'Intensity') if isdefined(self.inputs.use_norm) and self.inputs.use_norm: plt.subplot(212) self._plot_outliers_with_wave(normval, np.union1d(tidx, ridx), 'Norm (mm)') else: diff = '' if self.inputs.use_differences[0]: diff = 'diff' plt.subplot(312) self._plot_outliers_with_wave(traval, tidx, 'Translation (mm)' + diff) plt.subplot(313) self._plot_outliers_with_wave(rotval, ridx, 'Rotation (rad)' + diff) plt.savefig(plotfile) plt.close(fig) motion_outliers = np.union1d(tidx, ridx) stats = [{'motion_file': motionfile, 'functional_file': imgfile}, {'common_outliers': len(np.intersect1d(iidx, motion_outliers)), 'intensity_outliers': len(np.setdiff1d(iidx, motion_outliers)), 'motion_outliers': len(np.setdiff1d(motion_outliers, iidx)), }, {'motion': [{'using differences': self.inputs.use_differences[0]}, {'mean': np.mean(mc_in, axis=0).tolist(), 'min': np.min(mc_in, axis=0).tolist(), 'max': np.max(mc_in, axis=0).tolist(), 'std': np.std(mc_in, axis=0).tolist()}, ]}, {'intensity': [{'using differences': self.inputs.use_differences[1]}, {'mean': np.mean(gz, axis=0).tolist(), 'min': np.min(gz, axis=0).tolist(), 'max': np.max(gz, axis=0).tolist(), 'std': np.std(gz, axis=0).tolist()}, ]}, ] if self.inputs.use_norm: stats.insert(3, {'motion_norm': {'mean': np.mean(normval, axis=0).tolist(), 'min': np.min(normval, axis=0).tolist(), 'max': np.max(normval, axis=0).tolist(), 'std': np.std(normval, axis=0).tolist(), }}) save_json(statsfile, stats)
def _detect_outliers_core(self, imgfile, motionfile, runidx, cwd=None): """ Core routine for detecting outliers """ if not cwd: cwd = os.getcwd() # read in motion parameters mc_in = np.loadtxt(motionfile) mc = deepcopy(mc_in) if self.inputs.parameter_source == 'SPM': pass elif self.inputs.parameter_source == 'FSL': mc = mc[:, [3, 4, 5, 0, 1, 2]] elif self.inputs.parameter_source == 'Siemens': Exception("Siemens PACE format not implemented yet") else: Exception("Unknown source for movement parameters") if self.inputs.use_norm: # calculate the norm of the motion parameters normval = self._calc_norm(mc, self.inputs.use_differences[0]) tidx = find_indices(normval > self.inputs.norm_threshold) ridx = find_indices(normval < 0) else: if self.inputs.use_differences[0]: mc = np.concatenate((np.zeros((1, 6)), np.diff(mc_in, n=1, axis=0)), axis=0) traval = mc[:, 0:3] # translation parameters (mm) rotval = mc[:, 3:6] # rotation parameters (rad) tidx = find_indices(np.sum(abs(traval) > self.inputs.translation_threshold, 1) > 0) ridx = find_indices(np.sum(abs(rotval) > self.inputs.rotation_threshold, 1) > 0) # read in functional image if isinstance(imgfile, str): nim = load(imgfile) elif isinstance(imgfile, list): if len(imgfile) == 1: nim = load(imgfile[0]) else: images = [load(f) for f in imgfile] nim = funcs.concat_images(images) # compute global intensity signal (x, y, z, timepoints) = nim.get_shape() data = nim.get_data() g = np.zeros((timepoints, 1)) masktype = self.inputs.mask_type if masktype == 'spm_global': # spm_global like calculation intersect_mask = self.inputs.intersect_mask if intersect_mask: mask = np.ones((x, y, z), dtype=bool) for t0 in range(timepoints): vol = data[:, :, :, t0] mask = mask * (vol > (self._nanmean(vol) / 8)) for t0 in range(timepoints): vol = data[:, :, :, t0] g[t0] = self._nanmean(vol[mask]) if len(find_indices(mask)) < (np.prod((x, y, z)) / 10): intersect_mask = False g = np.zeros((timepoints, 1)) if not intersect_mask: for t0 in range(timepoints): vol = data[:, :, :, t0] mask = vol > (self._nanmean(vol) / 8) g[t0] = self._nanmean(vol[mask]) elif masktype == 'file': # uses a mask image to determine intensity mask = load(self.inputs.mask_file).get_data() mask = mask > 0.5 for t0 in range(timepoints): vol = data[:, :, :, t0] g[t0] = self._nanmean(vol[mask]) elif masktype == 'thresh': # uses a fixed signal threshold for t0 in range(timepoints): vol = data[:, :, :, t0] mask = vol > self.inputs.mask_threshold g[t0] = self._nanmean(vol[mask]) else: mask = np.ones((x, y, z)) g = self._nanmean(data[mask > 0, :], 1) # compute normalized intensity values gz = signal.detrend(g, axis=0) # detrend the signal if self.inputs.use_differences[1]: gz = np.concatenate((np.zeros((1, 1)), np.diff(gz, n=1, axis=0)), axis=0) gz = (gz - np.mean(gz)) / np.std(gz) # normalize the detrended signal iidx = find_indices(abs(gz) > self.inputs.zintensity_threshold) outliers = np.unique(np.union1d(iidx, np.union1d(tidx, ridx))) artifactfile, intensityfile, statsfile, normfile, plotfile = self._get_output_filenames(imgfile, cwd) # write output to outputfile np.savetxt(artifactfile, outliers, fmt='%d', delimiter=' ') np.savetxt(intensityfile, g, fmt='%.2f', delimiter=' ') if self.inputs.use_norm: np.savetxt(normfile, normval, fmt='%.4f', delimiter=' ') if isdefined(self.inputs.save_plot) and self.inputs.save_plot: import matplotlib.pyplot as plt fig = plt.figure() if isdefined(self.inputs.use_norm) and self.inputs.use_norm: plt.subplot(211) else: plt.subplot(311) self._plot_outliers_with_wave(gz, iidx, 'Intensity') if isdefined(self.inputs.use_norm) and self.inputs.use_norm: plt.subplot(212) self._plot_outliers_with_wave(normval, np.union1d(tidx, ridx), 'Norm (mm)') else: diff = '' if self.inputs.use_differences[0]: diff = 'diff' plt.subplot(312) self._plot_outliers_with_wave(traval, tidx, 'Translation (mm)' + diff) plt.subplot(313) self._plot_outliers_with_wave(rotval, ridx, 'Rotation (rad)' + diff) plt.savefig(plotfile) plt.close(fig) motion_outliers = np.union1d(tidx, ridx) stats = [{'motion_file': motionfile, 'functional_file': imgfile}, {'common_outliers': len(np.intersect1d(iidx, motion_outliers)), 'intensity_outliers': len(np.setdiff1d(iidx, motion_outliers)), 'motion_outliers': len(np.setdiff1d(motion_outliers, iidx)), }, {'motion': [{'using differences': self.inputs.use_differences[0]}, {'mean': np.mean(mc_in, axis=0).tolist(), 'min': np.min(mc_in, axis=0).tolist(), 'max': np.max(mc_in, axis=0).tolist(), 'std': np.std(mc_in, axis=0).tolist()}, ]}, {'intensity': [{'using differences': self.inputs.use_differences[1]}, {'mean': np.mean(gz, axis=0).tolist(), 'min': np.min(gz, axis=0).tolist(), 'max': np.max(gz, axis=0).tolist(), 'std': np.std(gz, axis=0).tolist()}, ]}, ] if self.inputs.use_norm: stats.insert(3, {'motion_norm': {'mean': np.mean(normval, axis=0).tolist(), 'min': np.min(normval, axis=0).tolist(), 'max': np.max(normval, axis=0).tolist(), 'std': np.std(normval, axis=0).tolist(), }}) save_json(statsfile, stats)