Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error loading initial transform and applying mask #274

Open
Sermoor opened this issue Mar 6, 2024 · 0 comments
Open

Error loading initial transform and applying mask #274

Sermoor opened this issue Mar 6, 2024 · 0 comments

Comments

@Sermoor
Copy link

Sermoor commented Mar 6, 2024

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

mrAffine1.txt
mrAffine2.txt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant