def define_good_voxels(input_fMRI_4D, ribbon_vol, goodvoxels_vol, tmpdir, NeighborhoodSmoothing = "5", CI_limit = "0.5"): ''' does diagnostics on input_fMRI_4D volume, within the ribbon_out mask, produces a goodvoxels_vol volume mask ''' ## calculate Coefficient of Variation (cov) of the fMRI tmean_vol = os.path.join(tmpdir, 'Mean.nii.gz') TstdVol = os.path.join(tmpdir, 'SD.nii.gz') cov_vol = os.path.join(tmpdir, 'cov.nii.gz') run(['fslmaths', input_fMRI_4D, '-Tmean', tmean_vol, '-odt', 'float']) run(['fslmaths', input_fMRI_4D, '-Tstd', TstdVol, '-odt', 'float']) run(['fslmaths', TstdVol, '-div', tmean_vol, cov_vol]) ## calculate a cov ribbon - modulated by the NeighborhoodSmoothing factor cov_ribbon = os.path.join(tmpdir, 'cov_ribbon.nii.gz') cov_ribbon_norm = os.path.join(tmpdir, 'cov_ribbon_norm.nii.gz') SmoothNorm = os.path.join(tmpdir, 'SmoothNorm.nii.gz') cov_ribbon_norm_smooth = os.path.join(tmpdir, 'cov_ribbon_norm_smooth.nii.gz') cov_norm_modulate = os.path.join(tmpdir, 'cov_norm_modulate.nii.gz') cov_norm_modulate_ribbon = os.path.join(tmpdir, 'cov_norm_modulate_ribbon.nii.gz') run(['fslmaths', cov_vol,'-mas', ribbon_vol, cov_ribbon]) cov_ribbonMean = first_word(get_stdout(['fslstats', cov_ribbon, '-M'])) cov_ribbonMean = cov_ribbonMean.rstrip(os.linesep) ## remove return run(['fslmaths', cov_ribbon, '-div', cov_ribbonMean, cov_ribbon_norm]) run(['fslmaths', cov_ribbon_norm, '-bin', '-s', NeighborhoodSmoothing, SmoothNorm]) run(['fslmaths', cov_ribbon_norm, '-s', NeighborhoodSmoothing, '-div', SmoothNorm, '-dilD', cov_ribbon_norm_smooth]) run(['fslmaths', cov_vol, '-div', cov_ribbonMean, '-div', cov_ribbon_norm_smooth, cov_norm_modulate]) run(['fslmaths', cov_norm_modulate, '-mas', ribbon_vol, cov_norm_modulate_ribbon]) ## get stats from the modulated cov ribbon file and log them ribbonMean = first_word(get_stdout(['fslstats', cov_norm_modulate_ribbon, '-M'])) logger.info('Ribbon Mean: {}'.format(ribbonMean)) ribbonSTD = first_word(get_stdout(['fslstats', cov_norm_modulate_ribbon, '-S'])) logger.info('Ribbon STD: {}'.format(ribbonSTD)) ribbonLower = float(ribbonMean) - (float(ribbonSTD)*float(CI_limit)) logger.info('Ribbon Lower: {}'.format(ribbonLower)) ribbonUpper = float(ribbonMean) + (float(ribbonSTD)*float(CI_limit)) logger.info('Ribbon Upper: {}'.format(ribbonUpper)) ## get a basic brain mask from the mean img bmaskVol = os.path.join(tmpdir, 'mask.nii.gz') run(['fslmaths', tmean_vol, '-bin', bmaskVol]) ## make a goodvoxels_vol mask img run(['fslmaths', cov_norm_modulate, '-thr', str(ribbonUpper), '-bin', '-sub', bmaskVol, '-mul', '-1', goodvoxels_vol]) return(tmean_vol, cov_vol)
def __set_func_4D(self, func_4D): ''' parse the input func file and test it's validity ''' if not os.path.isfile(func_4D): logger.error("fMRI input {} does not exist :(..Exiting".format(func_4D)) sys.exit(1) ## read the number of TR's and the TR from the header num_TR = first_word(get_stdout(['fslval', func_4D, 'dim4'])) #self.middle_TR = int(self.num_TR)//2 TR_in_ms = first_word(get_stdout(['fslval', func_4D, 'pixdim4'])) return func_4D, num_TR, TR_in_ms
def dilate_out_low_intensity_voxels(settings, hemisphere, mesh_settings): ''' looks for voxels of low intensity and marks dilates to try to correct for them Hopefully this is an unnessary step with volume to surface mapping is done well ''' intput_func_gii = func_gii_file(settings.subject.id, settings.fmri_label, hemisphere, mesh_settings) lowvoxels_gii = func_gii_file(settings.subject.id, 'lowvoxels', hemisphere, mesh_settings) middle_TR = int(settings.num_TR) // 2 low_intensity_thres = get_stdout([ 'wb_command', '-metric-stats', input_func_gii, '-percentile', str(settings.dilate_percent_below), '-column', str(middle_TR), '-roi', medial_wall_roi_file(settings.subject.id, hemisphere, mesh_settings) ]) run([ 'wb_command', '-metric-math', '"(x < {})"'.format(low_intensity_thres), lowvoxels_gii, '-var', 'x', input_func_gii, '-column', str(middle_TR) ]) run([ 'wb_command', '-metric-dilate', input_func_gii, medial_wall_roi_file(settings.subject.id, hemisphere, mesh_settings), str(settings.dilate_factor), input_func_gii, '-bad-vertex-roi', lowvoxels_gii, '-nearest' ])
def log_build_environment(): '''print the running environment info to the logs (info)''' logger.info("{}---### Environment Settings ###---".format(os.linesep)) logger.info("Username: {}".format(get_stdout(['whoami'], echo = False).replace(os.linesep,''))) logger.info(ciftify.config.system_info()) logger.info(ciftify.config.ciftify_version(os.path.basename(__file__))) logger.info(ciftify.config.wb_command_version()) logger.info(ciftify.config.freesurfer_version()) logger.info(ciftify.config.fsl_version()) logger.info("---### End of Environment Settings ###---{}".format(os.linesep))
def cifti_info(filename): '''runs wb_command -file-information" to try to figure out what the file is made off''' c_info = get_stdout( ['wb_command', '-file-information', filename, '-no-map-info']) cinfo = {} for line in c_info.split(os.linesep): if 'Structure' in line: cinfo['has_LSurf'] = True if 'CortexLeft' in line else False cinfo['has_RSurf'] = True if 'CortexRight' in line else False if 'Maps to Surface' in line: cinfo['maps_to_surf'] = True if "true" in line else False if 'Maps to Volume' in line: cinfo['maps_to_volume'] = True if "true" in line else False return cinfo
def run_ciftify_subject_fmri(arguments, tmpdir): input_fMRI = arguments["<func.nii.gz>"] if arguments['--ciftify-work-dir']: WorkDir = arguments['--ciftify-work-dir'] else: WorkDir = arguments["--hcp-data-dir"] Subject = arguments["<Subject>"] NameOffMRI = arguments["<NameOffMRI>"] SmoothingFWHM = arguments["--SmoothingFWHM"] DilateBelowPct = arguments["--DilateBelowPct"] OutputSurfDiagnostics = arguments['--OutputSurfDiagnostics'] noMNItransform = arguments['--already-in-MNI'] RegTemplate = arguments['--FLIRT-template'] FLIRT_dof = arguments['--FLIRT-dof'] FLIRT_cost = arguments['--FLIRT-cost'] reg_name = arguments['--reg-name'] if WorkDir == None: WorkDir = ciftify.config.find_work_dir() ## write a bunch of info about the environment to the logs log_build_environment() logger.info('Arguments:') logger.info("\tinput_fMRI: {}".format(input_fMRI)) if not os.path.isfile(input_fMRI): logger.error("input_fMRI does not exist :(..Exiting") sys.exit(1) logger.info("\tHCP_DATA: {}".format(WorkDir)) logger.info("\tSubject: {}".format(Subject)) logger.info("\tNameOffMRI: {}".format(NameOffMRI)) logger.info("\tSurface Registration: {}".format(reg_name)) if reg_name == "MSMSulc": RegName = "MSMSulc" elif reg_name == "FS": RegName = "reg.reg_LR" else: logger.critical('--reg-name argument must be "FS" or "MSMSulc"') sys.exit(1) if SmoothingFWHM: logger.info("\tSmoothingFWHM: {}".format(SmoothingFWHM)) if DilateBelowPct: logger.info( "\tWill fill holes defined as data with intensity below {} percentile" .format(DilateBelowPct)) # Setup PATHS GrayordinatesResolution = "2" LowResMesh = "32" DilateFactor = "10" #Templates and settings AtlasSpaceFolder = os.path.join(WorkDir, Subject, "MNINonLinear") DownSampleFolder = os.path.join(AtlasSpaceFolder, "fsaverage_LR32k") ResultsFolder = os.path.join(AtlasSpaceFolder, "Results", NameOffMRI) AtlasSpaceNativeFolder = os.path.join(AtlasSpaceFolder, "Native") logger.info("The following settings are set by default:") logger.info( "\nGrayordinatesResolution: {}".format(GrayordinatesResolution)) logger.info('\nLowResMesh: {}k'.format(LowResMesh)) logger.info( 'Native space surfaces are in: {}'.format(AtlasSpaceNativeFolder)) L_sphere = os.path.join( AtlasSpaceNativeFolder, '{}.L.sphere.{}.native.surf.gii'.format(Subject, RegName)) if not os.path.exists(L_sphere): logger.critical("Registration Sphere {} not found".format(L_sphere)) sys.exit(1) logger.info( 'The resampled surfaces (those matching the final result are in: {})'. format(DownSampleFolder)) # PipelineScripts=${HCPPIPEDIR_fMRISurf} input_fMRI_4D = os.path.join(ResultsFolder, '{}.nii.gz'.format(NameOffMRI)) input_fMRI_3D = os.path.join(tmpdir, '{}_Mean.nii.gz'.format(NameOffMRI)) # output files if OutputSurfDiagnostics: DiagnosticsFolder = os.path.join(ResultsFolder, 'RibbonVolumeToSurfaceMapping') logger.info("Diagnostic Files will be written to: {}".format( DiagnosticsFolder)) run(['mkdir', '-p', DiagnosticsFolder]) else: DiagnosticsFolder = tmpdir ###### from end of volume mapping pipeline ## copy inputs into the ResultsFolder run(['mkdir', '-p', ResultsFolder]) ## read the number of TR's and the TR from the header TR_num = first_word(get_stdout(['fslval', input_fMRI, 'dim4'])) logger.info('Number of TRs: {}'.format(TR_num)) MiddleTR = int(TR_num) // 2 logger.info('Middle TR: {}'.format(MiddleTR)) TR_vol = first_word(get_stdout(['fslval', input_fMRI, 'pixdim4'])) logger.info('TR(ms): {}'.format(TR_vol)) ## either transform or copy the input_fMRI if noMNItransform: run(['cp', input_fMRI, input_fMRI_4D]) else: logger.info(section_header('MNI Transform')) logger.info( 'Running transform to MNIspace with costfunction {} and dof {}'. format(FLIRT_cost, FLIRT_dof)) transform_to_MNI(input_fMRI, input_fMRI_4D, FLIRT_cost, FLIRT_dof, WorkDir, Subject, RegTemplate, tmpdir) #Make fMRI Ribbon #Noisy Voxel Outlier Exclusion #Ribbon-based Volume to Surface mapping and resampling to standard surface logger.info(section_header('Making fMRI Ribbon')) run(['fslmaths', input_fMRI_4D, '-Tmean', input_fMRI_3D]) ribbon_vol = os.path.join(DiagnosticsFolder, 'ribbon_only.nii.gz') make_cortical_ribbon(Subject, AtlasSpaceNativeFolder, input_fMRI_3D, ribbon_vol) goodvoxels_vol = os.path.join(DiagnosticsFolder, 'goodvoxels.nii.gz') tmean_vol, cov_vol = define_good_voxels(input_fMRI_4D, ribbon_vol, goodvoxels_vol, tmpdir) logger.info(section_header('Mapping fMRI to 32k Surface')) for Hemisphere in ["L", "R"]: ## the input surfaces for this section in the AtlasSpaceNativeFolder mid_surf_native = os.path.join( AtlasSpaceNativeFolder, '{}.{}.midthickness.native.surf.gii'.format(Subject, Hemisphere)) pial_surf = os.path.join( AtlasSpaceNativeFolder, '{}.{}.pial.native.surf.gii'.format(Subject, Hemisphere)) white_surf = os.path.join( AtlasSpaceNativeFolder, '{}.{}.white.native.surf.gii'.format(Subject, Hemisphere)) roi_native_gii = os.path.join( AtlasSpaceNativeFolder, '{}.{}.roi.native.shape.gii'.format(Subject, Hemisphere)) sphere_reg_native = os.path.join( AtlasSpaceNativeFolder, '{}.{}.sphere.{}.native.surf.gii'.format(Subject, Hemisphere, RegName)) ## the inputs for this section from the DownSampleFolder mid_surf_32k = os.path.join( DownSampleFolder, '{}.{}.midthickness.{}k_fs_LR.surf.gii'.format( Subject, Hemisphere, LowResMesh)) roi_32k_gii = os.path.join( DownSampleFolder, '{}.{}.atlasroi.{}k_fs_LR.shape.gii'.format( Subject, Hemisphere, LowResMesh)) sphere_reg_32k = os.path.join( DownSampleFolder, '{}.{}.sphere.{}k_fs_LR.surf.gii'.format(Subject, Hemisphere, LowResMesh)) ## now finally, actually project the fMRI input input_func_native = os.path.join( tmpdir, '{}.{}.native.func.gii'.format(NameOffMRI, Hemisphere)) run([ 'wb_command', '-volume-to-surface-mapping', input_fMRI_4D, mid_surf_native, input_func_native, '-ribbon-constrained', white_surf, pial_surf, '-volume-roi', goodvoxels_vol ]) ## dilate to get rid of wholes caused by the goodvoxels_vol mask run([ 'wb_command', '-metric-dilate', input_func_native, mid_surf_native, DilateFactor, input_func_native, '-nearest' ]) ## Erin's new addition - find what is below a certain percentile and dilate.. ## Erin's new addition - find what is below a certain percentile and dilate.. if DilateBelowPct: DilThres = get_stdout([ 'wb_command', '-metric-stats', input_func_native, '-percentile', str(DilateBelowPct), '-column', str(MiddleTR), '-roi', roi_native_gii ]) lowvoxels_gii = os.path.join( tmpdir, '{}.lowvoxels.native.func.gii'.format(Hemisphere)) run([ 'wb_command', '-metric-math', '"(x < {})"'.format(DilThres), lowvoxels_gii, '-var', 'x', input_func_native, '-column', str(MiddleTR) ]) run([ 'wb_command', '-metric-dilate', input_func_native, mid_surf_native, str(DilateFactor), input_func_native, '-bad-vertex-roi', lowvoxels_gii, '-nearest' ]) ## back to the HCP program - do the mask and resample ## mask resample than mask combo input_func_32k = os.path.join( tmpdir, '{}.{}.atlasroi.{}k_fs_LR.func.gii'.format(NameOffMRI, Hemisphere, LowResMesh)) mask_and_resample(input_func_native, input_func_32k, roi_native_gii, roi_32k_gii, mid_surf_native, mid_surf_32k, sphere_reg_native, sphere_reg_32k) if OutputSurfDiagnostics: logger.info( section_header('Writing Surface Mapping Diagnotic Files')) for mapname in ["mean", "cov"]: if mapname == "mean": map_vol = tmean_vol if mapname == "cov": map_vol = cov_vol ## the output directories for this section map_native_gii = os.path.join( tmpdir, '{}.{}.native.func.gii'.format(mapname, Hemisphere)) map_32k_gii = os.path.join( tmpdir, "{}.{}.{}k_fs_LR.func.gii".format(Hemisphere, mapname, LowResMesh)) run([ 'wb_command', '-volume-to-surface-mapping', map_vol, mid_surf_native, map_native_gii, '-ribbon-constrained', white_surf, pial_surf, '-volume-roi', goodvoxels_vol ]) run([ 'wb_command', '-metric-dilate', map_native_gii, mid_surf_native, DilateFactor, map_native_gii, '-nearest' ]) mask_and_resample(map_native_gii, map_32k_gii, roi_native_gii, roi_32k_gii, mid_surf_native, mid_surf_32k, sphere_reg_native, sphere_reg_32k) mapall_native_gii = os.path.join( tmpdir, '{}_all.{}.native.func.gii'.format(mapname, Hemisphere)) mapall_32k_gii = os.path.join( tmpdir, "{}.{}_all.{}k_fs_LR.func.gii".format( Hemisphere, mapname, LowResMesh)) run([ 'wb_command', '-volume-to-surface-mapping', map_vol, mid_surf_native, mapall_native_gii, '-ribbon-constrained', white_surf, pial_surf ]) mask_and_resample(mapall_native_gii, mapall_32k_gii, roi_native_gii, roi_32k_gii, mid_surf_native, mid_surf_32k, sphere_reg_native, sphere_reg_32k) ## now project the goodvoxels to the surface goodvoxels_native_gii = os.path.join( tmpdir, '{}.goodvoxels.native.func.gii'.format(Hemisphere)) goodvoxels_32k_gii = os.path.join( tmpdir, '{}.goodvoxels.{}k_fs_LR.func.gii'.format( Hemisphere, LowResMesh)) run([ 'wb_command', '-volume-to-surface-mapping', goodvoxels_vol, mid_surf_native, goodvoxels_native_gii, '-ribbon-constrained', white_surf, pial_surf ]) mask_and_resample(goodvoxels_native_gii, goodvoxels_32k_gii, roi_native_gii, roi_32k_gii, mid_surf_native, mid_surf_32k, sphere_reg_native, sphere_reg_32k) ## Also ouput the resampled low voxels if DilateBelowPct: lowvoxels_32k_gii = os.path.join( tmpdir, '{}.lowvoxels.{}k_fs_LR.func.gii'.format( Hemisphere, LowResMesh)) mask_and_resample(lowvoxels_gii, lowvoxels_32k_gii, roi_native_gii, roi_32k_gii, mid_surf_native, mid_surf_32k, sphere_reg_native, sphere_reg_32k) if OutputSurfDiagnostics: Maps = ['goodvoxels', 'mean', 'mean_all', 'cov', 'cov_all'] if DilateBelowPct: Maps.append('lowvoxels') # import pbd; pdb.set_trace() for Map in Maps: run([ 'wb_command', '-cifti-create-dense-scalar', os.path.join( DiagnosticsFolder, '{}.atlasroi.{}k_fs_LR.dscalar.nii'.format( Map, LowResMesh)), '-left-metric', os.path.join(tmpdir, 'L.{}.{}k_fs_LR.func.gii'.format(Map, LowResMesh)), '-roi-left', os.path.join( DownSampleFolder, '{}.L.atlasroi.{}k_fs_LR.shape.gii'.format( Subject, LowResMesh)), '-right-metric', os.path.join(tmpdir, 'R.{}.{}k_fs_LR.func.gii'.format(Map, LowResMesh)), '-roi-right', os.path.join( DownSampleFolder, '{}.R.atlasroi.{}k_fs_LR.shape.gii'.format( Subject, LowResMesh)) ]) ############ The subcortical resampling step... logger.info(section_header("Subcortical Processing")) logger.info("VolumefMRI: {}".format(input_fMRI_4D)) Atlas_Subcortical = os.path.join( tmpdir, '{}_AtlasSubcortical_s0.nii.gz'.format(NameOffMRI)) AtlasROIvols = os.path.join( AtlasSpaceFolder, "ROIs", 'Atlas_ROIs.{}.nii.gz'.format(GrayordinatesResolution)) atlas_roi_vol = subcortical_atlas(input_fMRI_4D, AtlasSpaceFolder, ResultsFolder, GrayordinatesResolution, tmpdir) resample_subcortical(input_fMRI_4D, atlas_roi_vol, AtlasROIvols, Atlas_Subcortical, tmpdir) #Generation of Dense Timeseries logger.info(section_header("Generation of Dense Timeseries")) cifti_output_s0 = os.path.join( ResultsFolder, '{}_Atlas_s0.dtseries.nii'.format(NameOffMRI)) run([ 'wb_command', '-cifti-create-dense-timeseries', cifti_output_s0, '-volume', Atlas_Subcortical, AtlasROIvols, '-left-metric', os.path.join( tmpdir, '{}.L.atlasroi.{}k_fs_LR.func.gii'.format(NameOffMRI, LowResMesh)), '-roi-left', os.path.join( DownSampleFolder, '{}.L.atlasroi.{}k_fs_LR.shape.gii'.format(Subject, LowResMesh)), '-right-metric', os.path.join( tmpdir, '{}.R.atlasroi.{}k_fs_LR.func.gii'.format(NameOffMRI, LowResMesh)), '-roi-right', os.path.join( DownSampleFolder, '{}.R.atlasroi.{}k_fs_LR.shape.gii'.format(Subject, LowResMesh)), '-timestep', TR_vol ]) #########cifti smoothing ################ if SmoothingFWHM: logger.info(section_header("Smoothing Output")) Sigma = FWHM2Sigma(SmoothingFWHM) logger.info("FWHM: {}".format(SmoothingFWHM)) logger.info("Sigma: {}".format(Sigma)) run([ 'wb_command', '-cifti-smoothing', cifti_output_s0, str(Sigma), str(Sigma), 'COLUMN', os.path.join( ResultsFolder, '{}_Atlas_s{}.dtseries.nii'.format(NameOffMRI, SmoothingFWHM)), '-left-surface', os.path.join( DownSampleFolder, '{}.L.midthickness.{}k_fs_LR.surf.gii'.format( Subject, LowResMesh)), '-right-surface', os.path.join( DownSampleFolder, '{}.R.midthickness.{}k_fs_LR.surf.gii'.format( Subject, LowResMesh)) ])