diff --git a/.github/workflows/run_batch_script.yml b/.github/workflows/run_batch_script.yml index 2794316..4553393 100644 --- a/.github/workflows/run_batch_script.yml +++ b/.github/workflows/run_batch_script.yml @@ -62,10 +62,26 @@ jobs: fi done - - name: Check that script executed without error + - name: Check results (no error logs) + if: always() run: | cd "${{ github.event.repository.name }}/multi_subject/output/log" [ "$(compgen -G "process_data_sub-0*.log")" ] # Log files should exist + + - name: Check results (no error logs) + if: always() + run: | + cd "${{ github.event.repository.name }}/multi_subject/output/log" [ ! "$(compgen -G "err.process_data_sub-0*.log")" ] # Error files should NOT exist - grep -iF "warning" process_data_sub-01.log - grep -iF "error" process_data_sub-01.log + + - name: Check results (warnings in log) + if: always() + run: | + cd "${{ github.event.repository.name }}/multi_subject/output/log" + # ! grep -iF "warning" process_data_sub-01.log + + - name: Check results (errors in log) + if: always() + run: | + cd "${{ github.event.repository.name }}/multi_subject/output/log" + ! grep -iF "error" process_data_sub-01.log diff --git a/multi_subject/process_data.sh b/multi_subject/process_data.sh index d10fcb4..9fd2155 100755 --- a/multi_subject/process_data.sh +++ b/multi_subject/process_data.sh @@ -71,7 +71,6 @@ segment_if_does_not_exist() { # This allows you to add manual segmentations on a subject-by-subject basis without disrupting the pipeline. ### local file="${1}" - local contrast="${2}" # Update global variable with segmentation file name FILESEG="${file}"_seg FILESEGMANUAL="${PATH_DATA}"/derivatives/labels/"${SUBJECT}"/anat/"${FILESEG}".nii.gz @@ -84,7 +83,7 @@ segment_if_does_not_exist() { 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 -task seg_sc_contrast_agnostic -i "${file}".nii.gz -qc "${PATH_QC}" -qc-subject "${SUBJECT}" fi } @@ -111,8 +110,8 @@ rsync -avzh "${PATH_DATA}"/"${SUBJECT}" . # ====================================================================================================================== cd "${SUBJECT}"/anat/ file_t2="${SUBJECT}"_T2w -# Segment spinal cord (only if it does not exist) -segment_if_does_not_exist "${file_t2}" "t2" +# Segment spinal cord (only if it does not exist) using contrast-agnostic model +segment_if_does_not_exist "${file_t2}" file_t2_seg="${FILESEG}" # Create labels in the cord at C2 and C5 mid-vertebral levels (only if it does not exist) label_if_does_not_exist "${file_t2}" "${file_t2_seg}" @@ -132,8 +131,8 @@ sct_process_segmentation -i "${file_t2_seg}".nii.gz -vert 2:3 -vertfile label_T2 # ====================================================================================================================== file_mt1="${SUBJECT}"_acq-MTon_MTS file_mt0="${SUBJECT}"_acq-MToff_MTS -# Segment spinal cord -segment_if_does_not_exist "${file_mt1}" "t2s" +# Segment spinal cord using contrast-agnostic model +segment_if_does_not_exist "${file_mt1}" file_mt1_seg="${FILESEG}" # Create mask sct_create_mask -i "${file_mt1}".nii.gz -p centerline,"${file_mt1_seg}".nii.gz -size 45mm diff --git a/single_subject/batch_single_subject.sh b/single_subject/batch_single_subject.sh index d2f2f5d..6f0a268 100755 --- a/single_subject/batch_single_subject.sh +++ b/single_subject/batch_single_subject.sh @@ -2,10 +2,17 @@ # # Example of commands to process multi-parametric data of the spinal cord # For information about acquisition parameters, see: www.spinalcordmri.org/protocols -# N.B. The parameters were chosen to suit SCT's sample tutorial data. With your data, -# it is worthwhile to explore the various parameters and tweak them to your situation. # -# tested with Spinal Cord Toolbox (v6.1.0) +# Notes: +# - Many of the commands in this script are commented out (start with "# "). These commands won't be run by default, +# as many of them involve manual steps (e.g. via an interactive pop-up interface), or may involve data-specific +# configuration. Often these commands correspond to the "try at home" slides in the SCT Course slide deck, +# (denoted by a "red circle" in the top-right corner of the corresponding slide). Feel free to "uncomment" the +# commands by removing the "# " symbol at the start of the line, and experiment with them on your own data. +# - The parameters were chosen to suit SCT's sample tutorial data. With your data, +# it is worthwhile to explore the various parameters and tweak them to your situation. +# +# tested with Spinal Cord Toolbox (v6.5) # Script utilities # ====================================================================================================================== @@ -36,13 +43,21 @@ fi # Spinal cord segmentation # ====================================================================================================================== -# Go to T2 contrast +# Go to T2 folder cd data/t2 -# Spinal cord segmentation ( -sct_deepseg_sc -i t2.nii.gz -c t2 -qc ~/qc_singleSubj +# Spinal cord segmentation (using the new 2024 contrast-agnostic method) +sct_deepseg -task seg_sc_contrast_agnostic -i t2.nii.gz -qc ~/qc_singleSubj +# The default output is t2_seg.nii.gz +# You can also choose your own output filename using the “-o” argument +sct_deepseg -task seg_sc_contrast_agnostic -i t2.nii.gz -o test/t2_seg_2.nii.gz + # To check the QC report, use your web browser to open the file qc_singleSubj/qc/index.html, which has been created in # your home directory +# View the rest of the `sct_deepseg` tasks +sct_deepseg -h +# See also: https://spinalcordtoolbox.com/stable/user_section/command-line/sct_deepseg.html + # Vertebral labeling @@ -59,20 +74,9 @@ sct_label_vertebrae -i t2.nii.gz -s t2_seg.nii.gz -c t2 -qc ~/qc_singleSubj #sct_label_utils -i t2.nii.gz -create-viewer 3 -o label_c2c3.nii.gz -msg "Click at the posterior tip of C2/C3 inter-vertebral disc" #sct_label_vertebrae -i t2.nii.gz -s t2_seg.nii.gz -c t2 -initlabel label_c2c3.nii.gz -qc ~/qc_singleSubj -# Create labels at C3 and T2 mid-vertebral levels. These labels are needed for template registration. -sct_label_utils -i t2_seg_labeled.nii.gz -vert-body 3,9 -o t2_labels_vert.nii.gz -# Generate a QC report to visualize the two selected labels on the anatomical image -sct_qc -i t2.nii.gz -s t2_labels_vert.nii.gz -p sct_label_utils -qc ~/qc_singleSubj - -# OPTIONAL: You might want to completely bypass sct_label_vertebrae and do the labeling manually. In that case, we -# provide a viewer to do so conveniently. In the example command below, we will create labels at the inter-vertebral -# discs C2-C3 (value=3), C3-C4 (value=4) and C4-C5 (value=5). -#sct_label_utils -i t2.nii.gz -create-viewer 3,4,5 -o labels_disc.nii.gz -msg "Place labels at the posterior tip of each inter-vertebral disc. E.g. Label 3: C2/C3, Label 4: C3/C4, etc." - - -# Computing shape metrics +# Shape-based analysis # ====================================================================================================================== # Compute cross-sectional area (CSA) of spinal cord and average it across levels C3 and C4 @@ -80,7 +84,7 @@ sct_process_segmentation -i t2_seg.nii.gz -vert 3:4 -vertfile t2_seg_labeled.nii # Aggregate CSA value per level sct_process_segmentation -i t2_seg.nii.gz -vert 3:4 -vertfile t2_seg_labeled.nii.gz -perlevel 1 -o csa_perlevel.csv # Aggregate CSA value per slices -sct_process_segmentation -i t2_seg.nii.gz -z 30:35 -perslice 1 -o csa_perslice.csv +sct_process_segmentation -i t2_seg.nii.gz -z 30:35 -vertfile t2_seg_labeled.nii.gz -perslice 1 -o csa_perslice.csv # A drawback of vertebral level-based CSA is that it doesn’t consider neck flexion and extension. # To overcome this limitation, the CSA can instead be computed using the distance to a reference point. @@ -90,13 +94,17 @@ sct_detect_pmj -i t2.nii.gz -c t2 -qc ~/qc_singleSubj # Check the QC to make sure PMJ was properly detected, then compute CSA using the distance from the PMJ: sct_process_segmentation -i t2_seg.nii.gz -pmj t2_pmj.nii.gz -pmj-distance 64 -pmj-extent 30 -o csa_pmj.csv -qc ~/qc_singleSubj -qc-image t2.nii.gz +# The above commands will output the metrics in the subject space (with the original image's slice numbers) +# However, you can get the corresponding slice number in the PAM50 space by using the flag `-normalize-PAM50 1` +sct_process_segmentation -i t2_seg.nii.gz -vertfile t2_seg_labeled.nii.gz -perslice 1 -normalize-PAM50 1 -o csa_PAM50.csv -# Computing normalized shape metrics for compressed data + +# Quantifying spinal cord compression using maximum spinal cord compression (MSCC) and normalizing with database of healthy controls # ====================================================================================================================== cd ../t2_compression # Segment the spinal cord of the compressed spine -sct_deepseg_sc -i t2_compressed.nii.gz -c t2 -qc ~/qc_singleSubj +sct_deepseg -task seg_sc_contrast_agnostic -i t2_compressed.nii.gz -qc ~/qc_singleSubj # Label the vertebrae using the compressed spinal cord segmentation sct_label_vertebrae -i t2_compressed.nii.gz -s t2_compressed_seg.nii.gz -c t2 -qc ~/qc_singleSubj # Generate labels for each spinal cord compression site. @@ -114,42 +122,36 @@ sct_compute_compression -i t2_compressed_seg.nii.gz -vertfile t2_compressed_seg_ -# Lesion analysis -# ====================================================================================================================== -cd ../t2_lesion -# Segment the spinal cord and intramedullary lesion using the SCIsegV2 model -# Note: t2.nii.gz contains a fake lesion for the purpose of this tutorial -sct_deepseg -i t2.nii.gz -task seg_sc_lesion_t2w_sci -qc ~/qc_singleSubj -# Note: Two files are output: -# - t2_sc_seg.nii.gz: the spinal cord segmentation -# - t2_lesion_seg.nii.gz: the lesion segmentation - -# Check results using FSLeyes -fsleyes t2.nii.gz -cm greyscale t2_sc_seg.nii.gz -cm red -a 70.0 t2_lesion_seg.nii.gz -cm blue-lightblue -a 70.0 & - -# Compute various morphometric measures, such as number of lesions, lesion length, lesion volume, etc. -sct_analyze_lesion -m t2_lesion_seg.nii.gz -s t2_sc_seg.nii.gz -qc ~/qc_singleSubj - - - -# Rootlets segmentation +# Registration to template # ====================================================================================================================== cd ../t2 -# Segment the spinal nerve rootlets -sct_deepseg -i t2.nii.gz -task seg_spinal_rootlets_t2w -qc ~/qc_singleSubj - -# Check results using FSLeyes -fsleyes t2.nii.gz -cm greyscale t2_seg.nii.gz -cm subcortical -a 70.0 & +# Create labels at C3 and T2 mid-vertebral levels. These labels are needed for template registration. +sct_label_utils -i t2_seg_labeled.nii.gz -vert-body 3,9 -o t2_labels_vert.nii.gz +# Generate a QC report to visualize the two selected labels on the anatomical image +sct_qc -i t2.nii.gz -s t2_labels_vert.nii.gz -p sct_label_utils -qc ~/qc_singleSubj +# OPTIONAL: You might want to completely bypass sct_label_vertebrae and do the labeling manually. In that case, we +# provide a viewer to do so conveniently. In the example command below, we will create labels at the inter-vertebral +# discs C2-C3 (value=3), C3-C4 (value=4) and C4-C5 (value=5). +#sct_label_utils -i t2.nii.gz -create-viewer 3,4,5 -o labels_disc.nii.gz -msg "Place labels at the posterior tip of each inter-vertebral disc. E.g. Label 3: C2/C3, Label 4: C3/C4, etc." -# Registering T2 data to the PAM50 template -# ====================================================================================================================== -cd ../t2 # Register t2->template. sct_register_to_template -i t2.nii.gz -s t2_seg.nii.gz -l t2_labels_vert.nii.gz -c t2 -qc ~/qc_singleSubj # Note: By default the PAM50 template is selected. You can also select your own template using flag -t. +# Register t2->template with modified parameters (advanced usage of `-param`) +sct_register_to_template -i t2.nii.gz -s t2_seg.nii.gz -l t2_labels_vert.nii.gz -qc ~/qc_singleSubj -ofolder advanced_param -c t2 -param step=1,type=seg,algo=rigid:step=2,type=seg,metric=CC,algo=bsplinesyn,slicewise=1,iter=3:step=3,type=im,metric=CC,algo=syn,slicewise=1,iter=2 + +# Register t2->template with large FOV (e.g. C2-L1) using `-ldisc` option +# sct_register_to_template -i t2.nii.gz -s t2_seg.nii.gz -ldisc t2_seg_labeled_discs.nii.gz -c t2 + +# Register t2->template in compressed cord (example command) +# In case of highly compressed cord, the algo columnwise can be used, which allows for more deformation than bsplinesyn. +# NB: In the example below, the registration is done in the subject space (no straightening) using a single label point at disc C3-C4 (). +# sct_register_to_template -i -s -ldisc -ref subject -param step=1,type=seg, +# algo=centermassrot:step=2,type=seg,algo=columnwise + # Warp template objects (T2, cord segmentation, vertebral levels, etc.). Here we use -a 0 because we don’t need the # white matter atlas at this point. sct_warp_template -d t2.nii.gz -w warp_template2anat.nii.gz -a 0 -qc ~/qc_singleSubj @@ -161,13 +163,13 @@ fsleyes t2.nii.gz -cm greyscale -a 100.0 label/template/PAM50_t2.nii.gz -cm grey -# Registering additional MT data to the PAM50 template +# Registering additional contrasts (MT registration to T2 template) # ====================================================================================================================== # Go to mt folder cd ../mt # Segment cord -sct_deepseg_sc -i mt1.nii.gz -c t2 -qc ~/qc_singleSubj +sct_deepseg -task seg_sc_contrast_agnostic -i mt1.nii.gz -qc ~/qc_singleSubj # Create a close mask around the spinal cord for more accurate registration (i.e. does not account for surrounding # tissue which could move independently from the cord) @@ -194,7 +196,7 @@ fsleyes mt1.nii.gz -cm greyscale -a 100.0 label/template/PAM50_t2.nii.gz -cm gre -# Computing MTR using MT0/MT1 coregistration +# Registering additional contrasts (MT0/MT1 coregistration to compute MTR) # ====================================================================================================================== # Register mt0->mt1 using z-regularized slicewise translations (algo=slicereg) @@ -208,33 +210,12 @@ sct_compute_mtr -mt0 mt0_reg.nii.gz -mt1 mt1.nii.gz -# Contrast-agnostic registration -# ====================================================================================================================== - -# 1. T2w preprocessing (cropping around spinal cord) -cd ../t2 -sct_deepseg_sc -i t2.nii.gz -c t2 -qc ~/qc_singleSubj -sct_create_mask -i t2.nii.gz -p centerline,t2_seg.nii.gz -size 35mm -f cylinder -o mask_t2.nii.gz -sct_crop_image -i t2.nii.gz -m mask_t2.nii.gz - -# 2. T1w preprocessing (cropping around spinal cord) -cd ../t1 -sct_deepseg_sc -i t1.nii.gz -c t1 -qc ~/qc_singleSubj -sct_create_mask -i t1.nii.gz -p centerline,t1_seg.nii.gz -size 35mm -f cylinder -o mask_t1.nii.gz -sct_crop_image -i t1.nii.gz -m mask_t1.nii.gz - -# 3. Perform registration -# NB: `-dseg` is not necessary for registration, but is provided for the `-qc` reporting to help with spinal cord visualization -sct_register_multimodal -i t1_crop.nii.gz -d ../t2/t2_crop.nii.gz -param step=1,type=im,algo=dl -qc ~/qc_singleSubj -dseg ../t2/t2_seg.nii.gz - - - -# Registering lumbar data to the PAM50 template +# Registering additional contrasts (T2 lumbar data) # ====================================================================================================================== cd ../t2_lumbar # Use lumbar-specific `sct_deepseg` model to segment the spinal cord -sct_deepseg -i t2_lumbar.nii.gz -task seg_lumbar_sc_t2w +sct_deepseg -i t2_lumbar.nii.gz -task seg_lumbar_sc_t2w -qc ~/qc_singleSubj # Generate labels for the 2 spinal cord landmarks: cauda equinea ('99') and T9-T10 disc ('17') # Note: Normally this would be done manually using fsleyes' "Edit mode -> Create mask" functionality. (Uncomment below) @@ -243,18 +224,14 @@ sct_deepseg -i t2_lumbar.nii.gz -task seg_lumbar_sc_t2w # # However, since this is an automated script with example data, we will place the labels at known locations for the # sake of reproducing the results in the tutorial. -sct_label_utils -i t2_lumbar.nii.gz -create 22,77,187,17:27,79,80,60 -o t2_lumbar_labels.nii.gz +sct_label_utils -i t2_lumbar.nii.gz -create 27,76,187,17:27,79,80,60 -o t2_lumbar_labels.nii.gz -qc ~/qc_singleSubj # Register the image to the template using segmentation and labels -sct_register_to_template -i t2_lumbar.nii.gz \ - -s t2_lumbar_seg.nii.gz \ - -ldisc t2_lumbar_labels.nii.gz \ - -c t2 -qc qc \ - -param step=1,type=seg,algo=centermassrot:step=2,type=seg,algo=bsplinesyn,metric=MeanSquares,iter=3,slicewise=0:step=3,type=im,algo=syn,metric=CC,iter=3,slicewise=0 +sct_register_to_template -i t2_lumbar.nii.gz -s t2_lumbar_seg.nii.gz -ldisc t2_lumbar_labels.nii.gz -c t2 -qc ~/qc_singleSubj -param step=1,type=seg,algo=centermassrot:step=2,type=seg,algo=bsplinesyn,metric=MeanSquares,iter=3,slicewise=0:step=3,type=im,algo=syn,metric=CC,iter=3,slicewise=0 -# Gray/white matter: Segmentation +# Gray matter segmentation (GM/WM seg) # ====================================================================================================================== # Go to T2*-weighted data, which has good GM/WM contrast and high in-plane resolution @@ -262,13 +239,16 @@ cd ../t2s # Segment gray matter (check QC report afterwards) sct_deepseg_gm -i t2s.nii.gz -qc ~/qc_singleSubj # Spinal cord segmentation -sct_deepseg_sc -i t2s.nii.gz -c t2s -qc ~/qc_singleSubj +sct_deepseg -task seg_sc_contrast_agnostic -i t2s.nii.gz -qc ~/qc_singleSubj # Subtract GM segmentation from cord segmentation to obtain WM segmentation -sct_maths -i t2s_seg.nii.gz -sub t2s_gmseg.nii.gz -o t2s_wmseg.nii.gz +# Note that we use the flag -thr 0 in case some voxels in the GM segmentation are *not* included in the cord +# segmentation. That would results in voxels in the WM segmentation having the value “-1”, which would cause issues +# with the registration. +sct_maths -i t2s_seg.nii.gz -sub t2s_gmseg.nii.gz -thr 0 -o t2s_wmseg.nii.gz -# Gray/white matter: Computing metrics using binary segmentation masks +# Gray matter segmentation (Shape-based analysis and metric extraction) # ====================================================================================================================== # Compute cross-sectional area (CSA) of the gray and white matter for all slices in the volume. @@ -287,7 +267,7 @@ sct_extract_metric -i t2s.nii.gz -f t2s_gmseg.nii.gz -method bin -z 2:12 -o t2s_ -# Gray/white matter: Improving registration results using binary segmentation masks +# Gray matter segmentation (Improving registration results using binary segmentation masks) # ====================================================================================================================== # Register template->t2s (using warping field generated from template<->t2 registration) @@ -296,8 +276,9 @@ sct_register_multimodal -i "${SCT_DIR}"/data/PAM50/template/PAM50_t2s.nii.gz -is # Warp template sct_warp_template -d t2s.nii.gz -w warp_template2t2s.nii.gz -qc ~/qc_singleSubj +# Register another metric while reusing newly-created GM-informed warping fields cd ../mt -# Register template->mt via t2s to account for GM segmentation +# Register template->mt using `-initwarp` with 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 # Warp template sct_warp_template -d mt1.nii.gz -w warp_template2mt.nii.gz -qc ~/qc_singleSubj @@ -330,23 +311,23 @@ cd ../dmri sct_dmri_separate_b0_and_dwi -i dmri.nii.gz -bvec bvecs.txt # Segment SC on mean dMRI data # Note: This segmentation does not need to be accurate-- it is only used to create a mask around the cord -sct_deepseg_sc -i dmri_dwi_mean.nii.gz -c dwi -qc ~/qc_singleSubj +sct_deepseg -task seg_sc_contrast_agnostic -i dmri_dwi_mean.nii.gz -qc ~/qc_singleSubj # Create mask (for subsequent cropping) -sct_create_mask -i dmri_dwi_mean.nii.gz -p centerline,dmri_dwi_mean_seg.nii.gz -f cylinder -size 35mm +sct_create_mask -i dmri_dwi_mean.nii.gz -p centerline,dmri_dwi_mean_seg.nii.gz -size 35mm # Motion correction (moco) sct_dmri_moco -i dmri.nii.gz -m mask_dmri_dwi_mean.nii.gz -bvec bvecs.txt -qc ~/qc_singleSubj -qc-seg dmri_dwi_mean_seg.nii.gz # Check results in the QC report # Segment SC on motion-corrected mean dwi data (check results in the QC report) -sct_deepseg_sc -i dmri_moco_dwi_mean.nii.gz -c dwi -qc ~/qc_singleSubj +sct_deepseg -task seg_sc_contrast_agnostic -i dmri_moco_dwi_mean.nii.gz -qc ~/qc_singleSubj -# Register template->dwi via t2s to account for GM segmentation +# Register template->dwi via t2 to account for cord shape (which is better defined in T2 contrast) # Tips: Here we use the PAM50 contrast t1, which is closer to the dwi contrast (although we are not using type=im in # -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 ../t2/warp_template2anat.nii.gz -initwarpinv ../t2/warp_anat2template.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 @@ -375,12 +356,19 @@ sct_create_mask -i fmri.nii.gz -p centerline,t2_seg_reg.nii.gz -size 35mm -f cyl # Motion correction (using mask) sct_fmri_moco -i fmri.nii.gz -m mask_fmri.nii.gz -qc ~/qc_singleSubj -qc-seg t2_seg_reg.nii.gz +# Cord segmentation on motion-corrected averaged time series +sct_deepseg -i fmri_moco_mean.nii.gz -task seg_sc_contrast_agnostic -qc ~/qc_singleSubj/ +# TSNR before/after motion correction with QC report +sct_fmri_compute_tsnr -i fmri.nii.gz +sct_fmri_compute_tsnr -i fmri_moco.nii.gz +sct_qc -i fmri_tsnr.nii.gz -d fmri_moco_tsnr.nii.gz -s fmri_moco_mean_seg.nii.gz -p sct_fmri_compute_tsnr -qc ~/qc_singleSubj/ + # Register the template to the fMRI scan. # Note: here we don't rely on the segmentation because it is difficult to obtain one automatically. Instead, we rely on # 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 -iseg "${SCT_DIR}"/data/PAM50/template/PAM50_cord.nii.gz -d fmri_moco_mean.nii.gz -dseg fmri_moco_mean_seg.nii.gz -param step=1,type=seg,algo=centermass:step=2,type=seg,algo=bsplinesyn,slicewise=1,iter=3:step=3,type=im,algo=syn,metric=CC,iter=3,slicewise=1 -initwarp ../t2/warp_template2anat.nii.gz -initwarpinv ../t2/warp_anat2template.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 (can be found at $SCT_DIR/data/PAM50/template/) @@ -392,15 +380,67 @@ sct_warp_template -d fmri_moco_mean.nii.gz -w warp_template2fmri.nii.gz -a 0 -qc cd ../t1 # Segment T1-weighted image (to be used in later steps) -sct_deepseg_sc -i t1.nii.gz -c t1 +sct_deepseg -task seg_sc_contrast_agnostic -i t1.nii.gz -qc ~/qc_singleSubj/ # Smooth spinal cord along centerline (extracted from the segmentation) sct_smooth_spinalcord -i t1.nii.gz -s t1_seg.nii.gz # Tips: use flag "-sigma" to specify smoothing kernel size (in mm) +# Second-pass segmentation using the smoothed anatomical image +sct_deepseg_sc -i t1_smooth.nii.gz -c t1 -qc ~/qc_singleSubj + # Align the spinal cord in the right-left direction using slice-wise translations. sct_flatten_sagittal -i t1.nii.gz -s t1_seg.nii.gz # Note: Use for visualization purposes only + + +# New features (SCT v6.5, December 2024) +# ====================================================================================================================== + +# Lesion analysis for SCI and MS lesions +cd ../t2_lesion +# Segment the spinal cord and intramedullary lesion using the SCIsegV2 model +# Note: t2.nii.gz contains a fake lesion for the purpose of this tutorial +sct_deepseg -i t2.nii.gz -task seg_sc_lesion_t2w_sci -qc ~/qc_singleSubj +# Note: Two files are output: +# - t2_sc_seg.nii.gz: the spinal cord segmentation +# - t2_lesion_seg.nii.gz: the lesion segmentation +# Check results using FSLeyes +fsleyes t2.nii.gz -cm greyscale t2_sc_seg.nii.gz -cm red -a 70.0 t2_lesion_seg.nii.gz -cm blue-lightblue -a 70.0 & + +# Note: We also have a contrast-agnostic segmentation command for MS lesions, too: +sct_deepseg -i t2.nii.gz -task seg_ms_lesion -qc ~/qc_singleSubj +# As well as a segmentation command tailored to MP2RAGE MS lesions +# sct_deepseg -i t2.nii.gz -task seg_ms_lesion_mp2rage -qc ~/qc_singleSubj + +# Compute various morphometric measures, such as number of lesions, lesion length, lesion volume, etc. +sct_analyze_lesion -m t2_lesion_seg.nii.gz -s t2_sc_seg.nii.gz -qc ~/qc_singleSubj +# Lesion analysis using PAM50 (the -f flag is used to specify the folder containing the atlas/template) +# Note: You must go through the "Register to Template" steps (labeling, registration) first +# This is because `sct_warp_template` is required to generate the `label` folder used for `-f` +# sct_analyze_lesion -m t2_lesion_seg.nii.gz -s t2_sc_seg.nii.gz -f label -qc ~/qc_singleSubj + +# Segment the spinal cord on gradient echo EPI data +cd ../fmri/ +sct_deepseg -i fmri_moco_mean.nii.gz -task seg_sc_epi -qc ~/qc_singleSubj + +# Canal segmentation +cd ../t2 +sct_deepseg -i t2.nii.gz -task canal_t2w -qc ~/qc_singleSubj +# Check results using FSLeyes +fsleyes t2.nii.gz -cm greyscale t2_canal_seg_seg.nii.gz -cm red -a 70.0 & + +# Full spinal segmentation (Vertebrae, Intervertebral discs, Spinal cord and Spinal canal) +# Segment using totalspineseg +sct_deepseg -i t2.nii.gz -task totalspineseg -qc ~/qc_singleSubj +# Check results using FSLeyes +fsleyes t2.nii.gz -cm greyscale t2_step1_canal.nii.gz -cm YlOrRd -a 70.0 t2_step1_cord.nii.gz -cm YlOrRd -a 70.0 t2_step1_levels.nii.gz -cm subcortical -a 70.0 t2_step1_output.nii.gz -cm subcortical -a 70.0 t2_step2_output.nii.gz -cm subcortical -a 70.0 & + +# Segment the spinal nerve rootlets +sct_deepseg -i t2.nii.gz -task seg_spinal_rootlets_t2w -qc ~/qc_singleSubj +# Check results using FSLeyes +fsleyes t2.nii.gz -cm greyscale t2_rootlets.nii.gz -cm subcortical -a 70.0 & + # Return to parent directory cd ..