Reputation: 1
I have a moved image that I created with simpleITK transforms and registration and I have object's measurements and centroids from the moved image(working as expected)
my transformation/registration:
final_transform1, registration_method1 = img_reg(roi11, mask11, roi21, mask21)
I then resample the images to produce the moved images:
moved_roi21 = sitk.Resample(roi21, roi11, final_transform1, sitk.sitkLinear, 0.0, roi21.GetPixelID())
moved_mask21 = sitk.Resample(mask21, roi11, final_transform1, sitk.sitkNearestNeighbor, 0.0, mask21.GetPixelID())
I do some measuring and get the centroids of those objects:
But then, I'm attempting to take those centroids from the moved image to map the location back to the original image.I need to pinpoint the centroid on the original image. Some of the centroids shift a bit due to the transformation. I tried the GetInverse() Function
Below: the column "Post centroid" is the location of the centroid from the moved image
inverse_transform1 = final_transform1.GetInverse()
stones1["Original Post Centroid"] = stones1["Post centroid"].apply(
lambda centroid: remap_centroid_with_inverse_transform(centroid, inverse_transform1)
)
def remap_centroid_with_inverse_transform(centroid, inverse_transform):
"""
Maps a centroid from the moved space back to the original space using the inverse transform.
Args:
centroid (tuple): The centroid in the moved image space (x, y, z).
inverse_transform (sitk.Transform): The inverse transform from registration.
Returns:
tuple: The remapped centroid in the original image space (x', y', z').
"""
try:
# Ensure the centroid is a tuple
if isinstance(centroid, (list, tuple)) and len(centroid) == 1:
centroid = centroid[0]
# Transform the centroid back to the original space
remapped_centroid = inverse_transform.TransformPoint(centroid)
print(f"Centroid {centroid} remapped to {remapped_centroid} using inverse transform.")
return remapped_centroid
except Exception as e:
print(f"Error remapping centroid {centroid} with inverse transform: {e}")
return None
My hope was this would map the centroid from the moved image(or any centoid in the moved image) to the centroid of the original image before the transform, but the remapping way off.
In case you're wondering what the img_reg function is doing:
def img_reg(fixed_image, fixed_image_mask, moving_image, moving_image_mask):
registration_method = sitk.ImageRegistrationMethod()
# Similarity metric settings.
# cross correlation
registration_method.SetMetricAsANTSNeighborhoodCorrelation(3)
registration_method.SetMetricSamplingStrategy(registration_method.RANDOM)
registration_method.SetMetricSamplingPercentage(0.95)
registration_method.SetMetricFixedMask(fixed_image_mask)
registration_method.SetInterpolator(sitk.sitkLinear)
# Optimizer settings.
registration_method.SetOptimizerAsGradientDescent(learningRate=1.0, numberOfIterations=300, convergenceMinimumValue=1e-6, convergenceWindowSize=10)
registration_method.SetOptimizerScalesFromPhysicalShift()
# Setup for the multi-resolution framework.
registration_method.SetShrinkFactorsPerLevel(shrinkFactors = [3, 2, 1])
registration_method.SetSmoothingSigmasPerLevel(smoothingSigmas= [2, 1, 1])
registration_method.SmoothingSigmasAreSpecifiedInPhysicalUnitsOn()
# Set the initial moving and optimized transforms.
#rigid
fix_mask = sitk.Cast(fixed_image > 1.0e-6, sitk.sitkFloat32) * sitk.Cast(fixed_image_mask > 0, sitk.sitkFloat32)
mov_mask = sitk.Cast(moving_image > 1.0e-6, sitk.sitkFloat32) * sitk.Cast(moving_image_mask > 0, sitk.sitkFloat32)
fix = sitk.Cast(fixed_image, sitk.sitkFloat32) * fix_mask
mov = sitk.Cast(moving_image, sitk.sitkFloat32) * mov_mask
#sitk.WriteImage(fix, 'tfix.nii.gz')
#sitk.WriteImage(mov, 'tmov.nii.gz')
initial_transform = sitk.CenteredTransformInitializer(fix_mask,
mov_mask,
sitk.Euler3DTransform(),
sitk.CenteredTransformInitializerFilter.MOMENTS) #GEOMETRY)
registration_method.SetOptimizerScales([0.2,0.2,0.2,0.5,0,5,0.5])
registration_method.SetInitialTransform(initial_transform, inPlace=True)
final_transform = registration_method.Execute(fix, mov)
# Always check the reason optimization terminated.
print('Final metric value: {0}'.format(registration_method.GetMetricValue()))
print('Optimizer\'s stopping condition, {0}'.format(registration_method.GetOptimizerStopConditionDescription()))
return final_transform, registration_method
Although the code runs:
The output of my debugging print statement
Centroid (-45.859375, 177.4645565257353, -218.10075018504835) remapped to (-37.074328555487725, 176.6125729911438, -323.46181403960696) using inverse transform. However the actual Centroid is or the original centroid is:
(-40.66764664446721, 165.81388511782788, -113.14662579231575)
(-45.859375, 177.4645565257353, -218.10075018504835) is the correct centroid of measurement from the moved image that was transformed from (-40.66764664446721, 165.81388511782788, -113.14662579231575), but was transformed because it was a follow up image.
Upvotes: 0
Views: 24
Reputation: 551
If I followed your code correctly we have the following:
roi11
and roi21
where roi11
is the fixed image and roi21
is the moving image.final_transform1
, maps points from the roi11
physical space to roi21
physical space. roi21
and mask21
are resampled onto the roi11
grid using this transformation, yielding moved_roi21
and moved_mask21
.moved_mask21
or moved_roi21
(make sure these points are in physical space, not image index based, see TransformContinuousIndexToPhysicalPoint).roi21
physical space you need to apply the final_transform
to them. They are defined in the roi11
physical space and you want them in the roi21
physical space.For further discussions relating to SimpleITK please use the ITK discourse which is a dedicated forum for the toolkit.
Upvotes: 1