ITK icon indicating copy to clipboard operation
ITK copied to clipboard

Feature Request: Make empty `itk.Image` and related data serializable (pickleable) for use with `dask.distributed`

Open tbirdso opened this issue 2 years ago • 4 comments

Description

ITK supports Python's pickle serialization technique for fully buffered itk.Image objects (see https://github.com/InsightSoftwareConsortium/ITK/pull/2829), but not for advanced use cases of itk.Image.

It would be good to support the following cases:

  1. Unbuffered itk.Image describing a relationship between an oriented spatial bounding box and an implied underlying voxel array. I.e., image.GetBufferedRegion() is zero and image.GetLargestPossibleRegion() is greater than zero.
  2. Partially buffered itk.Image describing a subimage. I.e., image.GetBufferedRegion() is greater than zero and is strictly less than image.GetLargestPossibleRegion().
  3. Directly support serialization of related itk.Image header objects such as itk.ImageRegion and itk.Matrix.

Steps to Reproduce

For case 1:

import itk
import pickle

reader = itk.ImageFileReader[itk.Image[itk.F,3]].New()
reader.SetFileName('path/to/image.mha')
reader.UpdateOutputInformation() # update without buffering

result = pickle.dumps(reader.GetOutput())

Expected behavior

Image is serialized to a bytestring and can be deserialized with pickle.loads(result) with no loss of information

Actual behavior

Serialization fails because there is not a voxel buffer to convert to NumPy:

>>> pickle.dumps(im2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\venvs\venv-itk\lib\site-packages\itk\itkImagePython.py", line 7297, in __getstate__
    state = itk.dict_from_image(self)
  File "C:\venvs\venv-itk\lib\site-packages\itk\support\extras.py", line 791, in dict_from_image
    pixel_arr = itk.array_from_image(image)
  File "C:\venvs\venv-itk\lib\site-packages\itk\support\extras.py", line 335, in GetArrayFromImage
    return _GetArrayFromImage(
  File "C:\venvs\venv-itk\lib\site-packages\itk\support\extras.py", line 317, in _GetArrayFromImage
    return templatedFunction(img, keep_axes, update)
  File "C:\venvs\venv-itk\lib\site-packages\itk\itkPyBufferPython.py", line 3839, in GetArrayFromImage
    arrayView = itkPyBufferIF3.GetArrayViewFromImage(image, keep_axes, update)
  File "C:\venvs\venv-itk\lib\site-packages\itk\itkPyBufferPython.py", line 3820, in GetArrayViewFromImage
    memview       = itkPyBufferIF3._GetArrayViewFromImage(image)
ValueError: PyMemoryView_FromBuffer(): info->buf must not be NULL

Additional Information

Related to work with dask.distributed in https://github.com/InsightSoftwareConsortium/itk-dreg

cc @thewtex

tbirdso avatar Oct 23 '23 17:10 tbirdso

arrayView = itkPyBufferIF3.GetArrayViewFromImage(image, keep_axes, update)

At this point, if the image buffer is empty / has not been allocated, we should return None.

thewtex avatar Oct 23 '23 19:10 thewtex

Partially buffered itk.Image describing a subimage. I.e., image.GetBufferedRegion() is greater than zero and is strictly less than image.GetLargestPossibleRegion()

I will work on this in coordination with https://github.com/InsightSoftwareConsortium/itk-wasm/issues/983.

Directly support serialization of related itk.Image header objects such as itk.ImageRegion and itk.Matrix.

I think Direction (Matrix) is already serialized.

thewtex avatar Oct 27 '23 14:10 thewtex

I think Direction (Matrix) is already serialized.

I see the following behavior in itk==v5.4rc1:

>>> pickle.dumps(itk.Matrix[itk.D,3,3]())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot pickle 'SwigPyObject' object

tbirdso avatar Oct 27 '23 14:10 tbirdso

Ah, yes, it currently has to be explicitly converted to a NumPy array.

thewtex avatar Oct 27 '23 15:10 thewtex