Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generation of scene/snapshots for fMRIQC #203

Merged
merged 17 commits into from
Jan 11, 2021
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions PostFreeSurfer/PostFreeSurferPipeline.sh
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,6 @@ fi
#display the parsed/default values
opts_ShowValues

#processing code goes here

verbose_red_echo "---> Starting ${log_ToolName}"
verbose_echo " "
verbose_echo " Using environment setting ..."
verbose_echo " HCPPIPEDIR: ${HCPPIPEDIR}"
verbose_echo " "

log_Check_Env_Var FSLDIR

HCPPIPEDIR_PostFS="$HCPPIPEDIR/PostFreeSurfer/scripts"
PipelineScripts="$HCPPIPEDIR_PostFS"

doProcessing=1
doQC=1

Expand All @@ -104,12 +91,26 @@ case "$QCMode" in
;;
(only)
doProcessing=0
log_Warn "Only generating structural QC scene and snapshots from existing data (no other processing)"
;;
(*)
log_Err_Abort "unrecognized value '$QCMode' for --structural-qc, use 'yes', 'no', or 'only'"
;;
esac

#processing code goes here

verbose_red_echo "---> Starting ${log_ToolName}"
verbose_echo " "
verbose_echo " Using environment setting ..."
verbose_echo " HCPPIPEDIR: ${HCPPIPEDIR}"
verbose_echo " "

log_Check_Env_Var FSLDIR

HCPPIPEDIR_PostFS="$HCPPIPEDIR/PostFreeSurfer/scripts"
PipelineScripts="$HCPPIPEDIR_PostFS"

# ------------------------------------------------------------------------------
# Naming Conventions
# Do NOT include spaces in any of these names
Expand Down Expand Up @@ -282,6 +283,7 @@ if ((doProcessing)); then
fi

if ((doQC)); then
log_Msg "Generating structural QC scene and snapshots"
"$PipelineScripts"/GenerateStructuralScenes.sh \
--study-folder="$StudyFolder" \
--subject="$Subject" \
Expand Down
39 changes: 8 additions & 31 deletions PostFreeSurfer/scripts/GenerateStructuralScenes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ fi
source "$HCPPIPEDIR/global/scripts/newopts.shlib" "$@"
source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@"
source "$HCPPIPEDIR/global/scripts/tempfiles.shlib" "$@"
source "$HCPPIPEDIR/global/scripts/relativePath.shlib" "$@"

#this function gets called by opts_ParseArguments when --help is specified
function usage()
Expand Down Expand Up @@ -118,7 +119,7 @@ verbose=$(opts_StringToBool "$verboseArg")

mkdir -p "$OutputSceneFolder"

# Convert TemplatesFolder and StudyFolder to absolute paths (for convenience in reporting locations).
# Convert TemplatesFolder, StudyFolder, and OutputSceneFolder to absolute paths (for convenience in reporting locations).
TemplatesFolder=$(cd "$TemplatesFolder"; pwd)
StudyFolder=$(cd "$StudyFolder"; pwd)
OutputSceneFolder=$(cd "$OutputSceneFolder"; pwd)
Expand Down Expand Up @@ -153,30 +154,6 @@ function copyTemplateFiles {
fi
}

# ----------------------------
# Function to determine relative paths
# ----------------------------

# We want to use relative paths in the scene file, so that it is robust
# against changes in the base directory path. As long as the relative
# paths between $OutputSceneFolder, $TemplatesFolder, and $StudyFolder are
# preserved, the scene should still work, even if the base directory changes
# (i.e., if the files are moved, or accessed via a different mount point).

# To determine the relative paths, 'realpath --relative-to' is not a robust
# solution, as 'realpath' is not present by default on MacOS, and the
# '--relative-to' option is not supported on older Ubuntu versions.
# So, use the following perl one-liner instead,
# from https://stackoverflow.com/a/17110582

function relativePath {
# both $1 and $2 are absolute paths beginning with /
# returns relative path from $1 to $2
local source=$(cd "$1"; pwd)
local target=$(cd "$2"; pwd)
perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' "$target" "$source"
}

# ----------------------------
# Define variables containing the "dummy strings" used in the template scene
# ----------------------------
Expand All @@ -192,19 +169,18 @@ TemplatesFolderDummyStr="TemplatesFolder"

scriptDir=$(pwd)

OutputSceneFolderSubj=$OutputSceneFolder
mkdir -p $OutputSceneFolderSubj
relPathToStudy=$(relativePath $OutputSceneFolderSubj $StudyFolder)
mkdir -p "$OutputSceneFolder"
relPathToStudy=$(relativePath "$OutputSceneFolder" "$StudyFolder")
if [[ "$CopyTemplates" == "TRUE" ]]; then
copyTemplateFiles $TemplatesFolder $OutputSceneFolderSubj
copyTemplateFiles "$TemplatesFolder" "$OutputSceneFolder"
relPathToTemplates="."
else
relPathToTemplates=$(relativePath $OutputSceneFolderSubj $TemplatesFolder)
relPathToTemplates=$(relativePath "$OutputSceneFolder" "$TemplatesFolder")
fi
if ((verbose)); then
echo "TemplatesFolder: $TemplatesFolder"
echo "StudyFolder: $StudyFolder"
echo "OutputSceneFolder: $(cd $OutputSceneFolderSubj; pwd)"
echo "OutputSceneFolder: $OutputSceneFolder"
echo "... relative path to template files (from OutputSceneFolder): $relPathToTemplates"
echo "... relative path to StudyFolder (from OutputSceneFolder): $relPathToStudy"
fi
Expand Down Expand Up @@ -325,3 +301,4 @@ done
# Cleanup
rm "$OutputSceneFolder/$Subject.$mapName."{L,R}".$mesh.func.gii"

log_Msg "structural QC scene generation completed"
79 changes: 57 additions & 22 deletions fMRISurface/GenericfMRISurfaceProcessingPipeline.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ Usage: ${script_name} [options]
--smoothingFWHM=<smoothing FWHM (mm)>
--grayordinatesres=<grayordinates res (mm)>
[--regname=<surface registration name>] defaults to 'MSMSulc'
[--fmri-qc=<"YES|NO|ONLY">
Controls whether to generate a QC scene and snapshots (default=YES).
ONLY executes *just* the QC script, skipping everything else (e.g., for previous data)

EOF
}
Expand Down Expand Up @@ -94,13 +97,16 @@ FinalfMRIResolution=`opts_GetOpt1 "--fmrires" $@`
SmoothingFWHM=`opts_GetOpt1 "--smoothingFWHM" $@`
GrayordinatesResolution=`opts_GetOpt1 "--grayordinatesres" $@`
RegName=`opts_GetOpt1 "--regname" $@`

if [ -z "${RegName}" ]; then
RegName="MSMSulc"
fi
RegName=`opts_DefaultOpt $RegName MSMSulc`
QCMode=`opts_GetOpt1 "--fmri-qc" $@`
QCMode=`opts_DefaultOpt $QCMode YES`
QCMode="$(echo ${QCMode} | tr '[:upper:]' '[:lower:]')" # Convert to all lowercase

RUN=`opts_GetOpt1 "--printcom" $@` # use ="echo" for just printing everything and not running the commands (default is to run)

doProcessing=1
doQC=1

log_Msg "Path: ${Path}"
log_Msg "Subject: ${Subject}"
log_Msg "NameOffMRI: ${NameOffMRI}"
Expand All @@ -109,6 +115,21 @@ log_Msg "FinalfMRIResolution: ${FinalfMRIResolution}"
log_Msg "SmoothingFWHM: ${SmoothingFWHM}"
log_Msg "GrayordinatesResolution: ${GrayordinatesResolution}"
log_Msg "RegName: ${RegName}"
log_Msg "QCMode: $QCMode"
case "$QCMode" in
(yes)
;;
(no)
doQC=0
;;
(only)
doProcessing=0
log_Warn "Only generating fMRI QC scene and snapshots from existing data (no other processing)"
;;
(*)
log_Err_Abort "unrecognized value '$QCMode' for --fmri-qc, use 'YES', 'NO', or 'ONLY'"
;;
esac
log_Msg "RUN: ${RUN}"

if [ "${RegName}" = "FS" ] ; then
Expand Down Expand Up @@ -139,25 +160,39 @@ T1wFolder="$Path"/"$Subject"/"$T1wFolder"
ResultsFolder="$AtlasSpaceFolder"/"$ResultsFolder"/"$NameOffMRI"
ROIFolder="$AtlasSpaceFolder"/"$ROIFolder"

#Make fMRI Ribbon
#Noisy Voxel Outlier Exclusion
#Ribbon-based Volume to Surface mapping and resampling to standard surface

log_Msg "Make fMRI Ribbon"
log_Msg "mkdir -p ${ResultsFolder}/RibbonVolumeToSurfaceMapping"
mkdir -p "$ResultsFolder"/RibbonVolumeToSurfaceMapping
"$PipelineScripts"/RibbonVolumeToSurfaceMapping.sh "$ResultsFolder"/RibbonVolumeToSurfaceMapping "$ResultsFolder"/"$NameOffMRI" "$Subject" "$AtlasSpaceFolder"/"$DownSampleFolder" "$LowResMesh" "$AtlasSpaceFolder"/"$NativeFolder" "${RegName}"

#Surface Smoothing
log_Msg "Surface Smoothing"
"$PipelineScripts"/SurfaceSmoothing.sh "$ResultsFolder"/"$NameOffMRI" "$Subject" "$AtlasSpaceFolder"/"$DownSampleFolder" "$LowResMesh" "$SmoothingFWHM"
# ------------------------------------------------------------------------------
# Start work
# ------------------------------------------------------------------------------

#Subcortical Processing
log_Msg "Subcortical Processing"
"$PipelineScripts"/SubcorticalProcessing.sh "$AtlasSpaceFolder" "$ROIFolder" "$FinalfMRIResolution" "$ResultsFolder" "$NameOffMRI" "$SmoothingFWHM" "$GrayordinatesResolution"
if ((doProcessing)); then
#Make fMRI Ribbon
#Noisy Voxel Outlier Exclusion
#Ribbon-based Volume to Surface mapping and resampling to standard surface
log_Msg "Make fMRI Ribbon"
coalsont marked this conversation as resolved.
Show resolved Hide resolved
log_Msg "mkdir -p ${ResultsFolder}/RibbonVolumeToSurfaceMapping"
mkdir -p "$ResultsFolder"/RibbonVolumeToSurfaceMapping
"$PipelineScripts"/RibbonVolumeToSurfaceMapping.sh "$ResultsFolder"/RibbonVolumeToSurfaceMapping "$ResultsFolder"/"$NameOffMRI" "$Subject" "$AtlasSpaceFolder"/"$DownSampleFolder" "$LowResMesh" "$AtlasSpaceFolder"/"$NativeFolder" "${RegName}"

#Surface Smoothing
log_Msg "Surface Smoothing"
"$PipelineScripts"/SurfaceSmoothing.sh "$ResultsFolder"/"$NameOffMRI" "$Subject" "$AtlasSpaceFolder"/"$DownSampleFolder" "$LowResMesh" "$SmoothingFWHM"

#Subcortical Processing
log_Msg "Subcortical Processing"
"$PipelineScripts"/SubcorticalProcessing.sh "$AtlasSpaceFolder" "$ROIFolder" "$FinalfMRIResolution" "$ResultsFolder" "$NameOffMRI" "$SmoothingFWHM" "$GrayordinatesResolution"

#Generation of Dense Timeseries
log_Msg "Generation of Dense Timeseries"
"$PipelineScripts"/CreateDenseTimeseries.sh "$AtlasSpaceFolder"/"$DownSampleFolder" "$Subject" "$LowResMesh" "$ResultsFolder"/"$NameOffMRI" "$SmoothingFWHM" "$ROIFolder" "$ResultsFolder"/"$OutputAtlasDenseTimeseries" "$GrayordinatesResolution"
fi

#Generation of Dense Timeseries
log_Msg "Generation of Dense Timeseries"
"$PipelineScripts"/CreateDenseTimeseries.sh "$AtlasSpaceFolder"/"$DownSampleFolder" "$Subject" "$LowResMesh" "$ResultsFolder"/"$NameOffMRI" "$SmoothingFWHM" "$ROIFolder" "$ResultsFolder"/"$OutputAtlasDenseTimeseries" "$GrayordinatesResolution"
if ((doQC)); then
log_Msg "Generating fMRI QC scene and snapshots"
"$PipelineScripts"/GenerateFMRIScenes.sh \
--study-folder="$Path" \
--subject="$Subject" \
--fmriname="$NameOffMRI" \
--output-folder="$ResultsFolder/fMRIQC"
fi

log_Msg "Completed!"
3 changes: 3 additions & 0 deletions fMRISurface/scripts/CreateDenseTimeseries.sh
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ ${CARET7DIR}/wb_command -cifti-create-dense-timeseries \
-right-metric "$NameOffMRI"_s"$SmoothingFWHM".atlasroi.R."$LowResMesh"k_fs_LR.func.gii -roi-right "$DownSampleFolder"/"$Subject".R.atlasroi."$LowResMesh"k_fs_LR.shape.gii \
-timestep "$TR_vol"

# Generate temporal mean of timeseries, for display in fMRIQC
${CARET7DIR}/wb_command -cifti-reduce "$OutputAtlasDenseTimeseries".dtseries.nii MEAN "$OutputAtlasDenseTimeseries"_mean.dscalar.nii

#Assess for zeros in the final dtseries (e.g., due to incomplete spatial coverage)
# (Note that earlier steps do an appreciable amount of dilation to eliminate zeros,
# so zeros remaining in the CIFTI at this point represent a non-trivial issue with spatial coverage)
Expand Down
113 changes: 113 additions & 0 deletions fMRISurface/scripts/GenerateFMRIScenes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/bin/bash
set -eu

pipedirguessed=0
if [[ "${HCPPIPEDIR:-}" == "" ]]
then
export HCPPIPEDIR="$(dirname -- "$0")/../.."
pipedirguessed=1
fi

source "$HCPPIPEDIR/global/scripts/newopts.shlib" "$@"
source "$HCPPIPEDIR/global/scripts/debug.shlib" "$@"
source "$HCPPIPEDIR/global/scripts/relativePath.shlib" "$@"

#this function gets called by opts_ParseArguments when --help is specified
function usage()
{
#header text
echo "
$log_ToolName: makes QC scenes and captures for HCP fMRIVolume pipeline

Usage: $log_ToolName PARAMETER...

PARAMETERs are [ ] = optional; < > = user supplied value
"
#automatic argument descriptions
opts_ShowArguments

#do not use exit, the parsing code takes care of it
}

#arguments to opts_Add*: switch, variable to set, name for inside of <> in help text, description, [default value if AddOptional], [compatibility flag, ...]
#help info for option gets printed like "--foo=<$3> - $4"
opts_AddMandatory '--study-folder' 'StudyFolder' 'path' "folder containing all subjects"
opts_AddMandatory '--subject' 'Subject' 'subject ID' ""
opts_AddMandatory '--fmriname' 'fMRIName' 'fMRI run name' ""
opts_AddMandatory '--output-folder' 'OutputSceneFolder' 'path' "output location for QC scene and snapshots"

opts_AddOptional '--verbose' 'verboseArg' 'true|false' "whether to output more messages, default 'false'" 'false'

opts_ParseArguments "$@"

if ((pipedirguessed))
then
log_Err_Abort "HCPPIPEDIR is not set, you must first source your edited copy of Examples/Scripts/SetUpHCPPipeline.sh"
fi

#display the parsed/default values
opts_ShowValues

#processing code goes here

### --------------------------------------------- ###
### Set Defaults
### --------------------------------------------- ###

TemplatesFolder="$HCPPIPEDIR/global/templates/fMRIQC"

verbose=$(opts_StringToBool "$verboseArg")

### --------------------------------------------- ###
### From here onward should not need any modification

mkdir -p "$OutputSceneFolder"

# Convert TemplatesFolder, StudyFolder, and OutputSceneFolder to absolute paths (for convenience in reporting locations).
TemplatesFolder=$(cd "$TemplatesFolder"; pwd)
StudyFolder=$(cd "$StudyFolder"; pwd)
OutputSceneFolder=$(cd "$OutputSceneFolder"; pwd)

# ----------------------------
# Define variables containing the "dummy strings" used in the template scene
# ----------------------------

# The following are matched to actual strings in the TEMPLATE_fMRIQC.scene file
StudyFolderDummyStr="STUDYDIR"
SubjectIDDummyStr="SESSION"
fMRINameDummyStr="FMRINAME"

# ----------------------------
# Begin main action of script
# ----------------------------

scriptDir=$(pwd)

mkdir -p "$OutputSceneFolder"
relPathToStudy=$(relativePath "$OutputSceneFolder" "$StudyFolder")
if ((verbose)); then
echo "TemplatesFolder: $TemplatesFolder"
echo "StudyFolder: $StudyFolder"
echo "OutputSceneFolder: $OutputSceneFolder"
echo "... relative path to StudyFolder (from OutputSceneFolder): $relPathToStudy"
fi

# Replace dummy strings in the template scenes to generate
# a scene file appropriate for each subject and fMRI run
sceneFile="${Subject}_${fMRIName}.fMRIQC.wb_scene" # No path (file name only)
sed -e "s|${StudyFolderDummyStr}|${relPathToStudy}|g" \
-e "s|${SubjectIDDummyStr}|${Subject}|g" \
-e "s|${fMRINameDummyStr}|${fMRIName}|g" \
"$TemplatesFolder"/TEMPLATE_fMRIQC.scene > "$OutputSceneFolder/$sceneFile"

# Generate snapshots
pngDir="$OutputSceneFolder/snapshots"
mkdir -p "${pngDir}"
#numScenes=$(grep "SceneInfo Index" "$OutputSceneFolder/$sceneFile" | wc -l)
#for ((ind = 1; ind <= numScenes; ind++)); do
scenesToCapture="1 2"
for ind in $scenesToCapture; do
wb_command -show-scene "$OutputSceneFolder/$sceneFile" $ind "${pngDir}/${sceneFile}${ind}.png" 1400 600 -logging OFF
done

log_Msg "fMRI QC scene generation completed"
1 change: 1 addition & 0 deletions fMRIVolume/GenericfMRIVolumeProcessingPipeline.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,7 @@ ${RUN} ${PipelineScripts}/IntensityNormalization.sh \
#Copy selected files to ResultsFolder
${RUN} cp ${fMRIFolder}/${NameOffMRI}_nonlin_norm.nii.gz ${ResultsFolder}/${NameOffMRI}.nii.gz
${RUN} cp ${fMRIFolder}/${NameOffMRI}_SBRef_nonlin_norm.nii.gz ${ResultsFolder}/${NameOffMRI}_SBRef.nii.gz
${RUN} cp ${fMRIFolder}/${NameOffMRI}_SBRef_nonlin_norm_nomask.nii.gz ${ResultsFolder}/${NameOffMRI}_SBRef_nomask.nii.gz
${RUN} cp ${fMRIFolder}/${JacobianOut}_MNI.${FinalfMRIResolution}.nii.gz ${ResultsFolder}/${NameOffMRI}_${JacobianOut}.nii.gz
${RUN} cp ${fMRIFolder}/${FreeSurferBrainMask}.${FinalfMRIResolution}.nii.gz ${ResultsFolder}
${RUN} cp ${fMRIFolder}/${NameOffMRI}_nonlin_mask.nii.gz ${ResultsFolder}/${NameOffMRI}_fovmask.nii.gz
Expand Down
11 changes: 9 additions & 2 deletions fMRIVolume/scripts/IntensityNormalization.sh
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,18 @@ echo "${fMRIMask}, ${PctBrainCoverage}, ${PctMaskCoverage}, ${NvoxT1FOVMask}, ${
# for the main fmri timeseries and the scout images (pre-saturation images)
${FSLDIR}/bin/fslmaths ${InputfMRI} $biascom $jacobiancom -mas ${FinalMask} -thr 0 -ing 10000 ${OutputfMRI} -odt float
if [ X${ScoutInput} != X ] ; then
${FSLDIR}/bin/fslmaths ${ScoutInput} $biascom $jacobiancom -mas ${FinalMask} -thr 0 -ing 10000 ${ScoutOutput} -odt float
# Generate both masked and unmasked versions of scout, but with consistent scaling within the mask
ScoutOutputNotMasked=${ScoutOutput}_nomask
${FSLDIR}/bin/fslmaths ${ScoutInput} $biascom $jacobiancom ${ScoutOutputNotMasked} -odt float
# Compute spatial mean within mask, and normalize to a mean of 10000 inside the mask
scaleFactor=$(${FSLDIR}/bin/fslstats ${ScoutOutputNotMasked} -k ${FinalMask} -l 0 -M)
${FSLDIR}/bin/fslmaths ${ScoutOutputNotMasked} -mul 10000 -div $scaleFactor -thr 0 ${ScoutOutputNotMasked} -odt float
# Apply mask to generate masked version
${FSLDIR}/bin/fslmaths ${ScoutOutputNotMasked} -mas ${FinalMask} ${ScoutOutput} -odt float
fi

#Basic Cleanup
#rm ${InputfMRI}.nii.* #Don't delete the unmasked spatially corrected unormalized data by default
#rm ${InputfMRI}.nii.* #Don't delete the spatially corrected but unmasked and unnormalized data by default

echo " "
echo "END: IntensityNormalization"
Expand Down
Loading