def recover_4D(mask_file, vector_maps, ref_4d): from rabies.utils import copyInfo_4DImage #vector maps of shape num_volumeXnum_voxel mask_img = sitk.ReadImage(mask_file, sitk.sitkFloat32) brain_mask = sitk.GetArrayFromImage(mask_img) volume_indices = brain_mask.astype(bool) shape = (vector_maps.shape[0], brain_mask.shape[0], brain_mask.shape[1], brain_mask.shape[2]) volumes = np.zeros(shape) for i in range(vector_maps.shape[0]): volume = volumes[i, :, :, :] volume[volume_indices] = vector_maps[i, :] volumes[i, :, :, :] = volume volume_img = copyInfo_4DImage( sitk.GetImageFromArray(volumes, isVector=False), mask_img, sitk.ReadImage(ref_4d)) return volume_img
def resample_IC_file(in_file, ref_file, transforms=[], inverses=[]): # resampling the reference image to the dimension of the EPI import SimpleITK as sitk import os from rabies.utils import split_volumes, copyInfo_4DImage, exec_applyTransforms import pathlib # Better path manipulation filename_split = pathlib.Path(in_file).name.rsplit(".nii") out_file = os.path.abspath(filename_split[0]) + '_resampled.nii.gz' # Splitting bold file into lists of single volumes [volumes_list, num_volumes] = split_volumes(in_file, "bold_", sitk.sitkFloat32) warped_volumes = [] for x in range(0, num_volumes): warped_vol_fname = os.path.abspath("deformed_volume" + str(x) + ".nii.gz") warped_volumes.append(warped_vol_fname) exec_applyTransforms(transforms=transforms, inverses=inverses, input_image=volumes_list[x], ref_image=ref_file, output_image=warped_vol_fname, mask=False) sample_volume = sitk.ReadImage(warped_volumes[0]) shape = sitk.GetArrayFromImage(sample_volume).shape combined = np.zeros((num_volumes, shape[0], shape[1], shape[2])) i = 0 for file in warped_volumes: combined[i, :, :, :] = sitk.GetArrayFromImage( sitk.ReadImage(file))[:, :, :] i = i + 1 if (i != num_volumes): raise ValueError("Error occured with Merge.") combined_image = sitk.GetImageFromArray(combined, isVector=False) # set metadata and affine for the newly constructed 4D image header_source = sitk.ReadImage(in_file) combined_image = copyInfo_4DImage(combined_image, sample_volume, header_source) sitk.WriteImage(combined_image, out_file) return out_file
tmppath+'/inputs/sub-token_bold.nii.gz') resampled = resample_image_spacing(sitk.ReadImage(mask), spacing) array = sitk.GetArrayFromImage(resampled) array[array < 1] = 0 array[array > 1] = 1 binarized = sitk.GetImageFromArray(array, isVector=False) binarized.CopyInformation(resampled) sitk.WriteImage(binarized, tmppath+'/inputs/token_mask.nii.gz') array[:, :, :6] = 0 binarized = sitk.GetImageFromArray(array, isVector=False) binarized.CopyInformation(resampled) sitk.WriteImage(binarized, tmppath+'/inputs/token_mask_half.nii.gz') sitk.WriteImage(copyInfo_4DImage(sitk.ReadImage(tmppath+'/inputs/sub-token_bold.nii.gz'), sitk.ReadImage(tmppath + '/inputs/sub-token_T1w.nii.gz'), sitk.ReadImage(tmppath+'/inputs/sub-token_bold.nii.gz')), tmppath+'/inputs/sub-token_bold.nii.gz') command = f"rabies --verbose 1 preprocess {tmppath}/inputs {tmppath}/outputs --anat_inho_cor_method disable --bold_inho_cor_method disable \ --anat_template {tmppath}/inputs/sub-token_T1w.nii.gz --brain_mask {tmppath}/inputs/token_mask.nii.gz --WM_mask {tmppath}/inputs/token_mask.nii.gz --CSF_mask {tmppath}/inputs/token_mask.nii.gz --vascular_mask {tmppath}/inputs/token_mask.nii.gz --labels {tmppath}/inputs/token_mask.nii.gz \ --coreg_script no_reg --atlas_reg_script no_reg --data_type int16 --bold_only --fast_commonspace --detect_dummy \ --tpattern seq" process = subprocess.run( command, check=True, shell=True, ) os.remove(f'{tmppath}/outputs/rabies_preprocess.pkl') command = f"rabies --verbose 1 preprocess {tmppath}/inputs {tmppath}/outputs --anat_inho_cor_method disable --bold_inho_cor_method disable \ --anat_template {tmppath}/inputs/sub-token_T1w.nii.gz --brain_mask {tmppath}/inputs/token_mask.nii.gz --WM_mask {tmppath}/inputs/token_mask_half.nii.gz --CSF_mask {tmppath}/inputs/token_mask_half.nii.gz --vascular_mask {tmppath}/inputs/token_mask_half.nii.gz --labels {tmppath}/inputs/token_mask.nii.gz \ --coreg_script no_reg --atlas_reg_script no_reg --data_type int16 --HMC_option 0 --commonspace_masking --coreg_masking --brain_extraction"
def _run_interface(self, runtime): from nipype import logging log = logging.getLogger('nipype.workflow') in_nii = sitk.ReadImage(self.inputs.in_file, self.inputs.rabies_data_type) if not in_nii.GetDimension()==4: raise ValueError(f"Input image {self.inputs.in_file} is not 4-dimensional.") data_slice = sitk.GetArrayFromImage(in_nii)[:50, :, :, :] n_volumes_to_discard = _get_vols_to_discard(in_nii) filename_split = pathlib.Path(self.inputs.in_file).name.rsplit(".nii") out_ref_fname = os.path.abspath( f'{filename_split[0]}_bold_ref.nii.gz') if (not n_volumes_to_discard == 0) and self.inputs.detect_dummy: log.info("Detected "+str(n_volumes_to_discard) + " dummy scans. Taking the median of these volumes as reference EPI.") median_image_data = np.median( data_slice[:n_volumes_to_discard, :, :, :], axis=0) out_bold_file = os.path.abspath( f'{filename_split[0]}_cropped_dummy.nii.gz') img_array = sitk.GetArrayFromImage( in_nii)[n_volumes_to_discard:, :, :, :] image_4d = copyInfo_4DImage(sitk.GetImageFromArray( img_array, isVector=False), in_nii, in_nii) sitk.WriteImage(image_4d, out_bold_file) else: out_bold_file = self.inputs.in_file n_volumes_to_discard = 0 if self.inputs.detect_dummy: log.info( "Detected no dummy scans. Generating the ref EPI based on multiple volumes.") # if no dummy scans, will generate a median from a subset of max 100 # slices of the time series if in_nii.GetSize()[-1] > 100: slice_fname = os.path.abspath("slice.nii.gz") image_4d = copyInfo_4DImage(sitk.GetImageFromArray( data_slice[20:100, :, :, :], isVector=False), in_nii, in_nii) sitk.WriteImage(image_4d, slice_fname) median_fname = os.path.abspath("median.nii.gz") image_3d = copyInfo_3DImage(sitk.GetImageFromArray( np.median(data_slice[20:100, :, :, :], axis=0), isVector=False), in_nii) sitk.WriteImage(image_3d, median_fname) else: slice_fname = self.inputs.in_file median_fname = os.path.abspath("median.nii.gz") image_3d = copyInfo_3DImage(sitk.GetImageFromArray( np.median(data_slice, axis=0), isVector=False), in_nii) sitk.WriteImage(image_3d, median_fname) # First iteration to generate reference image. res = antsMotionCorr(in_file=slice_fname, ref_file=median_fname, prebuilt_option=self.inputs.HMC_option, transform_type='Rigid', second=False, rabies_data_type=self.inputs.rabies_data_type).run() median = np.median(sitk.GetArrayFromImage(sitk.ReadImage( res.outputs.mc_corrected_bold, self.inputs.rabies_data_type)), axis=0) tmp_median_fname = os.path.abspath("tmp_median.nii.gz") image_3d = copyInfo_3DImage( sitk.GetImageFromArray(median, isVector=False), in_nii) sitk.WriteImage(image_3d, tmp_median_fname) # Second iteration to generate reference image. res = antsMotionCorr(in_file=slice_fname, ref_file=tmp_median_fname, prebuilt_option=self.inputs.HMC_option, transform_type='Rigid', second=True, rabies_data_type=self.inputs.rabies_data_type).run() # evaluate a trimmed mean instead of a median, trimming the 5% extreme values from scipy import stats median_image_data = stats.trim_mean(sitk.GetArrayFromImage(sitk.ReadImage( res.outputs.mc_corrected_bold, self.inputs.rabies_data_type)), 0.05, axis=0) # median_image_data is a 3D array of the median image, so creates a new nii image # saves it image_3d = copyInfo_3DImage(sitk.GetImageFromArray( median_image_data, isVector=False), in_nii) sitk.WriteImage(image_3d, out_ref_fname) # denoise the resulting reference image through non-local mean denoising # Denoising reference image. command = f'DenoiseImage -d 3 -i {out_ref_fname} -o {out_ref_fname}' rc = run_command(command) setattr(self, 'ref_image', out_ref_fname) setattr(self, 'bold_file', out_bold_file) return runtime
def slice_timing_correction(in_file, tr='auto', tpattern='alt', rabies_data_type=8): ''' This functions applies slice-timing correction on the anterior-posterior slice acquisition direction. The input image, assumed to be in RAS orientation (accoring to nibabel; note that the nibabel reading of RAS corresponds to LPI for AFNI). The A and S dimensions will be swapped to apply AFNI's 3dTshift STC with a quintic fitting function, which can only be applied to the Z dimension of the data matrix. The corrected image is then re-created with proper axes and the corrected timeseries. **Inputs** in_file BOLD series NIfTI file in RAS orientation. ignore Number of non-steady-state volumes detected at beginning of ``bold_file`` tr TR of the BOLD image. tpattern Input to AFNI's 3dTshift -tpattern option, which specifies the directionality of slice acquisition, or whether it is sequential or interleaved. **Outputs** out_file Slice-timing corrected BOLD series NIfTI file ''' import os import SimpleITK as sitk import numpy as np if tpattern == "alt": tpattern = 'alt-z' elif tpattern == "seq": tpattern = 'seq-z' else: raise ValueError('Invalid --tpattern provided.') img = sitk.ReadImage(in_file, rabies_data_type) if tr == 'auto': tr = str(img.GetSpacing()[3]) + 's' else: tr = str(tr) + 's' # get image data img_array = sitk.GetArrayFromImage(img) shape = img_array.shape new_array = np.zeros([shape[0], shape[2], shape[1], shape[3]]) for i in range(shape[2]): new_array[:, i, :, :] = img_array[:, :, i, :] image_out = sitk.GetImageFromArray(new_array, isVector=False) sitk.WriteImage(image_out, 'STC_temp.nii.gz') command = f'3dTshift -quintic -prefix temp_tshift.nii.gz -tpattern {tpattern} -TR {tr} STC_temp.nii.gz' from rabies.utils import run_command rc = run_command(command) tshift_img = sitk.ReadImage('temp_tshift.nii.gz', rabies_data_type) tshift_array = sitk.GetArrayFromImage(tshift_img) new_array = np.zeros(shape) for i in range(shape[2]): new_array[:, :, i, :] = tshift_array[:, i, :, :] image_out = sitk.GetImageFromArray(new_array, isVector=False) from rabies.utils import copyInfo_4DImage image_out = copyInfo_4DImage(image_out, img, img) import pathlib # Better path manipulation filename_split = pathlib.Path(in_file).name.rsplit(".nii") out_file = os.path.abspath(filename_split[0] + '_tshift.nii.gz') sitk.WriteImage(image_out, out_file) return out_file