Nipype - ANTs registration, Image registration working but applying transform to mask sometimes failing

Hello, I am using the nipype interface with ANTs to register a number of images to the MNI152_T1 atlas. I then want to apply the transform to masks corresponding to the moving image.

The majority of my cases are working just as expected, however, I have a handful where the image registration is fine but the transformed masks are not. I am visually checking all of them with itk-snap.

I have checked that the metadata of the image and roi are identical. But I have noticed that the cases that fail seem to originally have non-zero quatern values. I do have cases with non-zero quatern values that worked though, so this can’t be the only issue.

Has anyone else seen similar odd behavior or have suggestions for where I should look? I will copy what I believe to be the relevant code below.

This is my first time posting here, so definitely let me know if this question should go somewhere else! =)

Thanks in advance!

120 def register_images(filepaths, atlas_filepath):
121 print(filepaths)
122 for path in filepaths:
123 # Need to change working directory because ANTs saves transforms to working dir
124 os.chdir(path)
125 print(f"Currently in {os.getcwd()}")
126 moving_image_filepath = os.path.join(path, ‘original_T1Gd.nii.gz’)
127 registered_image_filepath = os.path.join(path, ‘registered_T1Gd.nii.gz’)
128 ants_registration(atlas_filepath, moving_image_filepath, registered_image_filepath)
129 ROI_files = [f for f in os.listdir(path) if ‘ROI’ in f]
130 for roi in ROI_files:
131 if ‘merged’ in roi:
132 registered_ROI_filepath = os.path.join(path, ‘registered_merged_ROI.nii.gz’)
133 else:
134
135 ROI_number_search = re.search(‘original_ROI_(. ).nii.gz’, roi, re.IGNORECASE)
136 if ROI_number_search:
137 count = ROI_number_search.group(1)
138 registered_ROI_filepath = os.path.join(path, f’registered_ROI_{count}.nii.gz’)
139 apply_ants_transform(atlas_filepath, os.path.join(path, roi), registered_ROI_filepath, path)
140
141 def ants_registration(base_image_filepath, moving_image_filepath, registered_image_filepath):
142 # base_image and moving_image are Image objects
143 # set base_image_filepath
144 if not os.path.exists(base_image_filepath):
145 raise ValueError(“base_image {base_image_filepath} doesn’t exist!”)
146 if not os.path.exists(moving_image_filepath):
147 raise ValueError(“moving_image {moving_image_filepath} doesn’t exist!”)
148
149 print(“Registering with ANTs…”)
150 reg = Registration()
151 reg.inputs.fixed_image = base_image_filepath
152 reg.inputs.moving_image = moving_image_filepath
153 reg.inputs.output_warped_image = registered_image_filepath
154 reg.inputs.transforms = [‘Rigid’, ‘Affine’, ‘SyN’]
155 reg.inputs.metric = [‘MI’, ‘MI’, [‘MI’, ‘CC’]]
156 reg.inputs.metric_weight = [1] * 2 + [[0.5, 0.5]]
157 reg.inputs.radius_or_number_of_bins = [32, 32, [32, 4]]
158 reg.inputs.convergence_window_size = [5, 5, 5]
159 reg.inputs.sampling_strategy = [‘Regular’] * 2 + [[None, None]]
160 reg.inputs.sampling_percentage = [0.5] * 2 + [[None, None]]
161 reg.inputs.number_of_iterations = ([[5000, 5000, 1000, 500],
162 [5000, 5000, 1000, 500],
163 [100, 90, 75]])
164 reg.inputs.shrink_factors = [[7, 5, 2, 1], [4, 3, 2, 1], [4, 2, 1]]
165 reg.inputs.smoothing_sigmas = [[6, 4, 1, 0], [3, 2, 1, 0], [1, 0.5, 0]]
166 reg.inputs.convergence_threshold = [1.e-6] * 2 + [-0.01]
167 reg.inputs.sigma_units = [‘vox’]
3
168 reg.inputs.transform_parameters = [(0.25,),
169 (0.25,),
170 (0.2, 3.0, 0.0)]
171 reg.inputs.use_estimate_learning_rate_once = [True] * 3
172 reg.inputs.use_histogram_matching = [False, False, True]
173 reg.inputs.verbose = True
174 reg.inputs.num_threads = 10
175 reg.run()
176
177 def apply_ants_transform(reference_image_filepath, moving_measurement, registered_ROI_filepath, path):
178 if not os.path.exists(os.path.join(path, ‘transform1Warp.nii.gz’)):
179 raise ValueError(“Transform parameters not found!”)
180 if not os.path.exists(os.path.join(path, ‘transform0GenericAffine.mat’)):
181 raise ValueError(“Transform parameters not found!”)
182 print(“Applying ANTs transforms…”)
183 at = ApplyTransforms()
184 at.inputs.input_image = moving_measurement
185 at.inputs.reference_image = reference_image_filepath
186 at.inputs.transforms = [os.path.join(path, ‘transform1Warp.nii.gz’),
187 os.path.join(path, ‘transform0GenericAffine.mat’)]
188 at.inputs.interpolation = ‘NearestNeighbor’
189 at.inputs.output_image = registered_ROI_filepath
190 at.run()