Installing and using Python wrapped Remote Module

Hi all,

I tried to build ITK Strain Image Filter https://github.com/KitwareMedical/ITKStrain and to install it.
I used a conda virtual env with Python 3.6 and ITK 5.0.0.post1 from pypy in the environment, a self-build local ITK 5.0.1 and skbuild using Win 10 x64.
I did “python setup.py install” and it finished without errors. Actually if I “conda list” in the env, there is a package called itk-strain 0.1.0. But I did not manage to import the module to python.
I tried:
“from itk import StrainImageFilter” --> module ‘itk’ has no attribute ‘StrainImageFilter’
“import itk-strain” --> syntax-error
“import itk_strain” --> no module itk_strain
Actually, I am not aware how the module is finally named.
I did not finde a module in “help(‘modules’)”, neither did I find a submodule in “dir(‘itk’)”

Is there a specific way to find the correct naming convention of a remote module, wrapped for python? Do I need change something in cmake to enable Python wrapping before I build ITK on my System?

I appreciate any answers and hints.

Kind Regards

I tried building ITK with wrapping enabled again and I put WrapITK.pth in sitepackages of a the conda-env I am using, added a path variable to build\lib\release and build\bin\release (Now, I do feel a little bit stupid for posting the question above, though :slight_smile: ) and now I can import StrainPython and have StrainPython.itkStrainImageFilterIVD22DD available. But I ran in the next issue. GetImageFromArray from ITKExtras does not work anymore as it did in ITK from PyPy…

In [19]: deformationField = itk.GetImageFromArray(test.astype(‘float32’), is_vector=True)

AttributeError Traceback (most recent call last)
in
----> 1 deformationField = itk.GetImageFromArray(test.astype(‘float32’), is_vector=True)

C:\build\Wrapping\Generators\Python\Release\itkExtras.py in GetImageFromArray(arr, is_vector)
295 “”“Get an ITK image from a Python array.
296 “””
→ 297 return _GetImageFromArray(arr, “GetImageFromArray”, is_vector)
298
299 image_from_array = GetImageFromArray

C:\build\Wrapping\Generators\Python\Release\itkExtras.py in _GetImageFromArray(arr, function, is_vector)
272 raise ImportError(‘Numpy not available.’)
273 import itk
→ 274 PixelType = _get_itk_pixelid(arr)
275 if is_vector:
276 Dimension = arr.ndim - 1

C:\build\Wrapping\Generators\Python\Release\itkExtras.py in _get_itk_pixelid(numpy_array_type)
225 numpy.float32:itk.F,
226 numpy.float64:itk.D,
→ 227 numpy.complex64:itk.complex[itk.F],
228 numpy.complex128:itk.complex[itk.D]
229 }

C:\build\Wrapping\Generators\Python\Release\itkLazy.py in getattribute(self, attr)
44 module = self.__belong_lazy_attributes[attr]
45 namespace = {}
—> 46 itkBase.LoadModule(module, namespace)
47 for k, v in namespace.items():
48 setattr(self, k, v)

C:\build\Wrapping\Generators\Python\Release\itkBase.py in LoadModule(name, namespace)
61 else:
62 swig = namespace.setdefault(‘swig’, imp.new_module(‘swig’))
—> 63 swig.dict.update(this_module.swig.dict)
64
65 # don’t worry about overwriting the symbols in namespace – any

AttributeError: module ‘ITKCommon’ has no attribute ‘swig’

Any suggestions? I am definitly missing somethin, sorry.

Okay, i tried back and forth, even rebuild itk with python wrapping. And I experienced a rather strange behavior, I cannot explain.
It depends on the order, how itk, and for example StrainPython (applies also to other modules) is imported and what happens inbetween.
I did:

import itk
itk.Image # for testing
#… (some other stuff)
import StrainPython

And everything works fine.

But if i do nothing inbetween the imports and use any itk function/class the problem in the post above is raised:

“UnboundLocalError: local variable ‘module’ referenced before assignment”
in ITKBase.py

To all who might have similar problems:
Try executing any itk class like itk.Image between your imports. This seems to solve the

“AttributeError: module ‘ITKCommon’ has no attribute ‘swig’”
and
“UnboundLocalError: local variable ‘module’ referenced before assignment”

errors, even though I do not understand why.

Perhaps lazy loading has something to do with it? @matt.mccormick

Welcome to the ITK community @laqua-stack!

First, well done building the Python package. :clap:

To make it easier, I have uploaded binary itk-strain Python packages to PyPI. Please try installing it in a new conda virtual environment with:

pip install itk-strain

Is there a specific way to find the correct naming convention of a remote module, wrapped for python?

To find out the content of the package, we can do the following:

from itk import Strain
dir(Strain)

which results in:

['ImageToImageFilter',
 'StrainImageFilter',
 '_LazyITKModule__belong_lazy_attributes',
 '__doc__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 'image_to_image_filter',
 'lazy_attributes',
 'loaded_lazy_modules',
 'strain_image_filter']

We know that the module is named Strain by the argument to itk_wrap_module.

StrainImageFilter is the ITK class that can be used for streaming pipelines.

strain_image_filter provides a functional, Pythonic interface to the filter.

Any suggestions? I am definitly missing somethin, sorry.

You are doing excellent :slight_smile: – I think there is a bug in the wrapping that causes the confusing error. I will follow-up…

1 Like

Thanks for all the nice words and the help :blush:.
itk-strain on pypy? Awesome!!! Thank you so much.
I will definitly try this. Is there a concern if a wrapped ITK is already build on the computer? Do i just need to rename WrapITK.pth to .bak in site-packages to make the custom build not interfere with it?

I think it was (ofcourse :-)) a mistake to import StrainPython module in addition to itk, since itk.StrainImageFilter is already there after importing itk. Now I imported itk only. That way it is also possible to use the Filter without specifying the used type like I did before in StrainPython.itkStrainImageFilterIVD22DD.New().

I think the errors I reported came from importing ITK modules (like StrainPython) in addtion to itk.

Again thank you so much.

Yes, that will work. A new conda env or virtualenv will work, too.

Yes, either approach can work. from itk import Strain can be helpful to just inspect the contents of the Strain module. In most use cases,

import itk
displacement = itk.imread('mydisplacement.mha')
strain = itk.strain_image_filter(displacement)

etc., is convenient.

1 Like

Thanks Matt and Dzenan!
I got it working now :smile:
You will get an update regarding pip’s itk-strain today or tomorrow.

1 Like

I tested pip install itk-strain in an conda env, without errors.
However, I am struggling with compatibility between numpy and PyPI’s itk:

import itk
import numpy as np

#VectorType=itk.Vector[itk.D,2]
VectorType=itk.Vector[itk.F,2]
VectorImageType=itk.Image[VectorType,2]
SSRTType=itk.Image[itk.SymmetricSecondRankTensor[itk.D,2],2]

nparr=np.ascontiguousarray(np.moveaxis(np.indices((256,256),dtype=‘float32’),0,-1))
#DisplacementField=itk.GetImageFromArray(nparr,is_vector=True)
DisplacementField=itk.PyBuffer[VectorImageType].GetImageFromArray(nparr,is_vector=True)

testFilter= itk.StrainImageFilter[VectorImageType].New(DisplacementField)
testFilter.SetInput(DisplacementField)
testFilter.SetStrainForm(testFilter.GREENLAGRANGIAN)
testFilter.Update()
StrainTensorField=itk.PyBuffer[SSRTType].GetArrayFromImage(testFilter.GetOutput())

Only itk.ImageVF22 is supported by PyBuffer in this build and
StrainImageFilter expects itk.ImageVD22 as input.
And VectorCastImageFilter is not available in the PyPI’s itk build.

But I think if I had Images to read in with ITK’s functionality without the Numpy Bridge, it would work fine :wink:

For me it works fine with my self-build ITK.
Would it be possible(/not too much work) to wrap VectorCastImageFilter or rewrap PyBuffer for ‘double’ with VectorImage? I did not test ImageAdaptor yet.

Would it be possible(/not too much work) to wrap VectorCastImageFilter or rewrap PyBuffer for ‘double’ with VectorImage?

Yes, good idea! In ITK 5, we can just use CastImageFilter instead of VectorCastImageFilter. I created these issues to track this:

In the meantime, a possible workaround is to write / read from file.

Also, a new version of the itk-strain package has been uploaded to PyPI; upgrade with:

pip install --upgrade itk-strain

Thank you Matt. I appreciate the new itk-strain version.
Unfortunately I experienced a new problem with the self-build ITK. Since it is closely related to the one I described above, I reply it just here.
When I use the self-build itk in Python 3.6 conda env, everything works fine.
But if I attempt to use the same build in Python 3.7 with WrapITK.pth and PATH and PYTHONPATH set to ITKbuild/lib/Release and ITKbuild/bin/Release it throws the following error. Seems like the lazy loader does not look in the lib/Release folder, where _ITKPyBasePython.pyd is located.

import itk

itk.Image
Traceback (most recent call last):

File “”, line 1, in
itk.Image

File “C:\build\Wrapping\Generators\Python\Release\itkLazy.py”, line 46, in getattribute
itkBase.LoadModule(module, namespace)

File “C:\build\Wrapping\Generators\Python\Release\itkBase.py”, line 118, in LoadModule
LoadModule(dep, namespace)

File “C:\build\Wrapping\Generators\Python\Release\itkBase.py”, line 128, in LoadModule
module = loader.load(swigModuleName)

File “C:\build\Wrapping\Generators\Python\Release\itkBase.py”, line 253, in load
return importlib.import_module(name)

File “C:\Users\Fabian\Anaconda3\envs\PythonCPU\lib\importlib_init_.py”, line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)

File “”, line 1006, in _gcd_import

File “”, line 983, in _find_and_load

File “”, line 967, in _find_and_load_unlocked

File “”, line 677, in _load_unlocked

File “”, line 728, in exec_module

File “”, line 219, in _call_with_frames_removed

File “C:\build\lib\ITKPyBasePython.py”, line 32, in
_ITKPyBasePython = swig_import_helper()

File “C:\build\lib\ITKPyBasePython.py”, line 24, in swig_import_helper
import _ITKPyBasePython

ImportError: DLL load failed: Das angegebene Modul wurde nicht gefunden.

Even though i do not understand the link, but: Do I need to have an extra ITK build (with different referenced Python in CMAKE)?

Thanks in advance. I will try with PyPI’s ITK in the meantime and report.

Are ITK’s CMake configuration variables, PYTHON_INCLUDE_DIR and PYTHON_LIBRARY consistent with the runtime version? Building for conda Python 3.6 and running Python 3.7, for example, is not expected to work.

I did not build ITK with PYTHON_INCLUDE_DIR set to python 3.7 executable yet.
I am going to try this tonight.

I wasn’t aware of the need.
Thank you!

1 Like