# Porting https://itk.org/Wiki/ITK/Examples/Metrics/MeanSquaresImageToImageMetric from C++ to Python

#1

Hi all, this is my first question here, I hope I understood the rules.

I have been using itk (C++ version) for many years now, so I am quite familiar with it. Recently I have been exploring the possibility to use it also in Python. So far with not a lot of luck. Here is an specific question but any link to itk or simple itk resources only will be most appreciated (so far I have found quite a few tutorials but after reading those I feel I do not yet understand the way itk works in Python).

The example:

I want to port the code from this example:

https://itk.org/Wiki/ITK/Examples/Metrics/MeanSquaresImageToImageMetric

to Python. As you will see, I am using both itk and simpleitk (I am not sure that is a good idea actually).

So far I have tried this:

``````import SimpleITK as sitk
import itk

def computeMetrics(nameFixed,nameMoving):

pixelType = sitk.sitkFloat32

fixedImage = sitk.ReadImage(nameFixed, pixelType)

movingImage = sitk.ReadImage(nameMoving, pixelType)

metric=itk.MeanSquaresImageToImageMetric()
interpolator=itk.LinearInterpolateImageFunction()
transform=itk.TranslationTransform()

interpolator.SetInputImage( fixedImage )

metric.SetFixedImage( fixedImage )
metric.SetMovingImage( movingImage )
metric.SetFixedImageRegion( fixedImage.GetLargestPossibleRegion() )
metric.SetTransform( transform )
metric.SetInterpolator( interpolator )
``````

However, whenever I try to set the input images for the metric (both fixed and moving) I get the following error:

Traceback (most recent call last):
File “./computeImageMetric.py”, line 67, in
computeMetrics(sys.argv,sys.argv)
File “./computeImageMetric.py”, line 26, in computeMetrics
interpolator.SetInputImage( fixedImage )
TypeError: in method ‘itkImageFunctionISS2DD_SetInputImage’, argument 2 of type ‘itkImageSS2 const *’
I do not understand the error and am also having a hard time finding documentation (in python) for the classes involved. Any help will be most appreciated.

(Dženan Zukić) #2

The short answer is: you cannot mix ITK and SimpleITK like that. `metric` expects and `ITKImage`, and SimpleITK image is similar but different class. I guess you will have to pick either ITK or SimpleITK.

@blowekamp @zivy Correct me if I am wrong.

#3

Thanks a lot for the answer.

I did worry a little bit about that and tried loading the images with itk (and not simple itk), for the following code:

def computeMetrics(nameFixed,nameMoving):

``````    pixelType = sitk.sitkFloat32

#fixedImage = sitk.ReadImage(nameFixed, pixelType)

#movingImage = sitk.ReadImage(nameMoving, pixelType)

metric=itk.MeanSquaresImageToImageMetric()
interpolator=itk.LinearInterpolateImageFunction()
transform=itk.TranslationTransform()

interpolator.SetInputImage( fixedImage )

metric.SetFixedImage( fixedImage )
metric.SetMovingImage( movingImage )
metric.SetFixedImageRegion( fixedImage.GetLargestPossibleRegion() )
metric.SetTransform( transform )
metric.SetInterpolator( interpolator )
``````

The error seems to persist, though

Traceback (most recent call last):
File “./computeImageMetric.py”, line 68, in
computeMetrics(sys.argv,sys.argv)
File “./computeImageMetric.py”, line 27, in computeMetrics
interpolator.SetInputImage( fixedImage )
TypeError: in method ‘itkImageFunctionISS2DD_SetInputImage’, argument 2 of type ‘itkImageSS2 const *’

Hello,

You may find this SimpleITK Example useful: https://simpleitk.readthedocs.io/en/master/Examples/ImageRegistrationMethodExhaustive/Documentation.html

It utilizes an exhaustive optimizer to evaluate the metric on a grid pattern. Additionally, you may be interested in the sitk::ImageRegistrationMethod::MetricEvaluate method.

(Ziv Yaniv) #5

Hello @nicill,

I wouldn’t recommend mixing and matching ITK and SimpleITK, but it should be easy to do via their numpy array import export facilities:

``````import SimpleITK as sitk
import itk

in_file_name = 'my_image.jpg'

def itk2sitk(img):
return sitk.GetImageFromArray(itk.GetArrayViewFromImage(img), img.GetNumberOfComponentsPerPixel()>1)

def sitk2itk(img):
return itk.GetImageFromArray(sitk.GetArrayViewFromImage(img), img.GetNumberOfComponentsPerPixel()>1)

# start with ITK, do some SimpleITK stuff, go back to ITK
img_sitk = sitk.Median(itk2sitk(img_itk))
itk.imwrite(sitk2itk(img_sitk), 'itk2sitk2itk.jpg')

# start with SimpleITK, do some ITK stuff, go back to SimpleITK
median_filter = itk.MedianImageFilter.New(sitk2itk(img_sitk))
median_filter.Update()
img_itk = median_filter.GetOutput()
sitk.WriteImage(itk2sitk(img_itk), 'sitk2itk2sitk.jpg')
``````

This code works for grayscale images, but I believe I uncovered a bug in ITK Python with respect to vector images. So, if nothing else, you have helped improve the toolkits.

(Jon Haitz Legarreta Gorroño) #6

As a side note, porting the example to Python and contributing to the ITK and/or SimpleITK Examples would be a great contribution:
https://itk.org/ITKExamples/Documentation/Contribute/index.html

Both toolkits are built in a large part thanks to the great contributions from the community. And this would definitely be such one .

#7

Thanks for your answer, it helped a lot.

I am not sure that is what you meant but your post made me think of computing the metric by setting up a registration scenario and then getting the metric (with the sitk::ImageRegistrationMethod::MetricEvaluate method that you mention by calling it before the registration is executed.

It looks like this:

``````def computeMetric(fixed,moving,mode):

# First, set up "phony" registration
R = sitk.ImageRegistrationMethod()
R.SetInitialTransform(sitk.Transform(2,sitk.sitkIdentity)) # Transformation deliberately not using any initializer
R.SetInterpolator(sitk.sitkLinear)

#second, choose metric
if(mode==0): R.SetMetricAsJointHistogramMutualInformation()
elif(mode==1): R.SetMetricAsMattesMutualInformation(numberOfHistogramBins = 50)
elif(mode==2): R.SetMetricAsMeanSquares()
elif(mode==3): R.SetMetricAsCorrelation()
else:
print("Error in computeMetric, unrecognized metric")
sys.exit ( 1 )

#third, get the metric value
print(R.MetricEvaluate(fixed, moving))
``````

I have been testing a few things (metric with same image, when the image order changes, after some registration methods) and I am getting some weird values from the mutual information metrics (modes 0 and 1) but least squares and correlation seem to work fine.

#8

Thanks for the tip about working with itk and simpleItk, at this moment I can do all I need to do with only simpleItk but I will definetely keep it mind.
{"ft_lang_label":"__label__en","ft_lang_prob":0.73484915,"math_prob":0.62146354,"size":1940,"snap":"2019-13-2019-22","text_gpt3_token_len":470,"char_repetition_ratio":0.12396694,"word_repetition_ratio":0.0,"special_character_ratio":0.20360824,"punctuation_ratio":0.15522388,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9501995,"pos_list":[0,1,2,3,4],"im_url_duplicate_count":[null,null,null,2,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2019-03-19T05:30:40Z\",\"WARC-Record-ID\":\"<urn:uuid:f59baf55-d193-4885-bd4a-0a43b531c0a5>\",\"Content-Length\":\"22657\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:59e63298-7e4b-48b3-b5d1-fed1f1f51684>\",\"WARC-Concurrent-To\":\"<urn:uuid:7f2d4d72-4b4e-479e-ab3c-6f808ee226eb>\",\"WARC-IP-Address\":\"50.58.123.179\",\"WARC-Target-URI\":\"https://discourse.itk.org/t/porting-https-itk-org-wiki-itk-examples-metrics-meansquaresimagetoimagemetric-from-c-to-python/1670\",\"WARC-Payload-Digest\":\"sha1:7JKF2UCEQYFKQALR6MRO6NHQN2KQM2DC\",\"WARC-Block-Digest\":\"sha1:GLTRUBK622HPD7BJGDB5UEIOCAH3IPOS\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2019/CC-MAIN-2019-13/CC-MAIN-2019-13_segments_1552912201904.55_warc_CC-MAIN-20190319052517-20190319074517-00500.warc.gz\"}"}