"Joint PDF summed to zero" error encountered during motion correction step

Dear SCT team:
I encountered an issue while performing DTI analysis of the spinal cord using the Spinal Cord Toolbox (SCT). When I reached the motion correction (dMRI motion correction) step and ran the following command, I encountered an error:

sct_dmri_moco -i dmri.nii.gz -m mask_dmri_dwi_mean.nii.gz -bvec bvecs.txt \
              -qc qc -qc-seg dmri_dwi_mean_seg.nii.gz

The error message is as follows:

--
Spinal Cord Toolbox (7.0)

sct_dmri_moco -i dmri.nii.gz -m mask_dmri_dwi_mean.nii.gz -bvec bvecs.txt -qc C:/Users/horizon user/qc_singleSubj -qc-seg dmri_dwi_mean_seg.nii.gz
--


Input parameters:
  Input file ............ dmri.nii.gz
  Group size ............ 3
Creating temporary folder (C:\Users\HORIZO~1\AppData\Local\Temp\sct_2025-08-16_22-49-01_moco-wrapper_il0u8ntg)

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

Get dimensions of data...
  96 x 36 x 20

Data orientation: RPI
  Treated as axial

Set suffix of transformation file name, which depends on the orientation:
Orientation is axial, suffix is 'Warp.nii.gz'. The estimated transformation is a 3D warping field, which is composed of a stack of 2D Tx-Ty transformations

Identify b=0 and DWI images...
  WARNING: bvecs file is 3xn instead of nx3. Consider using sct_dmri_transpose_bvecs.
  Transpose bvecs...
  Number of b=0: 5 [0, 31, 62, 63, 64]
  Number of DWI: 60 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61]

Split along T dimension...

Merge and average b=0 data...
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Merge within groups:   0%|                             | 0/20 [00:00<?, ?iter/s]Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Merge within groups:  15%|###1                 | 3/20 [00:00<00:00, 23.84iter/s]Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Merge within groups:  30%|######3              | 6/20 [00:00<00:00, 23.39iter/s]Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Merge within groups:  45%|#########4           | 9/20 [00:00<00:00, 23.65iter/s]Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Merge within groups:  60%|############        | 12/20 [00:00<00:00, 23.67iter/s]Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Merge within groups:  75%|###############     | 15/20 [00:00<00:00, 22.97iter/s]Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Merge within groups:  90%|##################  | 18/20 [00:00<00:00, 23.07iter/s]Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.
Merge within groups: 100%|####################| 20/20 [00:00<00:00, 23.41iter/s]

Merge across groups...

-------------------------------------------------------------------------------
  Estimating motion on b=0 images...
-------------------------------------------------------------------------------

Input parameters:
  Input file ............ b0.nii
  Reference file ........ data_T0000.nii.gz
  Polynomial degree ..... 2
  Smoothing kernel ...... 1
  Gradient step ......... 1
  Metric ................ MI
  Sampling .............. None
  Todo .................. estimate_and_apply
  Mask  ................. mask.nii
  Output mat folder ..... mat_b0groups

Data dimensions:
  96 x 36 x 20 x 5

Copy file_target to a temporary file...
Image header specifies datatype 'int32', but array is of type '<class 'numpy.uint8'>'. Header metadata will be overwritten to use '<class 'numpy.uint8'>'.

Register. Loop across Z (note: there is only one Z if orientation is axial)
Z=0/0:   0%|                                            | 0/5 [00:00<?, ?iter/s]
Traceback (most recent call last):
  File "D:\SCT7\spinalcordtoolbox\scripts\sct_dmri_moco.py", line 216, in <module>
    main(sys.argv[1:])
  File "D:\SCT7\spinalcordtoolbox\scripts\sct_dmri_moco.py", line 201, in main
    fname_output_image = moco_wrapper(param)
  File "D:\SCT7\spinalcordtoolbox\moco.py", line 330, in moco_wrapper
    file_mat_b0, _ = moco(param_moco)
  File "D:\SCT7\spinalcordtoolbox\moco.py", line 610, in moco
    failed_transfo[it] = register(param, file_data_splitZ_splitT[it], file_target_splitZ[iz], file_mat[iz][it],
  File "D:\SCT7\spinalcordtoolbox\moco.py", line 754, in register
    status, output = run_proc(cmd, verbose=1 if param.verbose == 2 else 0, env=env, **kw)
  File "D:\SCT7\spinalcordtoolbox\utils\sys.py", line 334, in run_proc
    raise RuntimeError(output)
RuntimeError: setting mask C:\Users\HORIZO~1\AppData\Local\Temp\sct_2025-08-16_22-49-01_moco-wrapper_il0u8ntg\mask_bin.nii
Exception caught:
itk::ExceptionObject (000000EA63B0DA20)
Location: "unknown"
File: D:\a\build_ANTs\build_ANTs\antsbin\staging\include\ITK-5.1\itkMattesMutualInformationImageToImageMetricv4.hxx
Line: 312
Description: itk::ERROR: MattesMutualInformationImageToImageMetricv4(0000022D6F1425F0): Joint PDF summed to zero
Total runtime; 2.628 seconds.

I would appreciate your assistance or any further solutions to resolve this issue.

Dear @willimon,

The “Joint PDF summed to zero” error typically arises due to either A) poor segmentation or B) poor overlap between volumes during analysis.

Please refer to the following page for past debugging/troubleshooting for this error message:

I would recommend opening the input images in an image viewer such as FSLeyes to verify that everything looks good. If possible, sharing sample data (dmri, mask, bvecs, segmentation) can also help us to identify the problem.

Kind regards,
Joshua

I am happy to share my sample. Here is the segmentation result, and the relevant files have been uploaded.


bvals.bval (251 Bytes)
bvecs.bvec (1.7 KB)
dmri.nii.gz (5.9 MB)
dmri_dwi_mean_seg.nii.gz (1.2 KB)
mask_dmri_dwi_mean.nii.gz (5.5 KB)

Thank you for your response.
I was wondering if the error is caused by the image containing brain tissue, which hasn’t been segmented properly? Is there a solution for this issue?
Additionally, in another case, the image has heavy artifacts, which have led to poor segmentation. Do you have any recommendations for handling this?
Here is the segmentation result from another subject for your reference.


Just to make sure I understand correctly: Does the error occur for all of your subjects? Or, only certain subjects (e.g. ones with poor segmentation)?

I will take a look at the sample data you provided. The QC screenshot looks good, but it is just the QC for the mean segmentation. Given that there are likely dozens of volumes (e.g. 65 as seen in the last screenshot), I am curious if there are issues with other volumes that are not easily displayed in the “mean segmentation” QC report. I’ll try to take a closer look.

Kind regards,
Joshua

Hi Joshua,

I encountered similar problems. Full logs:

(base) linip2@LINIP2:~/lxm/2025/07_als/1analysis/als_P009/dti$ sct_dmri_moco -i dti.nii.gz -m mask_dti_dwi_mean.nii.gz -bvec dti.bvec

--
Spinal Cord Toolbox (7.1.dev0)

sct_dmri_moco -i dti.nii.gz -m mask_dti_dwi_mean.nii.gz -bvec dti.bvec
--


Input parameters:
  Input file ............ dti.nii.gz
  Group size ............ 3
Creating temporary folder (/tmp/sct_2025-09-01_12-15-23_moco-wrapper_mxw_ili_)

Copying input data to tmp folder and convert to nii...
Image header specifies datatype 'int16', but array is of type 'float64'. Header metadata will be overwritten to use 'float64'.

Get dimensions of data...
  144 x 144 x 35

Data orientation: RPI
  Treated as axial

Set suffix of transformation file name, which depends on the orientation:
Orientation is axial, suffix is 'Warp.nii.gz'. The estimated transformation is a 3D warping field, which is composed of a stack of 2D Tx-Ty transformations

Identify b=0 and DWI images...
  WARNING: bvecs file is 3xn instead of nx3. Consider using sct_dmri_transpose_bvecs.
  Transpose bvecs...
  Number of b=0: 1 [0]
  Number of DWI: 10 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Split along T dimension...

Merge and average b=0 data...
Merge within groups: 100%|██████████████████████| 4/4 [00:00<00:00,  5.26iter/s]

Merge across groups...

-------------------------------------------------------------------------------
  Estimating motion on b=0 images...
-------------------------------------------------------------------------------

Input parameters:
  Input file ............ b0.nii
  Reference file ........ data_T0000.nii.gz
  Polynomial degree ..... 2
  Smoothing kernel ...... 1
  Gradient step ......... 1
  Metric ................ MI
  Sampling .............. None
  Todo .................. estimate_and_apply
  Mask  ................. mask.nii
  Output mat folder ..... mat_b0groups

Data dimensions:
  144 x 144 x 35 x 1

Copy file_target to a temporary file...
Image header specifies datatype 'int64', but array is of type '<class 'numpy.uint8'>'. Header metadata will be overwritten to use '<class 'numpy.uint8'>'.

Register. Loop across Z (note: there is only one Z if orientation is axial)
Z=0/0:   0%|                                            | 0/1 [00:00<?, ?iter/s]
Traceback (most recent call last):
  File "/usr/local/sct_v7.0_cuda/spinalcordtoolbox/scripts/sct_dmri_moco.py", line 216, in <module>
    main(sys.argv[1:])
  File "/usr/local/sct_v7.0_cuda/spinalcordtoolbox/scripts/sct_dmri_moco.py", line 201, in main
    fname_output_image = moco_wrapper(param)
  File "/usr/local/sct_v7.0_cuda/spinalcordtoolbox/moco.py", line 330, in moco_wrapper
    file_mat_b0, _ = moco(param_moco)
  File "/usr/local/sct_v7.0_cuda/spinalcordtoolbox/moco.py", line 610, in moco
    failed_transfo[it] = register(param, file_data_splitZ_splitT[it], file_target_splitZ[iz], file_mat[iz][it],
  File "/usr/local/sct_v7.0_cuda/spinalcordtoolbox/moco.py", line 754, in register
    status, output = run_proc(cmd, verbose=1 if param.verbose == 2 else 0, env=env, **kw)
  File "/usr/local/sct_v7.0_cuda/spinalcordtoolbox/utils/sys.py", line 334, in run_proc
    raise RuntimeError(output)
RuntimeError: setting mask /tmp/sct_2025-09-01_12-15-23_moco-wrapper_mxw_ili_/mask_bin.nii
Exception caught:
itk::ExceptionObject (0x347e8340)
Location: "unknown"
File: /__w/build_ANTs/build_ANTs/antsbin/staging/include/ITK-5.1/itkMattesMutualInformationImageToImageMetricv4.hxx
Line: 312
Description: itk::ERROR: MattesMutualInformationImageToImageMetricv4(0x34350f70): Joint PDF summed to zero
Total runtime; 2.361 seconds.

This happens on every subject I’ve tried, not just a few with obviously poor segmentations. I should add that this batch of DTI data is generally lower quality (SNR is not great, with some dropout/ghosting), so I originally suspected “only some” subjects would fail — but the behavior is consistent across the cohort.

If I switch the metric to MeanSquares or CC, the command runs without crashing, but the results before vs. after motion correction look essentially unchanged (both visually and from quick checks), as if the correction had no effect.

Do u have any idea what to do next? Appreciate your guidance!
dti_dwi.nii.gz (8.4 MB)
dti.bval (43 Bytes)
dti.bvec (263 Bytes)
dti.nii.gz (5.1 MB)
mask_dti_dwi_mean.nii.gz (36.5 KB)
dti_dwi_mean_seg.nii.gz (4.4 KB)
dti_dwi_mean.nii.gz (1.5 MB)

Crash when using metric=MI is a known issue:

See various workaround described in the issues listed above

@jcohenadad Hi Prof. Julien,

Thank you for your reply and for pointing me to the related threads.

However, I’m seeing another issue: with MeanSquares/CC the motion-corrected image is almost identical to the original (differences only at the 5th decimal place), and both moco_params_x.nii.gz and moco_params_y.nii.gz are entirely zeros. Do you have a sense of what could lead to identity transforms across all volumes?

Many thanks again for your time!

Best,
Xiaomin