How to register a pair of images and their corresponding masks?

Hello everyone.I’m new to simpleitk, and I want to register two images (pre and post surgery) and their corresponding masks. And my code is shown:

def rigid_pre_post(fixed_image_path, moving_image_path, fixed_mask_path, moving_mask_path, out_image_path, out_mask_path):
    # 读取图像
    fixed_image = sitk.ReadImage(fixed_image_path)
    fixed_image = sitk.Cast(fixed_image, sitk.sitkFloat32)
    moving_image = sitk.ReadImage(moving_image_path)
    moving_image = sitk.Cast(moving_image, sitk.sitkFloat32)
    # 读取mask
    fixed_mask = sitk.ReadImage(fixed_mask_path)
    moving_mask = sitk.ReadImage(moving_mask_path)

    # 初始化变换
    transform = sitk.CenteredTransformInitializer(fixed_image, moving_image, sitk.Euler3DTransform(),
    # 设置配准方法
    registration_method = sitk.ImageRegistrationMethod()
    registration_method.SetOptimizerAsGradientDescentLineSearch(learningRate=1.0, numberOfIterations=100,
                                                                convergenceMinimumValue=1e-6, convergenceWindowSize=10)

    # 执行配准
    final_transform = registration_method.Execute(fixed=fixed_image, moving=moving_image)

    # 变换移动图像
    moving_resampled = sitk.Resample(moving_image, fixed_image, final_transform, sitk.sitkLinear, 0.0, moving_image.GetPixelID())
    sitk.WriteImage(moving_resampled, out_image_path)
    # 变换移动mask(使用最近邻插值以保持二值性质)
    moving_mask_resampled = sitk.Resample(moving_mask, fixed_image, final_transform, sitk.sitkNearestNeighbor, 0.0, moving_mask.GetPixelID())
    sitk.WriteImage(moving_mask_resampled, out_mask_path)

In most cases, it works. However, some cases my registered mask is all zero! Can you give me some suggestions? Thank you!

Hello @vectorzwt,

If the moving_mask_resampled is all zeros then likely the registration failed. How does the moving_resampled image look? Likely that isn’t as expected either.

To allow us to help you please share the resulting transformation and reason for optimizer termination?

print(f"Final metric value: {registration_method.GetMetricValue()}")
f"Optimizer's stopping condition, {registration_method.GetOptimizerStopConditionDescription()}"
print(f"Final transformation: {final_transform}")

Most often the registration failure is due to poor initialization. Try resampling the moving image and mask after the transform returned by the CenteredTransformInitializer if the results are far from the fixed image and mask then likely you will need to look at a more robust initialization approach (see this notebook for details).

Finally, minor comment on the code, you can combine the image reading and casting:

fixed_image = sitk.ReadImage(fixed_image_path, sitk.sitkFloat32)
moving_image = sitk.ReadImage(moving_image_path, sitk.sitkFloat32)

Thank you for replying.

I have checked the moving_resampled image, it looks quite normal.

I get the results as below:

Can you give me some advice? Thank you!

Hello @vectorzwt,

The results seem reasonable and the optimizer did some work, 33 iterations, so doesn’t look like early termination due to really bad initialization.

Hard to guess why the moving_mask_resampled is not as expected (the resampling code looks correct and uses nearest neighbor interpolation). Just to be on the safe side, please confirm that the moving_mask had non-zero values after it was read. If the input was as expected, then it is hard to guess what is going on.

Possibly share the anonymized data?

1 Like

I have checked it, and it seems not to be all zero. I can upload the data.
mri nii file
Thank you very much!

Hello @vectorzwt,

From a quick look at the provided data the fixed image and fixed mask don’t seem to occupy the same spatial region. Their size, spacing and direction cosine matrices look similar but the origins are significantly different. Any idea what is causing this?

Oh, I think it causes my problem.I do not change the original data. I will contact the doctor for more information. Thank you very much!