ANTsX/ANTsPy

Encountering the error "RuntimeError: Registration failed with error code 1", when MRA images and T1-weighted images are co-registered with "SyN"

Closed this issue · 11 comments

Hello, everyone,

I’m interested in co-registering the T1 weighted images and MRA images using IXIdataset (http://brain-development.org/ixi-dataset/). I intend to primarily perform analysis with the MRA images, so I am trying to use the MRA as the reference image for the co-registration. After resampling and add-padding, I attempted to co-register using SyN. However, I encountered the error “RuntimeError: Registration failed with error code 1.”

Take case "IXI039-HH-1261" as an example.
IXI039-HH-1261-MRA.nii.gz
IXI039-HH-1261-T1.nii.gz

img_MRA = ants.image_read(input_MRA_path).
img_T1 = ants.image_read(input_T1_path)
ants.plot(img_T1, overlay=img_MRA)

MRA image header ANTsImage (RPI)
Pixel Type : float (float32)
Components : 1
Dimensions : (512, 512, 100)
Spacing : (0.4688, 0.4688, 0.8)
Origin : (-126.4276, 83.1077, -21.5363)
Direction : [ 0.9968 0.0793 0.0106 0.079 -0.9964 0.0321 -0.0131 0.0311 0.9994]

T1w image header ANTsImage (AIL)
Pixel Type : float (float32)
Components : 1
Dimensions : (256, 256, 150)
Spacing : (0.9375, 0.9375, 1.2)
Origin : (99.2376, -120.2171, -120.6638)
Direction : [-0.0776 0.0184 -0.9968 0.9882 -0.1311 -0.0794 0.1322 0.9912 0.008 ]

04c455ff-6f54-48f0-ade0-7aa4a55a115f
The MRA does not cover the whole brain and has a narrower imaging range compared to the T1-weighted image.

First, I performed isotropic resampling.
# Isotropic voxels of 0.5mm
voxel_size = 0.5
img_MRA_resampled = ants.resample_image(img_MRA, (voxel_size, voxel_size, voxel_size),False,4)
img_T1_resampled = ants.resample_image(img_T1, (voxel_size, voxel_size, voxel_size),False,4)

In this state, when using img_MRA_resampled as the reference for co-registering the T1 image, it is possible to perform the co-registration using “SyN.” However, as mentioned earlier, since the MRA image has a narrower range compared to the T1 image, data from the top of the head and brainstem in the T1 image is lost as shown bellow.
3a5b4d28-e732-4288-bab8-d756c3145409

Since I need the whole brain T1 image after co-registration, I decided to add padding to the MRA image.

matrix_size = max(img_MRA_resampled.shape)
img_MRA_resampled = ants.pad_image(img_MRA_resampled, shape=(matrix_size, matrix_size, matrix_size))

MRA image header after resampling and padding ANTsImage (RPI)
Pixel Type : float (float32)
Components : 1
Dimensions : (480, 480, 480)
Spacing : (0.5, 0.5, 0.5)
Origin : (-126.4276, 83.1077, -21.5363)
Direction : [ 0.9968 0.0793 0.0106 0.079 -0.9964 0.0321 -0.0131 0.0311 0.9994]

Then, using resampled and add-padded T1 image and resampled the MRA image, I performed an initial registration using TRSAA transformation, which executed without any issues.

initial_registration = ants.registration( fixed=img_MRA_resampled, moving=img_T1_resampled, type_of_transform='TRSAA', verbose=True )
initial_registered_image = initial_registration['warpedmovout']

The issue arises at the next step. When attempting non-linear registration using SyN, the following error occurs:

final_registration = ants.registration( fixed=img_MRA_resampled, moving=initial_registered_image, type_of_transform='SyN', initial_transform=initial_transform )

in registration(fixed, moving, type_of_transform, initial_transform, outprefix, mask, moving_mask, mask_all_stages, grad_step, flow_sigma, total_sigma, aff_metric, aff_sampling, aff_random_sampling_rate, syn_metric, syn_sampling, reg_iterations, aff_iterations, aff_shrink_factors, aff_smoothing_sigmas, write_composite_transform, random_seed, verbose, multivariate_extras, restrict_transformation, smoothing_in_mm, **kwargs)
1346 reg_exit = libfn(processed_args)
1347 if (reg_exit != 0):
-> 1348 raise RuntimeError(f"Registration failed with error code {reg_exit}")
1349 afffns = glob.glob(outprefix + "" + "[0-9]GenericAffine.mat")
1350 fwarpfns = glob.glob(outprefix + "
" + "[0-9]Warp.nii.gz")
RuntimeError: Registration failed with error code 1

mask = ants.get_mask(img_MRA_resampled)
moving_mask = ants.get_mask(img_T1_resampled)
Using these masks in co-registration made no difference.

The same error occurs when using ‘SyNAggro’ as well.
The co-registration using TRSAA is quite successful, but there is still some misalignment.
Therefore, I want to perform non-linear alignment as well.

Any advice would be greatly appreciated.
Thank you.

This is the repo for ANTs, this issue should be transferred to https://github.com/ANTsX/ANTsPy

final_registration = ants.registration( fixed=img_MRA_resampled, moving=initial_registered_image, type_of_transform='SyN', initial_transform=initial_transform )

Try replacing SyN with SyNOnly and add initial_transform='Identity'. You don't want to re-do the affine part

Actually, I think there's two problems in your initial command.

final_registration = ants.registration( fixed=img_MRA_resampled, moving=initial_registered_image, type_of_transform='SyN', initial_transform=initial_transform )

You're passing the initial_transform, but you're also using initial_registered_image as the moving image. So you're giving the registration a moving image that has already had initial_transform applied, then it's being applied again. The correct thing do do would be

final_registration = ants.registration( fixed=img_MRA_resampled, moving=initial_registered_image, type_of_transform='SyNOnly', initial_transform='Identity')

But you can also do

final_registration = ants.registration( fixed=img_MRA_resampled,  moving=img_T1_resampled, 
type_of_transform='SyNOnly', initial_transform=initial_registration['fwdtransforms'] )

@cookpa

Thank you for your help.

As you mentioned, I wasn't fully clear on the procedure of combining a non-linear transformation as the final registration step after the initial registration (Rigid or TRSAA). However, even after following your suggestion to use "SyNOnly," I encountered the same error.

final_registration = ants.registration( fixed=img_MRA_resampled, moving=initial_registered_image, type_of_transform='SyNOnly', initial_transform='Identity')
or
final_registration = ants.registration( fixed=img_MRA_resampled, moving=img_T1_resampled, type_of_transform='SyNOnly', initial_transform=initial_registration['fwdtransforms'] )

-> 1348 raise RuntimeError(f"Registration failed with error code {reg_exit}")
1349 afffns = glob.glob(outprefix + "" + "[0-9]GenericAffine.mat")
1350 fwarpfns = glob.glob(outprefix + "
" + "[0-9]Warp.nii.gz")

RuntimeError: Registration failed with error code 1

@gdevenyi
Thank you for your suggestion.

If you add verbose=True, does it give more information?

@cookpa

Unfortunately, the error log is the same as before.

=========================
*** Running SyN registration (varianceForUpdateField = 3.0000e+00, varianceForTotalField = 0.0000e+00) ***

XXDIAGNOSTIC,Iteration,metricValue,convergenceValue,ITERATION_TIME_INDEX,SINCE_LAST
1DIAGNOSTIC, 1, -2.069232761860e-01, inf, 1.3341e+00, 1.3341e+00,
1DIAGNOSTIC, 2, -2.104631662369e-01, inf, 1.6698e+00, 3.3565e-01,
1DIAGNOSTIC, 3, -2.135409414768e-01, inf, 2.0126e+00, 3.4281e-01,
1DIAGNOSTIC, 4, -2.159593105316e-01, inf, 2.3583e+00, 3.4574e-01,
1DIAGNOSTIC, 5, -2.178752869368e-01, inf, 2.7043e+00, 3.4592e-01,
1DIAGNOSTIC, 6, -2.192840427160e-01, inf, 3.0550e+00, 3.5075e-01,
1DIAGNOSTIC, 7, -2.203439474106e-01, inf, 3.4087e+00, 3.5366e-01,
1DIAGNOSTIC, 8, -2.207382023335e-01, 5.225569475442e-03, 3.7746e+00, 3.6591e-01,
1DIAGNOSTIC, 9, -2.214111983776e-01, 3.555110655725e-03, 4.1341e+00, 3.5948e-01,
1DIAGNOSTIC, 10, -2.217025458813e-01, 2.354470547289e-03, 4.4869e+00, 3.5281e-01,
1DIAGNOSTIC, 11, -2.219092845917e-01, 1.531834015623e-03, 4.8425e+00, 3.5562e-01,
1DIAGNOSTIC, 12, -2.219463884830e-01, 9.647732949816e-04, 5.1977e+00, 3.5524e-01,
1DIAGNOSTIC, 13, -2.219606339931e-01, 5.888302111998e-04, 5.5536e+00, 3.5590e-01,
1DIAGNOSTIC, 14, -2.220667898655e-01, 3.566694213077e-04, 5.9200e+00, 3.6640e-01,
1DIAGNOSTIC, 15, -2.219611108303e-01, 2.080217527691e-04, 6.2853e+00, 3.6528e-01,
1DIAGNOSTIC, 16, -2.217740416527e-01, 6.959090387681e-05, 6.6492e+00, 3.6386e-01,
1DIAGNOSTIC, 17, -2.216869294643e-01, -6.804820259276e-06, 7.0094e+00, 3.6027e-01,
Exception caught:
itk::InvalidRequestedRegionError (0x12182e8f0)
Location: "unknown"
File: /Users/admin/actions-runner/_work/ANTsPy/ANTsPy/itksource/Modules/Core/Common/src/itkDataObject.cxx
Line: 367
Description: Requested region is (at least partially) outside the largest possible region.

That suggests the registration has gone severely off track. Registering a slab to a whole brain is difficult with nonlinear deformation. Unfortunately the python registration interface does not expose all regularization options, but you can try doing fewer iterations by setting something like reg_iterations=(10), this will limit the amount of deformation.

You can also restrict deformation along a particular axis with the restrict_transformation option, if the expected deformations are along a particular axis (eg, the phase encoding axis).

I have had good success with slab-to-wholebrain registration with the following steps:

  1. Skullstirp both
  2. Rigid align slab to wholebrain
  3. Add a mask to slab and refine with affine registration
  4. Continue registration with slab mask and SyN

I've done all this with classic ants so I can't recommend commands for antspy

Clarification: for the slab mask I mean simply an otsu foreground/background ROI type mask or brain mask

That's a good idea. Even a crude mask (eg, including all the MRA FOV, but excluding the added padding slices, which should all be zero) would be helpful.

@cookpa
@gdevenyi

I'm sorry for the delay in my response.

I've tried various methods, but it seems that @gdevenyi's suggested approach is indeed the best.

Using add_pad causes issues with ANTs registration. So far, I've been segmenting images after registration, but now I'm starting to think it might be better to segment directly from the original image, then apply registration and transform the segmented binary image using transform information with nearest neighbor. This way, I feel I can avoid artifacts introduced by resampling or registration.

Thank you very much in any case.