ITKElastix icon indicating copy to clipboard operation
ITKElastix copied to clipboard

Extremely slow (compared to SimpleITK - Elastix)

Open gattia opened this issue 1 year ago • 8 comments

Hi,

I am trying to use Elastix in python. I went with itk-elastix first as its the most maintained version that can be easily installed. However, it seems to be having some sort of issues. Im using python 3.9 and the example outline and parameter file from: https://github.com/InsightSoftwareConsortium/ITKElastix/blob/main/examples/ITK_Example03_Masked_3D_Registration.ipynb

When I run this code using SimpleElastix (https://pypi.org/project/SimpleITK-SimpleElastix/), I get a registration in ~5seconds. When I do it with itk-elastix it ran overnight and didnt complete. Both were installed in a fresh python 3.9 environment using pip. itk elastix is version 5.4.0 and sitk elastix is 2.0.0. Simple code is below.

I also tried other parameter files (e.g., default rigid in both versions) and it has the same result.

ITK ELASTIX:

path_param_file = 'parameters.3D.NC.affine.ASGD.001.txt'
fixed_image = itk.imread(path_fixed_image, itk.F)
moving_image = itk.imread(path_moving_image, itk.F)

parameter_object = itk.ParameterObject.New()
parameter_object.AddParameterFile(path_param_file)
parameter_object.SetParameter(0, "WriteResultImage", "true")


elastix_object = itk.ElastixRegistrationMethod.New(fixed_image, moving_image)
elastix_object.SetParameterObject(parameter_object)

elastix_object.SetLogToConsole(True)

elastix_object.UpdateLargestPossibleRegion()

result_image = elastix_object.GetOutput()
result_transform_parameters = elastix_object.GetTransformParameterObject()

SITK ELASTIX:

path_param_file = 'parameters.3D.NC.affine.ASGD.001.txt'

fixed_image = sitk.ReadImage(path_fixed_image)
moving_image = sitk.ReadImage(path_moving_image)


selx = sitk.ElastixImageFilter()
selx.SetMovingImage(moving_image)
selx.SetFixedImage(fixed_image)


parameter_map = sitk.ReadParameterFile(path_param_file)
# parameter_map = sitk.GetDefaultParameterMap("rigid")
selx.SetParameterMap(parameter_map)

# Specify the output directory
selx.SetOutputDirectory(out_path)
# Execute registration
selx.Execute()

# Extract Image
registered_image = selx.GetResultImage()

gattia avatar Oct 26 '24 23:10 gattia

What version are you using? I remember some slowdowns happening with some versions, and crashes with others (see #265). Later versions should have taken care of that. Is that right, @thewtex?

dzenanz avatar Oct 28 '24 15:10 dzenanz

itk elastix is version 5.4.0 and sitk elastix is 2.0.0. Both on python 3.9

gattia avatar Oct 28 '24 15:10 gattia

Yes, this is unexpected behavior.

@gattia do you observe the behavior on the referenced example? Or just your own data / code?

thewtex avatar Oct 28 '24 20:10 thewtex

I only tried on my own data - I did briefly try seeing if it was a datatype issue by changing the data type in itk elastix, but that didnt seem to fix it in any way. I can try with the example data and report back.

gattia avatar Oct 28 '24 20:10 gattia

@gattia thanks -- it would be helpful to know if the example notebook also has the same behavior.

thewtex avatar Oct 29 '24 17:10 thewtex

Hello @gattia,

Is this issue reproducible with the latest Python package, itk-elastix 0.22.0?

thewtex avatar Mar 10 '25 17:03 thewtex

Sorry for the long delays here. I tried out the new version, and I got the same results. Then, I tried the example and it worked fine. Then, I tried to dig into what the root cause was. I noticed two differences.

  1. I used the class instead of function based approach.
  2. I set elastix_object.SetLogToConsole(True) (it was False in the example)

Turns out, it's setting log_to_console to True that causes the error - whether in the functional or class-based usage of the registration. And for reference, the SimpleElastix one just prints to console by default - so you see all of the outputs as its registering and it doesnt have the slow down.

Apologies for the delay - I hope this is helpful.

Anthony.

Class-based, log to console, slow/doesnt solve:

path_param_file = 'parameters.3D.NC.affine.ASGD.001.tx'
fixed_image = itk.imread(path_fixed_image, itk.F)
moving_image = itk.imread(path_moving_image, itk.F)

parameter_object = itk.ParameterObject.New()
parameter_object.AddParameterFile(path_param_file)
parameter_object.SetParameter(0, "WriteResultImage", "true")


elastix_object = itk.ElastixRegistrationMethod.New(fixed_image, moving_image)
elastix_object.SetParameterObject(parameter_object)

elastix_object.SetLogToConsole(True)

elastix_object.UpdateLargestPossibleRegion()

result_image = elastix_object.GetOutput()
result_transform_parameters = elastix_object.GetTransformParameterObject()

Function-based, log to console, slow/doesnt solve:

path_param_file = 'parameters.3D.NC.affine.ASGD.001.tx'
fixed_image = itk.imread(path_fixed_image, itk.F)
moving_image = itk.imread(path_moving_image, itk.F)

parameter_object = itk.ParameterObject.New()
parameter_object.AddParameterFile(path_param_file)
parameter_object.SetParameter(0, "WriteResultImage", "true")

# Call registration function
result_image, result_transform_parameters = itk.elastix_registration_method(
    fixed_image, moving_image,
    parameter_object=parameter_object,
    log_to_console=True
)

Class-based, don't log, fast:

path_param_file = 'parameters.3D.NC.affine.ASGD.001.tx'
fixed_image = itk.imread(path_fixed_image, itk.F)
moving_image = itk.imread(path_moving_image, itk.F)

parameter_object = itk.ParameterObject.New()
parameter_object.AddParameterFile(path_param_file)
parameter_object.SetParameter(0, "WriteResultImage", "true")


elastix_object = itk.ElastixRegistrationMethod.New(fixed_image, moving_image)
elastix_object.SetParameterObject(parameter_object)

elastix_object.SetLogToConsole(False)

elastix_object.UpdateLargestPossibleRegion()

result_image = elastix_object.GetOutput()
result_transform_parameters = elastix_object.GetTransformParameterObject()

Function-based, don't log, fast:

path_param_file = 'parameters.3D.NC.affine.ASGD.001.tx'
fixed_image = itk.imread(path_fixed_image, itk.F)
moving_image = itk.imread(path_moving_image, itk.F)

parameter_object = itk.ParameterObject.New()
parameter_object.AddParameterFile(path_param_file)
parameter_object.SetParameter(0, "WriteResultImage", "true")



# Call registration function
result_image, result_transform_parameters = itk.elastix_registration_method(
    fixed_image, moving_image,
    parameter_object=parameter_object,
    log_to_console=False
)

gattia avatar Mar 24 '25 16:03 gattia

@gattia that is very helpful, thank you!

@N-Dekker what do you think?

thewtex avatar Mar 24 '25 19:03 thewtex