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

rawpy plugin #1063

Draft
wants to merge 29 commits into
base: master
Choose a base branch
from
Draft

rawpy plugin #1063

wants to merge 29 commits into from

Conversation

tahseenadit
Copy link

@tahseenadit tahseenadit commented Feb 20, 2024

This PR adds rawpy plugin. https://github.com/imageio/imageio/issues/691

  • Created a python script in the plugins folder for rawpy plugin wrapper.
  • Created a python script in the test folder and added one test for the rawpy plugin.
  • Updated setup.py, plugins.py and extensions.py to include rawpy plugin.

Note: This is work in progress. This PR has been opened to keep track of the work and is still in draft.

Copy link
Contributor

@FirefoxMetzger FirefoxMetzger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a quick review. Great progress so far 🚀

So far I only have small comments on how plugins are used/digested by ImageIO and how you will have to adjust the logic to comply with these particularities.

imageio/config/extensions.py Outdated Show resolved Hide resolved
imageio/config/extensions.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
setup.py Outdated Show resolved Hide resolved
tests/test_rawpy.py Outdated Show resolved Hide resolved
tests/test_rawpy.py Outdated Show resolved Hide resolved
Copy link
Contributor

@FirefoxMetzger FirefoxMetzger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice progress 🚀

I started to comment on edge cases, which is a sign that we are getting closer to the finish line for the functions that are currently implemented.

Metadata is still missing and we should start thinking of docstrings next, but this is something we can take one step at a time.

Good work!

imageio/plugins/rawpy.py Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
Copy link
Contributor

@FirefoxMetzger FirefoxMetzger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice work @tahseenadit 🚀

Code-wise this looks pretty much ready to go except and there are now some action items for me:

  • Provide you feedback on which metadata fields need exporting and which we should keep out of the dict.
  • Check if forwarding the raw image's dtype is the correct thing to do in properties.
  • Find some permissively-licensed test images you can use for unit testing.

For you, there are two things left (beyond minor changes after me completing above tasks):

  1. Handling of index=... in read.
  2. Getting test coverage to 100%.

Regarding the first point, we have this piece of docs in the PluginV3 class:

If a PNG file (single image format) is read with
index=None the plugin does a very similar thing: It loads all
ndimages in the file (here it's just one) and stacks them along a new
first axis, effectively prepending an axis with size 1 to the image. If
a plugin does not wish to support index=None it should set a more
sensible default and raise a ValueError when requested to read using
index=None.

The docs are slightly outdated in that it should read index=... where it says index=None (I will update). The logic here is that some images may contain multiple frames/images and users should be able to conveniently request all images as a batch.

For rawpy we currently think that it handle single-image formats only, so handling this is fairly easy: Whenever a user calls file.read("some_image", index=...) we read the image and then add an "empty" dimension at the front. This can be as simple as image = image[None, ...].

Regarding the second point, you've already started adding some tests. Keep doing so and feel free to use images that you have the right to use for this purpose :) Once I find pictures we can use and distribute I will share them here and then we can keep the test logic but replace the image.

imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
height: int = ImageSize.height
shape: Tuple[int, ...] = (height, width)

dtype = self._image_file.raw_image.dtype.type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I need to think about this one. You are forwarding the dtype of the raw image here. However, all the methods (read/iter) provide the postprocessed image, which may have changed its type and thus no longer match what the type of the raw image. That said, I don't know if this can happen in rawpy, so I need to look into if this is the right thing to do, or not.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more thing, raw_image has raw_shape with raw_width and raw_height. The raw_height is slightly different than ImageSize.height of the raw image. In the documentation, there is ImageSize for width and height. Do you think I should use raw_height instead of height from the ImageSize ? What will be the shape for both metadata and properties in that case ? Or should I keep them both as I have done now ?

tests/test_rawpy.py Outdated Show resolved Hide resolved
@FirefoxMetzger
Copy link
Contributor

I also just saw that we are getting some CI failures due to the use of bytes | None in your type hints.

We need to solve this a bit differently here, because we need to support all python versions (currently 3.8 - 3.12) and not all of them support this syntax yet. Instead you'll have to do something like:

from typing import Optional

... # somewhere in the code
... -> Optional[bytes]

@FirefoxMetzger
Copy link
Contributor

Adding this here for later: I found that rawpy can raise a LibRawFileUnsupportedError error when reading an unsupported image. We should catch this during initialization and rase a InitializationError when that happens.

@FirefoxMetzger
Copy link
Contributor

Find some permissively-licensed test images you can use for unit testing.

I found a source of images: https://raw.pixls.us/

The website has a long list of CC0 licenced raw images that we can use (and distribute) for unit testing 🚀❤️ @tahseenadit feel free to have a look around and pick some images in different formats. Try to choose smaller files so that the initial image dataset download doesn't blow up too much 🙏

Copy link
Contributor

@FirefoxMetzger FirefoxMetzger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! Only very minor changes from my side this time.

I noticed that the docs are not picking up the new plugin. I will check this evening why that is the case and will let you know on Wednesday.

imageio/plugins/rawpy.py Show resolved Hide resolved
Copy link
Contributor

@FirefoxMetzger FirefoxMetzger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit later than I wanted, but I am now done with another round of review. I also went through the source of rawpy to see which pieces of metadata should live where.

The one thing I haven't managed to work out yet is how the raw dtype relates to the actual dtype of the returned image. What I can say so far is that there are more raw types than returned types and, hence, we can't just forward the raw dtype like we do now. However, I'm still not 100% sure what the correct alternative is so lets leave it as-is until we know :)

imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
Copy link
Contributor

@FirefoxMetzger FirefoxMetzger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick review before our meeting today. Looking good so far :)

imageio/plugins/rawpy.py Outdated Show resolved Hide resolved
tests/test_rawpy.py Outdated Show resolved Hide resolved
tests/test_rawpy.py Outdated Show resolved Hide resolved
@tahseenadit
Copy link
Author

I also just saw that we are getting some CI failures due to the use of bytes | None in your type hints.

We need to solve this a bit differently here, because we need to support all python versions (currently 3.8 - 3.12) and not all of them support this syntax yet. Instead you'll have to do something like:

from typing import Optional

... # somewhere in the code
... -> Optional[bytes]

Just leaving a reply here that it has been updated accordingly.

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

Successfully merging this pull request may close these issues.

None yet

2 participants