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

Unable to convert ImgLib2 BooleanType image to numpy/xarray bool #13

Open
elevans opened this issue Sep 20, 2021 · 5 comments
Open

Unable to convert ImgLib2 BooleanType image to numpy/xarray bool #13

elevans opened this issue Sep 20, 2021 · 5 comments
Assignees
Milestone

Comments

@elevans
Copy link
Collaborator

elevans commented Sep 20, 2021

imglyb does not support converting bool type images to numpy. This means that users are unable to convert masks/thresholded images into python numpy/xarray objects.

Here is a minimal example:

import imagej
import scyjava as sj

# initialize
ij = imagej.init()

# load blobs
img = ij.io().open('blobs.tif')

# threshold image w/ ops
CreateNamespace = sj.jimport('net.imagej.ops.create.CreateNamespace')

img_invert = ij.op().namespace(CreateNamespace).img(img)
ij.op().image().invert(img_invert, img)
threshold = ij.op().threshold().otsu(img_invert)

# get threshold from java
py_threshold = ij.py.from_java(threshold)

Returns the traceback:

File "/home/edward/Documents/repos/loci/imglyb/imglyb/util.py", line 149, in _to_imglib
    raise NotImplementedError("Cannot convert dtype to ImgLib2 type yet: {}".format(source.dtype))
NotImplementedError: Cannot convert dtype to ImgLib2 type yet: bool
@elevans elevans self-assigned this Sep 20, 2021
@ctrueden ctrueden changed the title Unable to convert ImgLib2 bool type to numpy/xarray Unable to convert ImgLib2 BooleanType image to numpy/xarray bool Sep 21, 2021
@elevans
Copy link
Collaborator Author

elevans commented Sep 21, 2021

With @hinerm we determined that imglib2-unsafe needs to support BitType or BooleanType types.

To resolve this bug we need to:

  • Add types BitType or BooleanType to imglib2-unsafe
  • Update the numpy_dtype_to_conversion_method dictionary in imglyb/util.py.

@hinerm
Copy link
Member

hinerm commented Sep 22, 2021

Technically this is an imglib2 BitType.

Adding support for this conversion requires:

This runs into several challenges including:

  • Unsafe does not provide a getBoolean(address) method in the way it does for every other data type. Presumably you can use getByte(address) and cast? But I don't know for sure.
  • BitType uses a LongAccess for storage. This makes the associated infrastructure that must be implemented much less straightforward.
  • NativeBoolType seems like a simpler direct match for booleans but would require conversion of BitType images to NativeBoolType, and again only is reasonable if it's compatible with Unsafe.getByte(address).

At the moment we have logic to catch upsupported types and default them to float64. In the short term I think we should comment out the BitType support since it is not actually supported, and rely on the fallback support.

hinerm added a commit to imagej/pyimagej that referenced this issue Sep 23, 2021
There currently is no `bool` convert method registered in imglyb.util.

See:
* imglib/imglyb#13
* https://github.com/imglib/imglyb/blob/master/imglyb/util.py#L39-L69
@ctrueden
Copy link
Member

@hinerm It looks like NumPy bool typed images are booleans each stored as a byte, same as in Java. I.e. each element ends up being 8 bits under the hood. Therefore, as you say, NativeBoolType would indeed be the direct mapping.

For converting a BitType image to NumPy, we can use net.imglib2.converter.RealTypeConverters.copyFromTo(bitImg, nativeBoolImg), since it uses getReal/setRealDouble to do the copy, rather than get/set directly like net.imagej.util.Images.copy does.

So then the plan to implement this initially would be:

  1. Augment imglyb to support conversion between Python bool and ImgLib2 NativeBoolType images.
  2. Augment pyimagej's rai_to_numpy function to be smarter about types, with a new case covering conversion of BitType RAIs by allocating the new_numpy_image result as a NativeBoolType instead, and using RealTypeConverters rather than Images to do the copy.
  3. Later down the line, consider doing something like what this SO post describes to create a NumPy image backed by 1-bit elements, and figure out if we can directly go between that and a BitType ImgLib2 image with zero copying.

@imagesc-bot
Copy link

This issue has been mentioned on Image.sc Forum. There might be relevant details there:

https://forum.image.sc/t/show-a-binary-image-in-pyimagej/58031/2

@ctrueden ctrueden added this to the unscheduled milestone Nov 16, 2021
@gselzer
Copy link
Contributor

gselzer commented Jul 29, 2022

I noticed this issue completely ignorant of this one, and just filed imglib/imglib2-unsafe#8

@hinerm It looks like NumPy bool typed images are booleans each stored as a byte, same as in Java. I.e. each element ends up being 8 bits under the hood. Therefore, as you say, NativeBoolType would indeed be the direct mapping.

But, now seeing this, I wonder if that is the correct fix... I don't know that it is an issue with the code, but I do think that it doesn't help with this issue.

Anyways, I'm going to try and fix this, as imagej/napari-imagej#69 doesn't do much for us without this feature. The only way to get a Mesh in stock ImageJ Ops is via a BooleanType 3D image, which we cannot get due to this.

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

5 participants