Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
tbirdso opened this issue Oct 23, 2023 · 4 comments
Assignees
Labels
type:Enhancement Improvement of existing methods or implementation
Milestone

Comments

@tbirdso
Copy link
Contributor

tbirdso commented Oct 23, 2023

Description

ITK supports Python's pickle serialization technique for fully buffered itk.Image objects (see #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 tbirdso added the type:Enhancement Improvement of existing methods or implementation label Oct 23, 2023
@thewtex
Copy link
Member

thewtex commented Oct 23, 2023

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 thewtex self-assigned this Oct 24, 2023
@thewtex thewtex added this to the ITK 5.4.0 milestone Oct 24, 2023
thewtex added a commit to thewtex/ITK that referenced this issue Oct 26, 2023
If an itk.Image's memory has not been allocated return None from
itk.array_view_from_image.

Pickle and unpickles an unallocated itk.Image to support sending the
image's metadata with Dask. Closes InsightSoftwareConsortium#4267.
thewtex added a commit to thewtex/ITK that referenced this issue Oct 27, 2023
If an itk.Image's memory has not been allocated return None from
itk.array_view_from_image.

Pickle and unpickles an unallocated itk.Image to support sending the
image's metadata with Dask. InsightSoftwareConsortium#4267.
@thewtex
Copy link
Member

thewtex commented Oct 27, 2023

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 InsightSoftwareConsortium/ITK-Wasm#983.

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

I think Direction (Matrix) is already serialized.

@tbirdso
Copy link
Contributor Author

tbirdso commented Oct 27, 2023

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

@thewtex
Copy link
Member

thewtex commented Oct 27, 2023

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

thewtex added a commit to thewtex/ITK that referenced this issue Nov 10, 2023
thewtex added a commit to thewtex/ITK that referenced this issue Nov 10, 2023
thewtex added a commit to thewtex/ITK that referenced this issue May 1, 2024
Optional specification of the BufferedRegion, which is a subset of the
LargestPossibleRegion. Addresses InsightSoftwareConsortium#4267.

The LargestPossibleRegion's Index is assumed to be trivial (zeros).

Also update the NumPy bridge to correctly use the BufferedRegion instead
of the LargestPossibleRegion for the array shape.
@thewtex thewtex closed this as completed May 3, 2024
bourdaisj pushed a commit to bourdaisj/ITK that referenced this issue May 15, 2024
Optional specification of the BufferedRegion, which is a subset of the
LargestPossibleRegion. Addresses InsightSoftwareConsortium#4267.

The LargestPossibleRegion's Index is assumed to be trivial (zeros).

Also update the NumPy bridge to correctly use the BufferedRegion instead
of the LargestPossibleRegion for the array shape.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:Enhancement Improvement of existing methods or implementation
Projects
None yet
Development

No branches or pull requests

2 participants