Continuing the discussion from 3D image registration with Python and without SimpleITK:
Hello!
Instead of the translation registration, I am now trying a registration with a versor. How can I do that? This is my code (MWE):
# Copyright 2022 edgar
# License:
#
# This program is free software: you can redistribute it
# and/or modify it under the terms of the GNU General
# Public License as published by the Free Software
# Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General
# Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# Copyright Insight Software Consortium
#
# Licensed under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0.txt
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import sys
import itk
import numpy as np
from distutils.version import StrictVersion as VS
# from benchmark3d.primitives import displ_series_obj3d
from skimage.morphology import disk
from scipy.ndimage import shift
# Draw a 3D disk
side_size = 10
obj2d = disk(side_size / 2, dtype=np.uint8)
obj3d = np.asarray([disk(side_size / 2, dtype=np.uint8)
for idx in range(5)])
# Create 4 frames
series_length = 4
holder = np.asarray([obj3d for idx in range(series_length)])
# Move the last frame
holder[-1] = shift(holder[-1],
(series_length - 1, 0, 0))
# Set the right data type
pixel_type = itk.ctype("float")
dimension = 3
image_type = itk.Image[pixel_type, dimension]
# Load first and last frames as ITK data (images);
# swap axes ITK: i, j, k, Numpy: k, i, j
# (https://discourse.itk.org/t/
# importing-image-from-array-and-axis-reorder/1192/)
fixed_image_arr = holder[0].transpose((2, 1, 0))
moving_image_arr = holder[-1].transpose((2, 1, 0))
fixed_image = itk.image_from_array(
fixed_image_arr.astype(np.float32))
moving_image = itk.image_from_array(
moving_image_arr.astype(np.float32))
dimension = fixed_image.GetImageDimension()
# fixed_image_type = itk.Image[pixel_type, dimension]
# moving_image_type = itk.Image[pixel_type, dimension]
fixed_image_type = type(fixed_image)
moving_image_type = type(moving_image)
versor_transform = itk.VersorTransform[itk.D]
initial_transform = versor_transform.New()
versor_optimizer = itk.VersorTransformOptimizer.New(
# # Not for this optimiser
# LearningRate=4,
MinimumStepLength=0.001,
RelaxationFactor=0.5,
NumberOfIterations=200)
mse_img2img_metric = itk.MeanSquaresImageToImageMetricv4
mse_metric = mse_img2img_metric[fixed_image_type,
moving_image_type].New()
registration_method = itk.ImageRegistrationMethodv4[
fixed_image_type, moving_image_type]
registration = registration_method.New(
FixedImage=fixed_image,
MovingImage=moving_image,
Metric=mse_metric,
Optimizer=versor_optimizer,
InitialTransform=initial_transform)
moving_initial_transform = versor_transform.New()
initial_parameters = moving_initial_transform.GetParameters()
, but I get this error:
File "/usr/lib/python3.10/itk/itkImageRegistrationMethodv4Python.py", line 363, in New
template_class.New(obj, *args, **kargs)
File "/usr/lib/python3.10/itk/support/template_class.py", line 800, in New
itk.set_inputs(self, args, kargs)
File "/usr/lib/python3.10/itk/support/extras.py", line 1252, in set_inputs
attrib(itk.output(value))
TypeError: in method 'itkImageRegistrationMethodv4REGv4F3F3_SetOptimizer', argument 2 of type 'itkObjectToObjectOptimizerBaseTemplateD *'
If I try with double
:
# Copyright 2022 edgar
# License:
#
# This program is free software: you can redistribute it
# and/or modify it under the terms of the GNU General
# Public License as published by the Free Software
# Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General
# Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# Copyright Insight Software Consortium
#
# Licensed under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0.txt
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
pixel_type = itk.ctype("double")
dimension = 3
image_type = itk.Image[pixel_type, dimension]
# Load first and last frames as ITK data (images);
# swap axes ITK: i, j, k, Numpy: k, i, j
# (https://discourse.itk.org/t/
# importing-image-from-array-and-axis-reorder/1192/)
fixed_image_arr = holder[0].transpose((2, 1, 0))
moving_image_arr = holder[-1].transpose((2, 1, 0))
fixed_image = itk.image_from_array(
fixed_image_arr.astype(np.double))
moving_image = itk.image_from_array(
moving_image_arr.astype(np.double))
dimension = fixed_image.GetImageDimension()
# fixed_image_type = itk.Image[pixel_type, dimension]
# moving_image_type = itk.Image[pixel_type, dimension]
fixed_image_type = type(fixed_image)
moving_image_type = type(moving_image)
versor_transform = itk.VersorTransform[itk.D]
initial_transform = versor_transform.New()
versor_optimizer = itk.VersorTransformOptimizer.New(
# # Not for this optimiser
# LearningRate=4,
MinimumStepLength=0.001,
RelaxationFactor=0.5,
NumberOfIterations=200)
mse_img2img_metric = itk.MeanSquaresImageToImageMetricv4
mse_metric = mse_img2img_metric[fixed_image_type,
moving_image_type].New()
registration_method = itk.ImageRegistrationMethodv4[
fixed_image_type, moving_image_type]
registration = registration_method.New(
FixedImage=fixed_image,
MovingImage=moving_image,
Metric=mse_metric,
Optimizer=versor_optimizer,
InitialTransform=initial_transform)
moving_initial_transform = versor_transform.New()
initial_parameters = moving_initial_transform.GetParameters()
I get this
Traceback (most recent call last):
File "/usr/lib/python3.10/itk/support/template_class.py", line 525, in __getitem__
this_item = self.__template__[key]
KeyError: (<class 'itk.itkImagePython.itkImageD3'>, <class 'itk.itkImagePython.itkImageD3'>)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<string>", line 17, in __PYTHON_EL_eval
File "<string>", line 1, in <module>
File "/usr/lib/python3.10/itk/support/template_class.py", line 529, in __getitem__
raise itk.TemplateTypeError(self, key)
itk.support.extras.TemplateTypeError: itk.MeanSquaresImageToImageMetricv4 is not wrapped for input type `itk.Image[itk.D,3], itk.Image[itk.D,3]`.
To limit the size of the package, only a limited number of
types are available in ITK Python. To print the supported
types, run the following command in your python environment:
itk.MeanSquaresImageToImageMetricv4.GetTypes()
Possible solutions:
,* If you are an application user:
,** Convert your input image into a supported format (see below).
,** Contact developer to report the issue.
,* If you are an application developer, force input images to be
loaded in a supported pixel type.
e.g.: instance = itk.MeanSquaresImageToImageMetricv4[itk.Image[itk.F,2], itk.Image[itk.F,2]].New(my_input)
,* (Advanced) If you are an application developer, build ITK Python yourself and
turned to `ON` the corresponding CMake option to wrap the pixel type or image
dimension you need. When configuring ITK with CMake, you can set
`ITK_WRAP_${type}` (replace ${type} with appropriate pixel type such as
`double`). If you need to support images with 4 or 5 dimensions, you can add
these dimensions to the list of dimensions in the CMake variable
`ITK_WRAP_IMAGE_DIMS`.
Supported input types:
itk.Image[itk.F,2]
itk.Image[itk.F,3]
I can compile again with -DITK_WRAP_double:BOOL=ON
, but may be float32 is a bit less memory expensive. How can a registration be run with versors and np.float32
? Thanks!