Dog Template Registration qform sform error

Please see link for previous conversations.

Unfortunately I am still receiving the following error even after changes all 3 image sets as instructed. It seems as if though the temporary file is creating it to where the sform and qform do not match. I can look through the dog template to ensure that they match.

--
Spinal Cord Toolbox (git-master-4220101576d7b18a5b1af18a8b211d8a849ec2ef)

sct_register_to_template -i T2w.nii.gz -s T2w_label-SC_seg.nii.gz -ldisc T2w_labels-disc.nii.gz -t data/template-dog -c t2 -s-template-id 2 -param step=1,type=seg,algo=centermassrot:step=2,type=im,algo=syn,metric=CC,iter=3 -ofolder HB_to_temp -qc qc_HB_to_temp
--


Check template files...
  OK: data/template-dog/template/templatedog_t2w.nii.gz
  OK: data/template-dog/template/templatedog_label_disc.nii.gz
  OK: data/template-dog/template/templatedog_cord.nii.gz

Check parameters:
  Data:                 T2w.nii.gz
  Landmarks:            T2w_labels-disc.nii.gz
  Segmentation:         T2w_label-SC_seg.nii.gz
  Path template:        data/template-dog
  Remove temp files:    1

Check input labels...
Creating temporary folder (/var/folders/zz/m4pgv4k94xn25p3h22kdhw1m0000gp/T/sct_2024-10-30_13-46-55_register-to-template_lyth7fo8)

Copying input data to tmp folder and convert to nii...

Check if provided labels are available in the template

Binarize segmentation

Change orientation of input images to RPI...

Resample data to 1mm isotropic...
load data...

Done! To view results, type:
fsleyes data_rpi_1mm.nii &

load data...
Converting image from type 'uint8' to type 'float64' for linear interpolation

Done! To view results, type:
fsleyes seg_bin_rpi_1mm.nii.gz &

To avoid intensity overflow due to convertion to +uint8+, intensity will be rescaled to the maximum quantization scale

Straighten the spinal cord using centerline/segmentation...
Creating temporary folder (/var/folders/zz/m4pgv4k94xn25p3h22kdhw1m0000gp/T/sct_2024-10-30_13-46-57_straighten-spinalcord_ep78v4k8)
Copy files to tmp folder...
Image /private/var/folders/zz/m4pgv4k94xn25p3h22kdhw1m0000gp/T/sct_2024-10-30_13-46-55_register-to-template_lyth7fo8/seg_bin_rpi_1mm_crop.nii.gz has different qform and sform matrices. This can produce incorrect results. Please use 'sct_image -i /private/var/folders/zz/m4pgv4k94xn25p3h22kdhw1m0000gp/T/sct_2024-10-30_13-46-55_register-to-template_lyth7fo8/seg_bin_rpi_1mm_crop.nii.gz -header' to check that both affine matrices are valid. Then, consider running either 'sct_image -set-sform-to-qform' or 'sct_image -set-qform-to-sform' to fix any discrepancies you may find.
Traceback (most recent call last):
  File "/Users/richardshinn/spinalcordtoolbox/spinalcordtoolbox/scripts/sct_register_to_template.py", line 815, in <module>
    main(sys.argv[1:])
  File "/Users/richardshinn/spinalcordtoolbox/spinalcordtoolbox/scripts/sct_register_to_template.py", line 564, in main
    sc_straight.straighten()
  File "/Users/richardshinn/spinalcordtoolbox/spinalcordtoolbox/straightening.py", line 108, in straighten
    Image(fname_anat, check_sform=True).save(os.path.join(path_tmp, "data.nii"))
  File "/Users/richardshinn/spinalcordtoolbox/spinalcordtoolbox/image.py", line 343, in __init__
    raise ValueError("Image sform does not match qform")
ValueError: Image sform does not match qform
1 Like

The command that fails is this one, quoted above.

Looking at the context of that command, fname_anat corresponds to the -i argument of sct_straighten_spinalcord. This command gets called in the middle of template registration here, on the file ftmp_seg, which corresponds to fname_seg (i.e. the -s argument for sct_register_to_template). Meaning, it is the -s argument that is the issue.

I think there are two possibilities:

  1. The input -s file has mismatched sform/qform (unlikely because you ran sct_image on all 3 images)
  2. One of the SCT preprocessing commands introduces a mismatch, and the problem is internal.

Are you able to share the data for the subject that produced this error? Feel free to share it privately to my university email (joshua.newton@polymtl.ca). If you can, it would help me to debug the issue.

Kind regards,
Joshua

1 Like

Thank you for the email, @Richard_Shinn! Using your data, I ran into the exact same issue.

Here are the commands I used to reproduce the error:

# get SC seg
sct_propseg -i T2w.nii.gz -c t2
mv T2w_seg.nii.gz T2w_label-SC_seg.nii.gz

# get disc labels
sct_label_utils -i T2w.nii.gz -viewer 3,9
mv labels.nii.gz T2w_labels-disc.nii.gz

# run registration
sct_register_to_template -i T2w.nii.gz -s T2w_label-SC_seg.nii.gz -ldisc T2w_labels-disc.nii.gz -t $SCT_DIR/data/template-dog -c t2 -s-template-id 2 -param step=1,type=seg,algo=centermassrot:step=2,type=im,algo=syn,metric=CC,iter=3 -ofolder HB_to_temp -qc qc_HB_to_temp
Error log
dot|joshua@mosaic:~/data/forum_t2_dog$ sct_register_to_template -i T2w.nii.gz -s T2w_label-SC_seg.nii.gz -ldisc T2w_labels-disc.nii.gz -t $SCT_DIR/data/template-dog -c t2 -s-template-id 2 -param step=1,type=seg,algo=centermassrot:step=2,type=im,algo=syn,metric=CC,iter=3 -ofolder HB_to_temp -qc qc_HB_to_temp

--
Spinal Cord Toolbox (git-jn/3767-add-sct_deepseg-model-gallery-bf67702b863b1124ea36907e047da894d57e6379)

sct_register_to_template -i T2w.nii.gz -s T2w_label-SC_seg.nii.gz -ldisc T2w_labels-disc.nii.gz -t /home/joshua/repos/spinalcordtoolbox/data/template-dog -c t2 -s-template-id 2 -param step=1,type=seg,algo=centermassrot:step=2,type=im,algo=syn,metric=CC,iter=3 -ofolder HB_to_temp -qc qc_HB_to_temp
--


Check template files...
  OK: /home/joshua/repos/spinalcordtoolbox/data/template-dog/template/templatedog_t2w.nii.gz
  OK: /home/joshua/repos/spinalcordtoolbox/data/template-dog/template/templatedog_label_disc.nii.gz
  OK: /home/joshua/repos/spinalcordtoolbox/data/template-dog/template/templatedog_cord.nii.gz

Check parameters:
  Data:                 T2w.nii.gz
  Landmarks:            T2w_labels-disc.nii.gz
  Segmentation:         T2w_label-SC_seg.nii.gz
  Path template:        /home/joshua/repos/spinalcordtoolbox/data/template-dog
  Remove temp files:    1

Check input labels...
Creating temporary folder (/tmp/sct_2024-11-08_13-01-46_register-to-template_z86brmqa)

Copying input data to tmp folder and convert to nii...

Check if provided labels are available in the template

Binarize segmentation
Image header specifies datatype 'int8', but array is of type '<class 'numpy.uint8'>'. Header metadata will be overwritten to use '<class 'numpy.uint8'>'.

Change orientation of input images to RPI...

Resample data to 1mm isotropic...
load data...

Done! To view results, type:
fsleyes data_rpi_1mm.nii &

load data...
Converting image from type 'uint8' to type 'float64' for linear interpolation

Done! To view results, type:
fsleyes seg_bin_rpi_1mm.nii.gz &

To avoid intensity overflow due to convertion to +uint8+, intensity will be rescaled to the maximum quantization scale

Straighten the spinal cord using centerline/segmentation...
Creating temporary folder (/tmp/sct_2024-11-08_13-01-48_straighten-spinalcord__vkbmutw)
Copy files to tmp folder...
Image /tmp/sct_2024-11-08_13-01-46_register-to-template_z86brmqa/seg_bin_rpi_1mm_crop.nii.gz has different qform and sform matrices. This can produce incorrect results. Please use 'sct_image -i /tmp/sct_2024-11-08_13-01-46_register-to-template_z86brmqa/seg_bin_rpi_1mm_crop.nii.gz -header' to check that both affine matrices are valid. Then, consider running either 'sct_image -set-sform-to-qform' or 'sct_image -set-qform-to-sform' to fix any discrepancies you may find.
Traceback (most recent call last):
  File "/home/joshua/repos/spinalcordtoolbox/spinalcordtoolbox/scripts/sct_register_to_template.py", line 803, in <module>
    main(sys.argv[1:])
  File "/home/joshua/repos/spinalcordtoolbox/spinalcordtoolbox/scripts/sct_register_to_template.py", line 552, in main
    sc_straight.straighten()
  File "/home/joshua/repos/spinalcordtoolbox/spinalcordtoolbox/straightening.py", line 108, in straighten
    Image(fname_anat, check_sform=True).save(os.path.join(path_tmp, "data.nii"))
  File "/home/joshua/repos/spinalcordtoolbox/spinalcordtoolbox/image.py", line 343, in __init__
    raise ValueError("Image sform does not match qform")
ValueError: Image sform does not match qform

When I check the input files, I can confirm that the sform/qforms all match. So, the error must be caused by the registration script.

Investigation

When I run a debugging program and examine the program when it crashes, I see:

  • Filename: '/tmp/sct_2024-11-08_13-08-00_register-to-template_c8m782ql/seg_bin_rpi_1mm_crop.nii.gz'
  • qform:
    [[-1.00712548e+00 -5.88069114e-03  3.43817538e-05  2.79939346e+01], 
     [-5.92414584e-03  9.99669682e-01 -1.16897379e-02 -1.09114853e+02], 
     [-3.46358138e-05  1.16897379e-02  9.99686978e-01 -2.81715271e+02], 
     [ 0.00000000e+00  0.00000000e+00  0.00000000e+00  1.00000000e+00]]
    
  • sform:
    [[-1.00712411e+00 -5.87104712e-03  1.68322189e-03  2.79939346e+01], 
     [-5.93385307e-03  9.99669682e-01 -1.16848804e-02 -1.09114853e+02], 
     [ 1.62638828e-03  1.16945795e-02  9.99685619e-01 -2.81715271e+02], 
     [ 0.00000000e+00  0.00000000e+00  0.00000000e+00  1.00000000e+00]],)
    
  • difference:
    image

So, they are roughly the same, except for two elements.

This discrepancy seems to come from the reorientation to RPI. Before this operation, Image(ftmp_seg, check_sform=True) passes. After the operation, Image(ftmp_seg, check_sform=True) fails.

However, this is very strange, because the reorientation function explicitly contains steps to ensure that the affines are equal.. So, this suggests that the set_qform step is not working for some reason. And indeed, these commands appear to do nothing:

# check qform before and after
>>> print(im_dst_aff - im_dst.header.get_qform())
[[ 1.23808742e-06  8.25844864e-06  1.41198199e-03 -4.76837158e-07]
 [-8.76812599e-06  1.79952582e-08  4.15943024e-06 -3.47755849e-06]
 [ 1.50030867e-03  4.14610448e-06 -1.16511079e-06  5.98956831e-06]
 [ 0.00000000e+00  0.00000000e+00  0.00000000e+00  0.00000000e+00]]

>>> im_dst.header.set_qform(im_dst_aff)

>>> print(im_dst_aff - im_dst.header.get_qform())
[[ 1.23808742e-06  8.25844864e-06  1.41198199e-03 -4.76837158e-07]
 [-8.76812599e-06  1.79952582e-08  4.15943024e-06 -3.47755849e-06]
 [ 1.50030867e-03  4.14610448e-06 -1.16511079e-06  5.98956831e-06]
 [ 0.00000000e+00  0.00000000e+00  0.00000000e+00  0.00000000e+00]]
# No change!

The issue appears to be from header.set_qform.

It looks like this bug comes from the behavior of one of our dependencies, nibabel. I will investigate further and report back once I have a solution.

Kind regards,
Joshua

Dear @Richard_Shinn,

We have discovered the source of the sform/qform discrepancy in issue #4689. We are working on a bug fix in PR #4697.

We will keep this post updated when the fix is ready. Thank you for your patience. :slight_smile:

Kind regards,
Joshua