diff --git a/multi_subject/process_data.sh b/multi_subject/process_data.sh index e7121f5..e21a01c 100755 --- a/multi_subject/process_data.sh +++ b/multi_subject/process_data.sh @@ -45,21 +45,21 @@ label_if_does_not_exist() { # - If it doesn't, perform automatic labeling. # This allows you to add manual labels on a subject-by-subject basis without disrupting the pipeline. ### - local file="$1" - local file_seg="$2" + local file="${1}" + local file_seg="${2}" # Update global variable with segmentation file name - FILELABEL="${file}_labels" - FILELABELMANUAL="${PATH_DATA}/derivatives/labels/${SUBJECT}/anat/${FILELABEL}-manual.nii.gz" - echo "Looking for manual label: $FILELABELMANUAL" - if [[ -e $FILELABELMANUAL ]]; then + FILELABEL="${file}"_labels + FILELABELMANUAL="${PATH_DATA}"/derivatives/labels/"${SUBJECT}"/anat/"${FILELABEL}"-manual.nii.gz + echo "Looking for manual label: ${FILELABELMANUAL}" + if [[ -e "${FILELABELMANUAL}" ]]; then echo "Found! Using manual labels." - rsync -avzh $FILELABELMANUAL ${FILELABEL}.nii.gz + rsync -avzh "${FILELABELMANUAL}" "${FILELABEL}".nii.gz else echo "Not found. Proceeding with automatic labeling." # Generate labeled segmentation - sct_label_vertebrae -i ${file}.nii.gz -s ${file_seg}.nii.gz -c t2 -qc "${PATH_QC}" -qc-subject "${SUBJECT}" + sct_label_vertebrae -i "${file}".nii.gz -s "${file_seg}".nii.gz -c t2 -qc "${PATH_QC}" -qc-subject "${SUBJECT}" # Create labels in the cord at C3 and C5 mid-vertebral levels - sct_label_utils -i ${file_seg}_labeled.nii.gz -vert-body 3,5 -o ${FILELABEL}.nii.gz + sct_label_utils -i "${file_seg}"_labeled.nii.gz -vert-body 3,5 -o "${FILELABEL}".nii.gz fi } @@ -70,21 +70,21 @@ segment_if_does_not_exist() { # - If it doesn't, perform automatic spinal cord segmentation. # This allows you to add manual segmentations on a subject-by-subject basis without disrupting the pipeline. ### - local file="$1" - local contrast="$2" + local file="${1}" + local contrast="${2}" # Update global variable with segmentation file name - FILESEG="${file}_seg" - FILESEGMANUAL="${PATH_DATA}/derivatives/labels/${SUBJECT}/anat/${FILESEG}-manual.nii.gz" + FILESEG="${file}"_seg + FILESEGMANUAL="${PATH_DATA}"/derivatives/labels/"${SUBJECT}"/anat/"${FILESEG}"-manual.nii.gz echo - echo "Looking for manual segmentation: $FILESEGMANUAL" - if [[ -e $FILESEGMANUAL ]]; then + echo "Looking for manual segmentation: ${FILESEGMANUAL}" + if [[ -e "${FILESEGMANUAL}" ]]; then echo "Found! Using manual segmentation." - rsync -avzh $FILESEGMANUAL ${FILESEG}.nii.gz - sct_qc -i ${file}.nii.gz -s ${FILESEG}.nii.gz -p sct_deepseg_sc -qc ${PATH_QC} -qc-subject ${SUBJECT} + rsync -avzh "${FILESEGMANUAL}" "${FILESEG}".nii.gz + sct_qc -i "${file}".nii.gz -s "${FILESEG}".nii.gz -p sct_deepseg_sc -qc "${PATH_QC}" -qc-subject "${SUBJECT}" else echo "Not found. Proceeding with automatic segmentation." # Segment spinal cord - sct_deepseg_sc -i ${file}.nii.gz -c $contrast -qc ${PATH_QC} -qc-subject ${SUBJECT} + sct_deepseg_sc -i "${file}".nii.gz -c "${contrast}" -qc "${PATH_QC}" -qc-subject "${SUBJECT}" fi } @@ -93,24 +93,24 @@ segment_if_does_not_exist() { # ====================================================================================================================== # Retrieve input params -SUBJECT=$1 +SUBJECT="${1}" # get starting time: -start=`date +%s` +start="$(date +%s)" # Display useful info for the log, such as SCT version, RAM and CPU cores available sct_check_dependencies -short # Go to folder where data will be copied and processed -cd $PATH_DATA_PROCESSED +cd "${PATH_DATA_PROCESSED}" # Copy source images -rsync -avzh $PATH_DATA/$SUBJECT . +rsync -avzh "${PATH_DATA}"/"${SUBJECT}" . # T2w # ====================================================================================================================== -cd "${SUBJECT}/anat/" -file_t2="${SUBJECT}_T2w" +cd "${SUBJECT}"/anat/ +file_t2="${SUBJECT}"_T2w # Segment spinal cord (only if it does not exist) segment_if_does_not_exist "${file_t2}" "t2" file_t2_seg="${FILESEG}" @@ -118,36 +118,36 @@ file_t2_seg="${FILESEG}" label_if_does_not_exist "${file_t2}" "${file_t2_seg}" file_label="${FILELABEL}" # Register to template -sct_register_to_template -i "${file_t2}.nii.gz" -s "${file_t2_seg}.nii.gz" -l "${file_label}.nii.gz" -c t2 \ +sct_register_to_template -i "${file_t2}".nii.gz -s "${file_t2_seg}".nii.gz -l "${file_label}".nii.gz -c t2 \ -param step=1,type=seg,algo=centermassrot:step=2,type=im,algo=syn,iter=5,slicewise=1,metric=CC,smooth=0 \ -qc "${PATH_QC}" # Warp template # Note: we don't need the white matter atlas at this point, therefore use flag "-a 0" -sct_warp_template -d "${file_t2}.nii.gz" -w warp_template2anat.nii.gz -a 0 -ofolder label_T2w -qc "${PATH_QC}" +sct_warp_template -d "${file_t2}".nii.gz -w warp_template2anat.nii.gz -a 0 -ofolder label_T2w -qc "${PATH_QC}" # Compute average CSA between C2 and C3 levels (append across subjects) -sct_process_segmentation -i "${file_t2_seg}.nii.gz" -vert 2:3 -vertfile label_T2w/template/PAM50_levels.nii.gz \ - -o "${PATH_RESULTS}/CSA.csv" -append 1 -qc "${PATH_QC}" +sct_process_segmentation -i "${file_t2_seg}".nii.gz -vert 2:3 -vertfile label_T2w/template/PAM50_levels.nii.gz \ + -o "${PATH_RESULTS}"/CSA.csv -append 1 -qc "${PATH_QC}" # MT # ====================================================================================================================== -file_mt1="${SUBJECT}_acq-MTon_MTS" -file_mt0="${SUBJECT}_acq-MToff_MTS" +file_mt1="${SUBJECT}"_acq-MTon_MTS +file_mt0="${SUBJECT}"_acq-MToff_MTS # Segment spinal cord segment_if_does_not_exist "${file_mt1}" "t2s" -file_mt1_seg=$FILESEG +file_mt1_seg="${FILESEG}" # Create mask -sct_create_mask -i "${file_mt1}.nii.gz" -p centerline,"${file_mt1_seg}.nii.gz" -size 45mm +sct_create_mask -i "${file_mt1}".nii.gz -p centerline,"${file_mt1_seg}".nii.gz -size 45mm # Crop data for faster processing -sct_crop_image -i "${file_mt1}.nii.gz" -m "mask_${file_mt1}.nii.gz" -o "${file_mt1}_crop.nii.gz" -sct_crop_image -i "${file_mt1_seg}.nii.gz" -m "mask_${file_mt1}.nii.gz" -o "${file_mt1}_crop_seg.nii.gz" -file_mt1="${file_mt1}_crop" +sct_crop_image -i "${file_mt1}".nii.gz -m "mask_${file_mt1}".nii.gz -o "${file_mt1}"_crop.nii.gz +sct_crop_image -i "${file_mt1_seg}".nii.gz -m "mask_${file_mt1}".nii.gz -o "${file_mt1}"_crop_seg.nii.gz +file_mt1="${file_mt1}"_crop # Register mt0->mt1 # Tips: here we only use rigid transformation because both images have very # similar sequence parameters. We don't want to use SyN/BSplineSyN to avoid # introducing spurious deformations. -sct_register_multimodal -i "${file_mt0}.nii.gz" \ - -d "${file_mt1}.nii.gz" \ - -dseg "${file_mt1}_seg.nii.gz" \ +sct_register_multimodal -i "${file_mt0}".nii.gz \ + -d "${file_mt1}".nii.gz \ + -dseg "${file_mt1}"_seg.nii.gz \ -param step=1,type=im,algo=rigid,slicewise=1,metric=CC \ -x spline \ -qc "${PATH_QC}" @@ -156,21 +156,21 @@ sct_register_multimodal -i "${file_mt0}.nii.gz" \ # Tips: First step: slicereg based on images, with large smoothing to capture # potential motion between anat and mt, then at second step: bpslinesyn in order to # adapt the shape of the cord to the mt modality (in case there are distortions between anat and mt). -sct_register_multimodal -i "${SCT_DIR}/data/PAM50/template/PAM50_t2.nii.gz" \ - -iseg "${SCT_DIR}/data/PAM50/template/PAM50_cord.nii.gz" \ - -d "${file_mt1}.nii.gz" \ - -dseg "${file_mt1}_seg.nii.gz" \ +sct_register_multimodal -i "${SCT_DIR}"/data/PAM50/template/PAM50_t2.nii.gz \ + -iseg "${SCT_DIR}"/data/PAM50/template/PAM50_cord.nii.gz \ + -d "${file_mt1}".nii.gz \ + -dseg "${file_mt1}"_seg.nii.gz \ -param step=1,type=seg,algo=centermass:step=2,type=seg,algo=bsplinesyn,slicewise=1,iter=3 \ -initwarp warp_template2anat.nii.gz \ -initwarpinv warp_anat2template.nii.gz \ -qc "${PATH_QC}" # Rename warping fields for clarity -mv "warp_PAM50_t22${file_mt1}.nii.gz" warp_template2mt.nii.gz -mv "warp_${file_mt1}2PAM50_t2.nii.gz" warp_mt2template.nii.gz +mv warp_PAM50_t22"${file_mt1}".nii.gz warp_template2mt.nii.gz +mv warp_"${file_mt1}"2PAM50_t2.nii.gz warp_mt2template.nii.gz # Warp template -sct_warp_template -d "${file_mt1}.nii.gz" -w warp_template2mt.nii.gz -ofolder label_MT -qc "${PATH_QC}" +sct_warp_template -d "${file_mt1}".nii.gz -w warp_template2mt.nii.gz -ofolder label_MT -qc "${PATH_QC}" # Compute mtr -sct_compute_mtr -mt0 "${file_mt0}_reg.nii.gz" -mt1 "${file_mt1}.nii.gz" +sct_compute_mtr -mt0 "${file_mt0}"_reg.nii.gz -mt1 "${file_mt1}".nii.gz # compute MTR in dorsal columns between levels C2 and C5 (append across subjects) sct_extract_metric -i mtr.nii.gz -f label_MT/atlas -l 53 -vert 2:5 -vertfile label_MT/template/PAM50_levels.nii.gz \ -method map -o "${PATH_RESULTS}/MTR_in_DC.csv" -append 1 @@ -178,8 +178,8 @@ sct_extract_metric -i mtr.nii.gz -f label_MT/atlas -l 53 -vert 2:5 -vertfile lab # Verify presence of output files and write log file if error # ====================================================================================================================== FILES_TO_CHECK=( - "$file_t2_seg.nii.gz" - "mtr.nii.gz" + "${file_t2_seg}".nii.gz + mtr.nii.gz ) for file in "${FILES_TO_CHECK[@]}"; do if [ ! -e "${file}" ]; then @@ -188,11 +188,11 @@ for file in "${FILES_TO_CHECK[@]}"; do done # Display useful info for the log -end=`date +%s` -runtime=$((end-start)) +end="$(date +%s)" +runtime="$((end-start))" echo echo "~~~" -echo "SCT version: `sct_version`" -echo "Ran on: `uname -nsr`" -echo "Duration: $(($runtime / 3600))hrs $((($runtime / 60) % 60))min $(($runtime % 60))sec" +echo "SCT version: $(sct_version)" +echo "Ran on: $(uname -nsr)" +echo "Duration: $((runtime / 3600))hrs $(( (runtime / 60) % 60))min $((runtime % 60))sec" echo "~~~" diff --git a/single_subject/batch_single_subject.sh b/single_subject/batch_single_subject.sh index f98eeee..c9ebff6 100755 --- a/single_subject/batch_single_subject.sh +++ b/single_subject/batch_single_subject.sh @@ -23,7 +23,7 @@ echo -e "\nStarted at: $(date +%x_%r)" # Source: https://unix.stackexchange.com/a/497540 if ! command -v fsleyes > /dev/null; then fsleyes() { - printf 'WARNING: FSLeyes is not installed, so the following command was skipped:\nfsleyes %s\n' "$*"; + printf 'WARNING: FSLeyes is not installed, so the following command was skipped:\nfsleyes %s\n' "${*@Q}"; }; fi @@ -136,7 +136,7 @@ sct_create_mask -i mt1.nii.gz -p centerline,mt1_seg.nii.gz -size 35mm -f cylinde # Register template->mt1. The flag -initwarp ../t2/warp_template2anat.nii.gz initializes the registration using the # template->t2 transformation which was previously estimated -sct_register_multimodal -i $SCT_DIR/data/PAM50/template/PAM50_t2.nii.gz -iseg $SCT_DIR/data/PAM50/template/PAM50_cord.nii.gz -d mt1.nii.gz -dseg mt1_seg.nii.gz -m mask_mt1.nii.gz -initwarp ../t2/warp_template2anat.nii.gz -param step=1,type=seg,algo=centermass:step=2,type=seg,algo=bsplinesyn,slicewise=1,iter=3 -owarp warp_template2mt.nii.gz -qc ~/qc_singleSubj +sct_register_multimodal -i "${SCT_DIR}"/data/PAM50/template/PAM50_t2.nii.gz -iseg "${SCT_DIR}"/data/PAM50/template/PAM50_cord.nii.gz -d mt1.nii.gz -dseg mt1_seg.nii.gz -m mask_mt1.nii.gz -initwarp ../t2/warp_template2anat.nii.gz -param step=1,type=seg,algo=centermass:step=2,type=seg,algo=bsplinesyn,slicewise=1,iter=3 -owarp warp_template2mt.nii.gz -qc ~/qc_singleSubj # Tips: Here we only use the segmentations (type=seg) to minimize the sensitivity of the registration procedure to # image artifacts. # Tips: Step 1: algo=centermass to align source and destination segmentations, then Step 2: algo=bpslinesyn to adapt the @@ -228,13 +228,13 @@ sct_extract_metric -i t2s.nii.gz -f t2s_gmseg.nii.gz -method bin -z 2:12 -o t2s_ # Register template->t2s (using warping field generated from template<->t2 registration) # Tips: Here we use the WM seg for the iseg/dseg fields in order to account for both the cord and the GM shape. -sct_register_multimodal -i "${SCT_DIR}/data/PAM50/template/PAM50_t2s.nii.gz" -iseg "${SCT_DIR}/data/PAM50/template/PAM50_wm.nii.gz" -d t2s.nii.gz -dseg t2s_wmseg.nii.gz -initwarp ../t2/warp_template2anat.nii.gz -initwarpinv ../t2/warp_anat2template.nii.gz -owarp warp_template2t2s.nii.gz -owarpinv warp_t2s2template.nii.gz -param step=1,type=seg,algo=rigid:step=2,type=seg,algo=bsplinesyn,slicewise=1,iter=3 -qc ~/qc_singleSubj +sct_register_multimodal -i "${SCT_DIR}"/data/PAM50/template/PAM50_t2s.nii.gz -iseg "${SCT_DIR}"/data/PAM50/template/PAM50_wm.nii.gz -d t2s.nii.gz -dseg t2s_wmseg.nii.gz -initwarp ../t2/warp_template2anat.nii.gz -initwarpinv ../t2/warp_anat2template.nii.gz -owarp warp_template2t2s.nii.gz -owarpinv warp_t2s2template.nii.gz -param step=1,type=seg,algo=rigid:step=2,type=seg,algo=bsplinesyn,slicewise=1,iter=3 -qc ~/qc_singleSubj # Warp template sct_warp_template -d t2s.nii.gz -w warp_template2t2s.nii.gz -qc ~/qc_singleSubj cd ../mt # Register template->mt via t2s to account for GM segmentation -sct_register_multimodal -i "${SCT_DIR}/data/PAM50/template/PAM50_t2.nii.gz" -iseg "${SCT_DIR}/data/PAM50/template/PAM50_cord.nii.gz" -d mt1.nii.gz -dseg mt1_seg.nii.gz -param step=1,type=seg,algo=centermass:step=2,type=seg,algo=bsplinesyn,slicewise=1,iter=3 -m mask_mt1.nii.gz -initwarp ../t2s/warp_template2t2s.nii.gz -owarp warp_template2mt.nii.gz -qc ~/qc_singleSubj +sct_register_multimodal -i "${SCT_DIR}"/data/PAM50/template/PAM50_t2.nii.gz -iseg "${SCT_DIR}"/data/PAM50/template/PAM50_cord.nii.gz -d mt1.nii.gz -dseg mt1_seg.nii.gz -param step=1,type=seg,algo=centermass:step=2,type=seg,algo=bsplinesyn,slicewise=1,iter=3 -m mask_mt1.nii.gz -initwarp ../t2s/warp_template2t2s.nii.gz -owarp warp_template2mt.nii.gz -qc ~/qc_singleSubj # Warp template sct_warp_template -d mt1.nii.gz -w warp_template2mt.nii.gz -qc ~/qc_singleSubj # Check results @@ -279,7 +279,7 @@ sct_deepseg_sc -i dmri_moco_dwi_mean.nii.gz -c dwi -qc ~/qc_singleSubj # -param, so it will not make a difference here) # Note: the flag “-initwarpinv" provides a transformation dmri->template, in case you would like to bring all your DTI # metrics in the PAM50 space (e.g. group averaging of FA maps) -sct_register_multimodal -i "${SCT_DIR}/data/PAM50/template/PAM50_t1.nii.gz" -iseg "${SCT_DIR}/data/PAM50/template/PAM50_cord.nii.gz" -d dmri_moco_dwi_mean.nii.gz -dseg dmri_moco_dwi_mean_seg.nii.gz -initwarp ../t2s/warp_template2t2s.nii.gz -initwarpinv ../t2s/warp_t2s2template.nii.gz -owarp warp_template2dmri.nii.gz -owarpinv warp_dmri2template.nii.gz -param step=1,type=seg,algo=centermass:step=2,type=seg,algo=bsplinesyn,slicewise=1,iter=3 -qc ~/qc_singleSubj +sct_register_multimodal -i "${SCT_DIR}"/data/PAM50/template/PAM50_t1.nii.gz -iseg "${SCT_DIR}"/data/PAM50/template/PAM50_cord.nii.gz -d dmri_moco_dwi_mean.nii.gz -dseg dmri_moco_dwi_mean_seg.nii.gz -initwarp ../t2s/warp_template2t2s.nii.gz -initwarpinv ../t2s/warp_t2s2template.nii.gz -owarp warp_template2dmri.nii.gz -owarpinv warp_dmri2template.nii.gz -param step=1,type=seg,algo=centermass:step=2,type=seg,algo=bsplinesyn,slicewise=1,iter=3 -qc ~/qc_singleSubj # Warp template (so 'label/atlas' can be used to extract metrics) sct_warp_template -d dmri_moco_dwi_mean.nii.gz -w warp_template2dmri.nii.gz -qc ~/qc_singleSubj # Check results in the QC report @@ -313,7 +313,7 @@ sct_fmri_moco -i fmri.nii.gz -m mask_fmri.nii.gz -qc ~/qc_singleSubj -qc-seg t2_ # ANTs_SyN superpower to find a suitable transformation between the PAM50_t2s and the fMRI scan. We don't want to # put too many iterations because this registration is very sensitive to the artifacts (drop out) in the image. # Also, we want a 3D transformation (not 2D) because we need the through-z regularization. -sct_register_multimodal -i "${SCT_DIR}/data/PAM50/template/PAM50_t2s.nii.gz" -d fmri_moco_mean.nii.gz -dseg t2_seg_reg.nii.gz -param step=1,type=im,algo=syn,metric=CC,iter=5,slicewise=0 -initwarp ../t2s/warp_template2t2s.nii.gz -initwarpinv ../t2s/warp_t2s2template.nii.gz -owarp warp_template2fmri.nii.gz -owarpinv warp_fmri2template.nii.gz -qc ~/qc_singleSubj +sct_register_multimodal -i "${SCT_DIR}"/data/PAM50/template/PAM50_t2s.nii.gz -d fmri_moco_mean.nii.gz -dseg t2_seg_reg.nii.gz -param step=1,type=im,algo=syn,metric=CC,iter=5,slicewise=0 -initwarp ../t2s/warp_template2t2s.nii.gz -initwarpinv ../t2s/warp_t2s2template.nii.gz -owarp warp_template2fmri.nii.gz -owarpinv warp_fmri2template.nii.gz -qc ~/qc_singleSubj # Check results in the QC report # Warp template with the spinal levels (-s 1)