PAM50 Template Registration for highly anisotropic axial scans

Hello SCT Team,

I am currently working on a comprehensive whole spine project focusing on MS with fully segmented cord and lesion masks. We have employed SCT 6.0 for registration to the PAM50 template. As of now, we have chosen to work exclusively with stitched axial images, which are highly anisotropic (0.7x0.7x5). Disk labeling (for all levels) is done manually via sct_label_utils, as we encountered challenges when trying to automate the step with sct_label_vertebrae. We have successfully registered these stitched scans to the template but have the following questions:

  1. Does the quality of our current registration meet the criteria for further analysis (perhaps the screenshot helps?), such as gray-matter/white-matter atlas analysis, lesion frequency maps, and lesion load? I hope the attached screenshot allows you to give some indication. It’s hard for me to judge if the jittering is expected/normal, or if this is an example of poor registration quality.

  1. Are there recommendations for optimizing the template registration process beyond the default settings we’ve been using? (I would gladly share some of the data with you in the context of our collaboration but need to ensure the data remains confidential.)

  2. Regarding manual disk labeling, if there’s a variation in the sagittal plane (like always centering the image to midline before placing the disc label), how might it influence the registration to the PAM50 template? Does this process potentially impact the jittering of the cord?

Additionally, I’d like to mention that we are happy to share raw and processed data results with the SC, but at the moment I do not have permission to post the 3D NIFTIs here. If this is mandatory, I can ask the clinicians (once they return from summer vacations) for a sample we could potentially share.

Thank you very much.

Cheers,
Julian

Hi @jqmcginnis,

thank you for reaching out!

  1. Does the quality of our current registration meet the criteria for further analysis (perhaps the screenshot helps?), such as gray-matter/white-matter atlas analysis, lesion frequency maps, and lesion load? I hope the attached screenshot allows you to give some indication. It’s hard for me to judge if the jittering is expected/normal, or if this is an example of poor registration quality.

The jittering is definitely sub-optimal and likely results in issues with the segmentation and/or straightening and/or registration parameters. Could you please send a representative dataset alongside your script so we can reproduce and debug from there.

  1. Are there recommendations for optimizing the template registration process beyond the default settings we’ve been using? (I would gladly share some of the data with you in the context of our collaboration but need to ensure the data remains confidential.)

Yes, but it depends on the data. I would need to “play” with them to get a sense of the best registration parameters.

  1. Regarding manual disk labeling, if there’s a variation in the sagittal plane (like always centering the image to midline before placing the disc label), how might it influence the registration to the PAM50 template? Does this process potentially impact the jittering of the cord?

Labeling is only used at step=0 of sct_register_to_template to find an S-I transformation. So nothing is happening along A-P and R-L. When using 2+ vert/disc labels, that transformation is non-affine (affine otherwise). So no, I don’t think the jittering is from there, although I would need your script so I can reproduce exactly what you did and confirm the source of the jittering.

Thank you very much, I have sent you a representative dataset via slack :+1:

Very good, that’s exactly the feedback the neurologist in our team needed!

I have also attached the script here, in case another community member would like to understand our discussion in the future.
register_to_PAM50_manual_disks_cleaned.sh (8.7 KB)

Hi Julian,

Sorry about the delay. Here are the results of my investigations.

Firstly, it appears that the jittering is caused by the cord straightening procedure, which is part of sct_register_to_template. The straightened cord is output with the file name straight_ref.nii.gz, so that’s the one I compared across various experiments below.

Image resolution

I was wondering if highly anisotropic axial resolution (0.6x0.6x4.8mm) was causing that problem, so I resampled the image, segmentation and labels:

# Resample anat to 1mm iso
sct_resample -i sub-m023917_ses-20160302_acq-ax_T2w.nii.gz -mm 1 -x linear 
# Change input segmentation type to FLOAT32 before resampling to linear for better precision
sct_image -i sub-m023917_ses-20160302_acq-ax_seg_T2w.nii.gz -type float32 -o sub-m023917_ses-20160302_acq-ax_seg_T2w_float32.nii.gz
# Resample seg to 1mm
sct_resample -i sub-m023917_ses-20160302_acq-ax_seg_T2w_float32.nii.gz -mm 1 -x linear
# Resample labels to 1mm
# Note: We cannot use simple nearest neighbour interpolation, otherwise labels will be duplicated with upsampling. Hence, we need to use `sct_apply_transfo`, which uses the center of mass of each label.
sct_register_multimodal -i sub-m023917_ses-20160302_acq-ax_disks_T2w.nii.gz -d sub-m023917_ses-20160302_acq-ax_T2w_r.nii.gz -identity 1 
sct_apply_transfo -i sub-m023917_ses-20160302_acq-ax_disks_T2w.nii.gz -d sub-m023917_ses-20160302_acq-ax_T2w_r.nii.gz -w warp_sub-m023917_ses-20160302_acq-ax_disks_T2w2sub-m023917_ses-20160302_acq-ax_T2w_r.nii.gz -x label

However, when comparing straight_ref.nii.gz with/without resampling, the jittering is still there:

comparison_straightening_resampled

Quality of segmentation

Another concern is the quality of the segmentation. I noticed strange effects, for example the same segmentation across two adjacent slices, with sub-optimal matching between the cord and the mask:

same_seg

Other issues concern sub-optimal segmentation, such as the leaking below (the manual segmentation you provided is in white):

leaking

I am wondering why you did not start from sct_deepseg_sc, which seems to give overall better segmentation than the manual segmentation (red segmentation in the GIF above).

However, despite the better segmentation, the jittering still occurs:

deepseg

2+ labels

Using 2+ labels implies a non-linear registration at step=0 to match the disc levels of the PAM50. Given the highly anisotropic resolution, maybe this non-linear registration is causing the jittering. I tried doing the registration to the template with only 2 discs:

sct_label_utils -i sub-m023917_ses-20160302_acq-ax_disks_T2w.nii.gz -keep 2,8 -o sub-m023917_ses-20160302_acq-ax_disks_T2w_2-8.nii.gz
sct_register_to_template -i sub-m023917_ses-20160302_acq-ax_T2w.nii.gz -s sub-m023917_ses-20160302_acq-ax_T2w_seg.nii.gz -ldisc sub-m023917_ses-20160302_acq-ax_disks_T2w_2-8.nii.gz -c t2 -r 0

However, the jittering is still there:

:warning: IMPORTANT
Please be aware that when using 2+ labels, the image is cropped above/below the top/bottom labels. So make sure cropping does not happen in regions you are interested in, otherwise add more labels at the top/bottom, or use 2 labels only.

Straightening

Strangely, when running straightening outside of sct_register_to_template, there is no jittering, on both the manual and the deepseg-based segmentations:

sct_straighten_spinalcord

So, this suggests something fishy in sct_register_to_template pipeline. Digging deeper…

When looking at the straightening results on the intermediate outputs of the function (using -r 0 flag to access them), I notice that the straightening is performed on the 1mm resampled data. Now, one issue that was recently noticed, is that the resampling performed on binary masks with dtype UINT8 produces binary masks, even though linear interpolation is specified (for more details see issue: https://github.com/spinalcordtoolbox/spinalcordtoolbox/issues/4210). So let’s try to resample the segmentation properly to FLOAT32 with linear interpolation, and run the straightening:

sct_image -i seg_bin.nii.gz -type float32 -o seg_bin_float32.nii.gz
sct_resample -i seg_bin_float32.nii.gz -mm 1
sct_image -i seg_bin_float32_r.nii.gz -setorient RPI
sct_crop_image -i seg_bin_float32_r.nii.gz -zmin 148 -zmax 485 
sct_straighten_spinalcord -i seg_bin_float32_r_crop.nii.gz -s seg_bin_float32_r_crop.nii.gz -dest template_seg_crop.nii.gz

Nope, that didn’t help:

However, when running the straightening on the native resolution, there is no jittering:

sct_straighten_spinalcord -i seg.nii.gz -s seg.nii.gz

This suggests that the issue is intrinsic to the native anisotropic resolution, and straightening images with axial images with large thickness will inevitably result in jittering, especially in presence of large curvature (ie: cases where the cord is not orthogonal to the slice).

Registration parameter

An obvious way to mitigate the jittering, is to regularize during registration. By default, sct_register_to_template uses centermassrot at step=1, so if there is any jittering, it will be passed on by centermassrot. Instead, I recommend using e.g. slicereg with high polynomial order (to accommodate complex cord curvatures) and relying on the image at step=2 for fine-tuning:

sct_register_to_template -i sub-m023917_ses-20160302_acq-ax_T2w.nii.gz -s sub-m023917_ses-20160302_acq-ax_T2w_seg.nii.gz -ldisc sub-m023917_ses-20160302_acq-ax_disks_T2w.nii.gz -c t2 -param step=1,type=seg,algo=slicereg,smooth=1,poly=5:step=2,type=im,algo=syn,metric=cc,iter=3

Results look nice in the native space:

anim

However there is still jittering in the template space, which I think is caused by the transformation of highly anisotropic resolution data coupled with high cord curvature:

reg_template_space

Unfortunately I don’t think there is anything we can do here, apart from adding smoothing on the input image, but that will reduce the effective resolution.

:warning: IMPORTANT
I’ve only tried one set of registration parameter (not enough time). By spending some more time tweaking the registration parameters, you might be able to obtain even better results. Also, I’ve only tested on one subject, so make sure these params apply to your cohort.

Conclusion

My suggestions are:

  • Improve the segmentation you are working with (use sct_deepseg_sc and manually correct)
  • Use the suggested registration parameters, which are possibly less sensitive to the jittering of the straightened segmentation at step=1,
  • Do you really need to register to the PAM50 if your goal is to quantify lesions and CSA? Given the highly anisotropic nature of the data, I think you are better off doing the metric computation in the native space.

See my updated script with some comments: register_to_PAM50_manual_disks_cleaned_julien.sh (9.4 KB)