diff --git a/fMRISurface/GenericHippocampusfMRISurfaceProcessingPipeline.sh b/fMRISurface/GenericHippocampusfMRISurfaceProcessingPipeline.sh new file mode 100755 index 000000000..2ee49f627 --- /dev/null +++ b/fMRISurface/GenericHippocampusfMRISurfaceProcessingPipeline.sh @@ -0,0 +1,153 @@ + #!/bin/bash + + # Requirements for this script + # installed versions of: FSL, Connectome Workbench (wb_command) + # environment: HCPPIPEDIR, FSLDIR, CARET7DIR + + ########################################## PIPELINE OVERVIEW ########################################## + + # This script combines surface metric files from the left and right hippocampus and dentate gyrus + # into CIFTI files for each requested non-native mesh. + # + # The script creates: + # 1. Dense scalar CIFTI files containing mean fMRI intensity of both good voxels and all voxels. + # 2. Dense scalar CIFTI files containing coefficient of variation (COV) of both good voxels and all voxels. + # 3. A dense scalar CIFTI file containing the good-voxel mask when good-voxel processing is enabled. + # 4. A dense timeseries CIFTI file containing smooth fMRI timeseries. + # 5. A dense scalar CIFTI file containing the fMRI variance normalization (VN) data. + # + # Native-mesh files are retained as processing intermediates and are not converted to CIFTI. + + ########################################## OUTPUT DIRECTORIES ########################################## + + # ResultsFolder: + # Contains the final hippocampal fMRI CIFTI outputs: + # ${NameOffMRI}_AtlasHipp${ProcString}.${Mesh}.dtseries.nii + # ${NameOffMRI}_AtlasHipp${ProcString}_vn.${Mesh}.dscalar.nii + # + # WorkingDirectory: + # Contains the hippocampal volume-to-surface mapping outputs and QC CIFTI files: + # ${Subject}.allStructures_mean.${Mesh}.dscalar.nii + # ${Subject}.allStructures_mean_all.${Mesh}.dscalar.nii + # ${Subject}.allStructures_cov.${Mesh}.dscalar.nii + # ${Subject}.allStructures_cov_all.${Mesh}.dscalar.nii + # ${Subject}.allStructures_goodvoxels.${Mesh}.dscalar.nii + # + + ################################################ SUPPORT FUNCTIONS ################################################## + set -eu + pipedirguessed=0 + if [[ "${HCPPIPEDIR:-}" == "" ]] + then + pipedirguessed=1 + # Fix this if the script is more than one level below HCPPIPEDIR + export HCPPIPEDIR="$(dirname -- "$0")/.." + fi + + source "${HCPPIPEDIR}/global/scripts/debug.shlib" "$@" # Debugging functions; also sources log.shlib + source "${HCPPIPEDIR}/global/scripts/log.shlib" "$@" # Debugging functions; also sources log.shlib + + source "${HCPPIPEDIR}/global/scripts/newopts.shlib" "$@" + source "${HCPPIPEDIR}/global/scripts/processingmodecheck.shlib" # Check processing mode requirements + + opts_SetScriptDescription "Run hippocampal fMRISurface processing" + + opts_AddMandatory '--studyfolder' 'Path' 'path' "folder containing all subjects" "--path" + + opts_AddMandatory '--subject' 'Subject' 'subject ID' "" + + opts_AddMandatory '--fmriname' 'NameOffMRI' 'string' 'fMRI run name, for example rfMRI_REST1_LR' + + opts_AddOptional '--procstring' 'ProcString' 'string' 'processing suffix appended to the 4D fMRI filename; include the leading underscore' "" + + opts_AddMandatory '--smoothingFWHM' 'SmoothingFWHM' 'number' 'smoothing FWHM (mm)' + + opts_AddOptional '--goodvoxel' 'doGoodVoxels' 'YES OR NO' "Controls whether to do goodVoxel procedure (default = YES)" "YES" + + opts_AddOptional '--factor' 'factor' 'number' "Scaling factor for eliminating high COV voxels (default = 1.5)" "1.5" + + opts_AddOptional '--resample_mesh' 'MeshString' 'string' 'Resample native mesh to: 512, 2k, 8k, or 18k. Use quote for multiple meshes, e.g. "512 2k 8k"' "2k" + opts_ParseArguments "$@" + + if ((pipedirguessed)) + then + log_Err_Abort "HCPPIPEDIR is not set; first source your edited copy of Examples/Scripts/SetUpHCPPipeline.sh" + fi + + opts_ShowValues + + "${HCPPIPEDIR}/show_version" + + # ------------------------------------------------------------------------------ + # Verify required environment variables are set + # ------------------------------------------------------------------------------ + + log_Check_Env_Var HCPPIPEDIR + log_Check_Env_Var FSLDIR + log_Check_Env_Var CARET7DIR + + HCPPIPEDIR_fMRISurf="${HCPPIPEDIR}/fMRISurface/scripts" + + # ------------------------------------------------------------------------------ + # Parse command-line options + # ------------------------------------------------------------------------------ + + log_Msg "Platform Information Follows:" + uname -a + + # ------------------------------------------------------------------------------ + # Set up paths + # ------------------------------------------------------------------------------ + + MainSubjectFolder="${Path}/${Subject}" + AtlasSpaceFolder="${MainSubjectFolder}/MNINonLinear" + InputResultsFolder="${AtlasSpaceFolder}/Results/${NameOffMRI}" + ResultsFolder="${AtlasSpaceFolder}/Results/${NameOffMRI}" + + WorkingDirectory="${ResultsFolder}/HippocampalVolumeToSurfaceMapping" + mkdir -p "${WorkingDirectory}" + + VolumefMRI="${InputResultsFolder}/${NameOffMRI}${ProcString}.nii.gz" + + SBRef="${InputResultsFolder}/${NameOffMRI}_SBRef.nii.gz" + + HippUnfoldFolder="${AtlasSpaceFolder}/HippUnfold" + + if [ ! -f "${VolumefMRI}" ]; then + log_Err_Abort "Cannot find selected fMRI file: ${VolumefMRI}" + fi + + if [ ! -f "${SBRef}" ]; then + log_Err_Abort "Cannot find selected SBRef file: ${SBRef}" + fi + + #Parse MeshString into a mesh array + for Mesh in ${MeshString}; do + if [[ " 512 2k 8k 18k " != *" ${Mesh} "* ]]; then + log_Err_Abort "Invalid mesh: ${Mesh}" + fi + done + Meshes="native ${MeshString}" + + log_Msg "Selected fMRI file: ${VolumefMRI}" + log_Msg "Selected SBRef file: ${SBRef}" + + # ------------------------------------------------------------------------------ + # Combining ROIs into a single CIFTI time series and vn file + # ------------------------------------------------------------------------------ + + log_Msg "mkdir -p ${WorkingDirectory}" + log_Msg "Hippocampal Volume To Surface Mapping" + + + # Generate fMRI time series for each of the hippocampal structures: L hipp, R hipp, L dentate, R dentate + "${HCPPIPEDIR_fMRISurf}/HippocampalVolumeToSurfaceMapping.sh" "${ResultsFolder}" "${WorkingDirectory}" "${Subject}" "${HippUnfoldFolder}" "${VolumefMRI}" "${SBRef}" "${doGoodVoxels}" "${factor}" "${Meshes}" + + #Surface Smoothing of each hippocampal structure + "${HCPPIPEDIR_fMRISurf}/HippocampalSmoothing.sh" "${HippUnfoldFolder}" "${WorkingDirectory}" "${Subject}" "${SmoothingFWHM}" "${Meshes}" + + #Integration of the 4 hippocampal structures into single CIFTI files and cleanup of intermediate files + "${HCPPIPEDIR_fMRISurf}/CreateHippocampalCIFTIs.sh" "${ResultsFolder}" "${WorkingDirectory}" "${Subject}" "${NameOffMRI}" "${ProcString}" "${Meshes}" "${doGoodVoxels}" "${SmoothingFWHM}" "${VolumefMRI}" + + log_Msg "GenericHippocampusfMRISurfaceProcessingPipeline Completed!" + diff --git a/fMRISurface/scripts/CreateHippocampalCIFTIs.sh b/fMRISurface/scripts/CreateHippocampalCIFTIs.sh new file mode 100755 index 000000000..ac01040a5 --- /dev/null +++ b/fMRISurface/scripts/CreateHippocampalCIFTIs.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +# -------------------------------------------------------------------------------- +# A script for the conversion of 4 structures (L hipp, R hipp, L dentate, R dentate) +# into a single CIFTI file and deletion of intermediate func.gii file +# -------------------------------------------------------------------------------- + +script_name=$(basename "${0}") + +show_usage() { + cat < 0" "${BinaryRibbon}" -var x "${ProbabilisticRibbon}" + + # ------------------------------------------------------------------------------ + # Generating good-voxel mask for each structure + # ------------------------------------------------------------------------------ + + if [[ "${doGoodVoxels}" == "YES" ]]; then + + fslmaths "${WorkingDirectory}/${Subject}.cov" -mas "${BinaryRibbon}" "${WorkingDirectory}/${Prefix}_cov_ribbon" + meanIntensity=$(fslstats "${WorkingDirectory}/${Prefix}_cov_ribbon" -M) + fslmaths "${WorkingDirectory}/${Prefix}_cov_ribbon" -div ${meanIntensity} "${WorkingDirectory}/${Prefix}_cov_ribbon_norm" + fslmaths "${WorkingDirectory}/${Prefix}_cov_ribbon_norm" -bin -s "${NeighborhoodSmoothing}" "${WorkingDirectory}/${Prefix}_SmoothNorm" + fslmaths "${WorkingDirectory}/${Prefix}_cov_ribbon_norm" -s "${NeighborhoodSmoothing}" -div "${WorkingDirectory}/${Prefix}_SmoothNorm" -dilD "${WorkingDirectory}/${Prefix}_cov_ribbon_norm_s${NeighborhoodSmoothing}" + fslmaths "${WorkingDirectory}/${Subject}.cov" -div ${meanIntensity} -div "${WorkingDirectory}/${Prefix}_cov_ribbon_norm_s${NeighborhoodSmoothing}" "${WorkingDirectory}/${Prefix}_cov_norm_modulate" + fslmaths "${WorkingDirectory}/${Prefix}_cov_norm_modulate" -mas "${BinaryRibbon}" "${WorkingDirectory}/${Prefix}_cov_norm_modulate_ribbon" + + STD=$(fslstats "${WorkingDirectory}/${Prefix}_cov_norm_modulate_ribbon" -S) + echo "STD: ${STD}" + MEAN=$(fslstats "${WorkingDirectory}/${Prefix}_cov_norm_modulate_ribbon" -M) + echo "MEAN: ${MEAN}" + Upper=$(echo "${MEAN} + (${STD} * ${Factor})" | bc -l) + echo "UPPER: ${Upper}" + + fslmaths "${WorkingDirectory}/${Subject}.mean" -bin "${WorkingDirectory}/${Prefix}_mask" + fslmaths "${WorkingDirectory}/${Prefix}_cov_norm_modulate" -thr "${Upper}" -bin -sub "${WorkingDirectory}/${Prefix}_mask" -mul -1 -mas "${BinaryRibbon}" "${WorkingDirectory}/${Prefix}_goodvoxels" + fi + + + NativeFolder="${HippUnfoldFolder}/Native" + + InnerSurface="${NativeFolder}/${Prefix}_inner.native.surf.gii" + MidSurface="${NativeFolder}/${Prefix}_midthickness.native.surf.gii" + OuterSurface="${NativeFolder}/${Prefix}_outer.native.surf.gii" + + NativeFlat="${NativeFolder}/${Prefix}_flat.native.surf.gii" + NativeROI="${WorkingDirectory}/${Prefix}_ones.native.func.gii" + + # ===================================================================== + # Map mean and covariance volumes + # ===================================================================== + + for Map in mean cov; do + NativeMetric="${WorkingDirectory}/${Prefix}_${Map}.native.func.gii" + NativeAllMetric="${WorkingDirectory}/${Prefix}_${Map}_all.native.func.gii" + + # ----------------------------------------------------------------- + # Map using good voxels + # ----------------------------------------------------------------- + + if [[ "${doGoodVoxels}" == "YES" ]]; then + wb_command -volume-to-surface-mapping "${WorkingDirectory}/${Subject}.${Map}.nii.gz" "${MidSurface}" "${NativeMetric}" \ + -ribbon-constrained "${InnerSurface}" "${OuterSurface}" -volume-roi "${WorkingDirectory}/${Prefix}_goodvoxels.nii.gz" -dilate-missing ${dilation_dist} -nearest + else + + wb_command -volume-to-surface-mapping "${WorkingDirectory}/${Subject}.${Map}.nii.gz" "${MidSurface}" "${NativeMetric}" \ + -ribbon-constrained "${InnerSurface}" "${OuterSurface}" -dilate-missing ${dilation_dist} -nearest + fi + + wb_command -metric-dilate "${NativeMetric}" "${MidSurface}" "${dilation_dist}" "${NativeMetric}" -nearest + wb_command -metric-mask "${NativeMetric}" "${NativeROI}" "${NativeMetric}" + + + # ----------------------------------------------------------------- + # Map using all ribbon voxels + # ----------------------------------------------------------------- + + wb_command -volume-to-surface-mapping "${WorkingDirectory}/${Subject}.${Map}.nii.gz" "${MidSurface}" "${NativeAllMetric}" \ + -ribbon-constrained "${InnerSurface}" "${OuterSurface}" -dilate-missing ${dilation_dist} -nearest + wb_command -metric-mask "${NativeAllMetric}" "${NativeROI}" "${NativeAllMetric}" + + # ----------------------------------------------------------------- + # Resample native metrics using unfolded flat surfaces + # ----------------------------------------------------------------- + + for Mesh in ${Meshes}; do + + if [[ "${Mesh}" == "native" ]]; then + continue + fi + + MeshFolder="${HippUnfoldFolder}/${Mesh}" + + TargetFlat="${MeshFolder}/${Prefix}_flat.${Mesh}.surf.gii" + TargetMidSurface="${MeshFolder}/${Prefix}_midthickness.${Mesh}.surf.gii" + TargetSurfArea="${MeshFolder}/${Prefix}_surfarea.${Mesh}.shape.gii" + + TargetROI="${WorkingDirectory}/${Prefix}_ones.${Mesh}.func.gii" + + TargetMetric="${WorkingDirectory}/${Prefix}_${Map}.${Mesh}.func.gii" + TargetAllMetric="${WorkingDirectory}/${Prefix}_${Map}_all.${Mesh}.func.gii" + + wb_command -metric-math "x * 0 + 1" "${TargetROI}" -var x "${TargetSurfArea}" + wb_command -metric-resample "${NativeMetric}" "${NativeFlat}" "${TargetFlat}" ADAP_BARY_AREA "${TargetMetric}" \ + -area-surfs "${MidSurface}" "${TargetMidSurface}" -current-roi "${NativeROI}" -bypass-sphere-check + wb_command -metric-mask "${TargetMetric}" "${TargetROI}" "${TargetMetric}" + wb_command -metric-resample "${NativeAllMetric}" "${NativeFlat}" "${TargetFlat}" ADAP_BARY_AREA "${TargetAllMetric}" \ + -area-surfs "${MidSurface}" "${TargetMidSurface}" -current-roi "${NativeROI}" -bypass-sphere-check + wb_command -metric-mask "${TargetAllMetric}" "${TargetROI}" "${TargetAllMetric}" + done + done + + # ===================================================================== + # Map goodvoxels in volume space + # ===================================================================== + + if [[ "${doGoodVoxels}" == "YES" ]]; then + + NativeGoodVoxels="${WorkingDirectory}/${Prefix}_goodvoxels.native.func.gii" + + wb_command -volume-to-surface-mapping "${WorkingDirectory}/${Prefix}_goodvoxels.nii.gz" "${MidSurface}" "${NativeGoodVoxels}" \ + -ribbon-constrained "${InnerSurface}" "${OuterSurface}" -dilate-missing ${dilation_dist} -nearest + wb_command -metric-mask "${NativeGoodVoxels}" "${NativeROI}" "${NativeGoodVoxels}" + + + for Mesh in ${Meshes}; do + if [[ "${Mesh}" == "native" ]]; then + continue + fi + MeshFolder="${HippUnfoldFolder}/${Mesh}" + + TargetFlat="${MeshFolder}/${Prefix}_flat.${Mesh}.surf.gii" + TargetMidSurface="${MeshFolder}/${Prefix}_midthickness.${Mesh}.surf.gii" + TargetROI="${WorkingDirectory}/${Prefix}_ones.${Mesh}.func.gii" + + TargetGoodVoxels="${WorkingDirectory}/${Prefix}_goodvoxels.${Mesh}.func.gii" + + + wb_command -metric-resample "${NativeGoodVoxels}" "${NativeFlat}" "${TargetFlat}" ADAP_BARY_AREA "${TargetGoodVoxels}" \ + -area-surfs "${MidSurface}" "${TargetMidSurface}" -current-roi "${NativeROI}" -bypass-sphere-check + wb_command -metric-mask "${TargetGoodVoxels}" "${TargetROI}" "${TargetGoodVoxels}" + done + fi + + # ===================================================================== + # Map complete fMRI timeseries to native hippocampal surface + # ===================================================================== + for Mesh in ${Meshes}; do + + if [[ "${Mesh}" == "native" ]]; then + MeshFolder="${HippUnfoldFolder}/Native" + else + MeshFolder="${HippUnfoldFolder}/${Mesh}" + fi + + TargetfMRI="${WorkingDirectory}/${Prefix}_fMRI.${Mesh}.func.gii" + TargetFlat="${MeshFolder}/${Prefix}_flat.${Mesh}.surf.gii" + TargetMidSurface="${MeshFolder}/${Prefix}_midthickness.${Mesh}.surf.gii" + TargetROI="${WorkingDirectory}/${Prefix}_ones.${Mesh}.func.gii" + + if [[ "${Mesh}" == "native" ]]; then + + # Map fMRI volume to native surface + if [[ "${doGoodVoxels}" == "YES" ]]; then + + wb_command -volume-to-surface-mapping "${VolumefMRI}" "${TargetMidSurface}" "${TargetfMRI}" -ribbon-constrained "${InnerSurface}" "${OuterSurface}" \ + -volume-roi "${WorkingDirectory}/${Prefix}_goodvoxels.nii.gz" -dilate-missing "${dilation_dist}" -nearest + else + + wb_command -volume-to-surface-mapping "${VolumefMRI}" "${TargetMidSurface}" "${TargetfMRI}" \ + -ribbon-constrained "${InnerSurface}" "${OuterSurface}" -dilate-missing "${dilation_dist}" -nearest + fi + NativefMRI="${TargetfMRI}" + log_Msg "Generated fMRI file in native mesh at: ${TargetfMRI}" + else + + # Resample native fMRI surface to target mesh + wb_command -metric-resample "${NativefMRI}" "${NativeFlat}" "${TargetFlat}" ADAP_BARY_AREA "${TargetfMRI}" \ + -area-surfs "${MidSurface}" "${TargetMidSurface}" -current-roi "${NativeROI}" -bypass-sphere-check + + log_Msg "Generated fMRI file in ${Mesh} mesh at: ${TargetfMRI}" + + fi + + # Dilate and mask both native and target-mesh fMRI + wb_command -metric-dilate \ + "${TargetfMRI}" \ + "${TargetMidSurface}" \ + "${dilation_dist}" \ + "${TargetfMRI}" \ + -nearest + + wb_command -metric-mask \ + "${TargetfMRI}" \ + "${TargetROI}" \ + "${TargetfMRI}" + + done + # ===================================================================== + # Map VN volume to native hippocampal surface + # ===================================================================== + VolumefMRIVN="${VolumefMRI%.nii.gz}_vn.nii.gz" + + if [[ ! -f "${VolumefMRIVN}" ]]; then + log_Err_Abort "Cannot find VN volume: ${VolumefMRIVN}" + fi + + FiniteVolumefMRIVN="${WorkingDirectory}/${Subject}_vn_finite.nii.gz" + + fslmaths "${VolumefMRIVN}" -thr -1e30 -uthr 1e30 -nan "${FiniteVolumefMRIVN}" #Thresholding inf and -inf and replacing nan with 0 + + for Mesh in ${Meshes}; do + + TargetfMRIVN="${WorkingDirectory}/${Prefix}_fMRI_vn.${Mesh}.func.gii" + + if [[ "${Mesh}" == "native" ]]; then + MeshFolder="${HippUnfoldFolder}/Native" + TargetFlat="${MeshFolder}/${Prefix}_flat.native.surf.gii" + TargetMidSurface="${MeshFolder}/${Prefix}_midthickness.native.surf.gii" + + # Map VN volume to native surface + wb_command -volume-to-surface-mapping "${FiniteVolumefMRIVN}" "${TargetMidSurface}" "${TargetfMRIVN}" -cubic + NativefMRIVN="${TargetfMRIVN}" + + log_Msg "Generated VN file in native mesh at: ${TargetfMRIVN}" + else + MeshFolder="${HippUnfoldFolder}/${Mesh}" + TargetFlat="${MeshFolder}/${Prefix}_flat.${Mesh}.surf.gii" + TargetMidSurface="${MeshFolder}/${Prefix}_midthickness.${Mesh}.surf.gii" + # Resample native VN surface to other mesh surface + wb_command -metric-resample "${NativefMRIVN}" "${NativeFlat}" "${TargetFlat}" ADAP_BARY_AREA "${TargetfMRIVN}" \ + -area-surfs "${MidSurface}" "${TargetMidSurface}" -current-roi "${NativeROI}" -bypass-sphere-check + + log_Msg "Generated VN file in ${Mesh} mesh at: ${TargetfMRIVN}" + fi + done + done +done +