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

affine_transform fails in simplest possible use case #204

Closed
martinschorb opened this issue Apr 20, 2021 · 8 comments
Closed

affine_transform fails in simplest possible use case #204

martinschorb opened this issue Apr 20, 2021 · 8 comments

Comments

@martinschorb
Copy link
Contributor

What happened:
Running affine_transform on a simple 2D image produces a TypeError when offset is None

from scipy import  misc
from dask_image.ndinterp import affine_transform

img = da.from_array(misc.ascent())

matrix = np.array([[0,-1],[1,0]])

img_45 = affine_transform(img, matrix)

results in:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-28-84fbda5afee9> in <module>
      8 matrix = np.array([[0,-1],[1,0]])
      9 
---> 10 img_45 = affine_transform(img, matrix)
     11 #plt.imshow(img_45)

/g/emcf/software/python/miniconda/envs/xtomo/lib/python3.8/site-packages/dask_image/ndinterp/__init__.py in affine_transform(image, matrix, offset, output_shape, order, output_chunks, **kwargs)
    154             rel_image_edges = matrix * out_chunk_edges + offset
    155         else:
--> 156             rel_image_edges = np.dot(matrix, out_chunk_edges.T).T + offset
    157 
    158         rel_image_i = np.min(rel_image_edges, 0)

TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'

Anything else we need to know?:

The problem is due to offset still being None. In this case it is never touched, and offset = np.asarray(offset).squeeze() in l. 96 also yields None.

Environment:

  • Dask version: 2021.3.0
  • dask-image 0.5.0
  • Python version: 3.8.8
  • Operating System: CentOS 7
  • Install method (conda, pip, source): conda
@martinschorb
Copy link
Contributor Author

Also, I found that output_shape needs to be a tuple in dask-image, whereas the "original" function also accepts np.arrays.

Otherwise l.126: normalized_chunks = da.core.normalize_chunks(output_chunks, output_shape) fails.

@martinschorb
Copy link
Contributor Author

In addition, the variable that is returned cannot be specified as output kwarg.

I now have handcrafted my own rotate around it.

@martinschorb
Copy link
Contributor Author

In addition, the variable that is returned cannot be specified as output kwarg.

This seems to be more tricky in cases with ndim>2 as this output accepts not only arrays but also slice iterators at arbitrary angles and positions pointing to an array.
https://github.com/scipy/scipy/blob/f2ef65dc7f00672496d7de6154744fee55ef95e9/scipy/ndimage/interpolation.py#L941

@m-albert
Copy link
Collaborator

m-albert commented Apr 20, 2021

@martinschorb Thanks a lot for reporting this bug and the careful characterization :)

I addressed what you found in #205. Feel free to check out the PR branch and see whether it fixes the problems you mentioned.

Running affine_transform on a simple 2D image produces a TypeError when offset is None

Fixed.

Also, I found that output_shape needs to be a tuple in dask-image, whereas the "original" function also accepts np.arrays.

The scipy implementation expects a tuple, but works fine with a numpy array. In the PR, I fixed the docstring to reflect that the input should be a tuple, and at the same time introduced a tuple conversion so that, just like the scipy implementation, passing an array doesn't lead to an error.

In addition, the variable that is returned cannot be specified as output kwarg.

True, very good point. While this is an inconsistency with the scipy implementation, I'm not sure whether it would have any benefits to provide an output dask array (although output= also accepts a dtype). So I didn't address this for now. Though probably it will be important to make this consistent once the dask_image integration into NEP18 efforts advances. Maybe @jakirkham has thoughts on this.

@m-albert
Copy link
Collaborator

I now have handcrafted my own rotate around it.

What you could do of course is to convert your rotation parameters into an affine matrix and simply use the affine transform. Or is there something dask_image.ndinterp.affine_transform doesn't allow you to do?

@martinschorb
Copy link
Contributor Author

Or is there something dask_image.ndinterp.affine_transform doesn't allow you to do?

Yes, that's linked to the output and the way rotate populates that array when slicing arbitrarily.
In my case, it's OK because I am rotating in a coordinate plane, so I can manually distribute the slices. But for more general cases I see two options:

  • support the slice-based output
  • rewriting rotate such that it does not perform individual slice-based transformations but rather one single N-D matrix operation on the whole array. This should be feasible with the current dask_image.ndinterp.affine_transform.

@m-albert
Copy link
Collaborator

Could you post an example of your usage that includes the slicing you mention?

@m-albert
Copy link
Collaborator

Let's move this discussion to #205

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants