You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Context
I'm aiming to perform affine registration on 3D MRI data to align it with a template. My approach involves initially conducting an affine registration using the entire volume, followed by a finer registration using a mask of the reference. Additionally, I aim to use the initial affine registration as a starting point to avoid starting from scratch.
Implementation
I've followed notebook tutorials 3 and 4, but haven't achieved success. I suspect the issue lies in the use of the initial transform by the second registration call. In the second affine registration, the CenterOfRotationPoint and Translation coordinates shouldn't vary excessively from the first registration since it's a refinement process. However, the change is substantial, making it impossible to perform the inverse using the second affine coordinates as the resulting volume is misaligned. I've experimented with both 'Compose' and 'Add' for the 'HowToCombineTransforms' parameter. Interestingly, 'Add' seems to maintain a similar CenterOfRotationPoint but with minor changes in Translation coordinates [see attached files for Affine1 and Affine2]. This leads me to believe these coordinates are relative to the first transform, although I haven't found any documentation explaining this aspect.
I would greatly appreciate any assistance, whether it pertains to the code or the underlying concept.
def ITK(ima , ref, if_mask, mask_name):
# Load vols
mask_img = nii.load(mask_name)
mask = np.asanyarray(mask_img.dataobj)
moving_image = itk.imread(ima, itk.F)
fixed_image = itk.imread(ref, itk.F)
# Import Default Parameter Map
parameter_object = itk.ParameterObject.New()
affine_parameter_map = parameter_object.GetDefaultParameterMap('affine', 4)
# Initial aligment of volumes
affine_parameter_map['AutomaticTransformInitialization'] = ['true']
# Perform center of mass initialization for the affine transformation
affine_parameter_map['AutomaticTransformInitializationMethod'] = ['CenterOfGravity']
# // Order of B-Spline interpolation used during registration/optimisation.
# // It may improve accuracy if you set this to 3. Never use 0.
# // An order of 1 gives linear interpolation. This is in most
# // applications a good choice.
# Read for more detail: https://github.com/SuperElastix/ElastixModelZoo/blob/master/models/default/Parameters_Affine.txt
affine_parameter_map['FinalBSplineInterpolationOrder'] = ['3']
affine_parameter_map['BSplineInterpolationOrder'] = ['1']
parameter_object.AddParameterMap(affine_parameter_map)
#Call registration function
#by default uses metric: AdvancedMattesMutualInformation (MI)
result_image, result_transform_parameters = itk.elastix_registration_method(fixed_image,
moving_image,
parameter_object=parameter_object,
number_of_threads=8,
log_to_console=True
)
# Save the affine transform parameters in a txt file -> specific method
if os.path.basename(ima).endswith(".gz"):
affine_filename = os.path.basename(ima[0:-7])+"Affine1.txt"
else:
affine_filename = os.path.basename(ima[0:-4])+"Affine1.txt"
for index in range(result_transform_parameters.GetNumberOfParameterMaps()):
parameter_map = result_transform_parameters.GetParameterMap(index)
result_transform_parameters.WriteParameterFile(
parameter_map,
affine_filename)
if if_mask:
del parameter_map, parameter_object, affine_parameter_map
# Import Default Parameter Map
parameter_object = itk.ParameterObject.New()
affine_parameter_map = parameter_object.GetDefaultParameterMap('affine') # type of registration and number of resolutions
#affine_parameter_map['AutomaticScalesEstimation'] = ['false']
#affine_parameter_map['AutomaticTransformInitialization'] = ['true']
#affine_parameter_map['AutomaticTransformInitializationMethod'] = ['CenterOfGravity']
# // Order of B-Spline interpolation used during registration/optimisation.
# // It may improve accuracy if you set this to 3. Never use 0.
# // An order of 1 gives linear interpolation. This is in most
# // applications a good choice.
# Read for more detail: https://github.com/SuperElastix/ElastixModelZoo/blob/master/models/default/Parameters_Affine.txt
#affine_parameter_map['ErodeMask'] = ['false']
affine_parameter_map['HowToCombineTransforms'] = ['Add']
affine_parameter_map['FinalBSplineInterpolationOrder'] = ['3']
affine_parameter_map['BSplineInterpolationOrder'] = ['1']
parameter_object.AddParameterMap(affine_parameter_map)
# Use the mask to fine register the image, but loading the previous affine to not start from the beginning -> Not worki
try:
mask = mask.astype(np.uint8)
mask_img = itk.image_view_from_array(mask) # itk.UC is = np.uint8
except Exception as e:
print("Error loading mask:", str(e))
sys.exit(1)
print(f"Using affine file {affine_filename}")
# how to used mask in fixed image:
# https://github.com/InsightSoftwareConsortium/ITKElastix/blob/main/examples/ITK_Example04_InitialTransformAndMultiThreading.ipynb
# https://github.com/InsightSoftwareConsortium/ITKElastix/blob/main/examples/ITK_Example03_Masked_3D_Registration.ipynb
result_image, result_transform_parameters = itk.elastix_registration_method(fixed_image, moving_image,
initial_transform_parameter_file_name=affine_filename,
parameter_object=parameter_object, # same configuration as before
fixed_mask = mask_img,
number_of_threads=8,
log_to_console=True)
if os.path.basename(ima).endswith(".gz"):
affine_filename = os.path.basename(ima[0:-7])+"Affine2.txt"
else:
affine_filename = os.path.basename(ima[0:-4])+"Affine2.txt"
for index in range(result_transform_parameters.GetNumberOfParameterMaps()):
parameter_map = result_transform_parameters.GetParameterMap(index)
result_transform_parameters.WriteParameterFile(
parameter_map,
affine_filename)
return affine_filename
Context
I'm aiming to perform affine registration on 3D MRI data to align it with a template. My approach involves initially conducting an affine registration using the entire volume, followed by a finer registration using a mask of the reference. Additionally, I aim to use the initial affine registration as a starting point to avoid starting from scratch.
Implementation
I've followed notebook tutorials 3 and 4, but haven't achieved success. I suspect the issue lies in the use of the initial transform by the second registration call. In the second affine registration, the CenterOfRotationPoint and Translation coordinates shouldn't vary excessively from the first registration since it's a refinement process. However, the change is substantial, making it impossible to perform the inverse using the second affine coordinates as the resulting volume is misaligned. I've experimented with both 'Compose' and 'Add' for the 'HowToCombineTransforms' parameter. Interestingly, 'Add' seems to maintain a similar CenterOfRotationPoint but with minor changes in Translation coordinates [see attached files for Affine1 and Affine2]. This leads me to believe these coordinates are relative to the first transform, although I haven't found any documentation explaining this aspect.
I would greatly appreciate any assistance, whether it pertains to the code or the underlying concept.
mrAffine1.txt
mrAffine2.txt
The text was updated successfully, but these errors were encountered: