-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Add support for high bit depth multichannel images #1888
Comments
I'm having the same problem with 16 bit single-channel paletted TIFFs, created by GDAL. It would be "really" nice if Pillow could play nicely with GIS and scientific image formats, as GDAL is a pain in the ass and I'd rather not use it. tiffinfo as follows: TIFFReadDirectory: Warning, Unknown field with tag 33550 (0x830e) encountered. |
Any updates on this? |
Unfortunately, no. |
@wiredfool what do you think about to add the support of multichannel images as sequence of Image ? For example, 4 channels image with uint16 is represented (more less equivalently) by |
To do anything useful with it, we'd have to have support in the C layer, so it would have to be at the core imaging layer, and especially Unpack/Pack. |
@wiredfool following your "Ways to help",
For GIS, as there is a huge amount of different formats (for example, gdal format list), this can be left for GIS libraries as gdal, rasterio etc.
For GIS imagery, this can be easily created manually with gdal, rasterio. I would like to give a hand on this, so, feel free to ask me. |
PIL cannot handle processing multi-channel images. They get truncated to 3-ch images if you perform any transformation using PIL. #3160 |
What is the status of this issue? It has been almost three years since the first proposal. I am unfortunately unable to provide any help since I have zero experience with coding in C, but I am among the people that is awaiting support for e.g. multi-channel floating-point images (with possibilities for negative pixel values). This especially useful in deep learning, where it is preferable to have all values normalized with zero mean. PIL has some really awesome ImageOps, which is one of the reasons for wanting this support. |
Please fix the issue with multi-channel 16 bit images. |
@aclark4life For the most part, VFX studios tend to work with EXR file formats. Internally most of our softwares process in 32bit float, although saving the resulting images in 16bit float is usually enough, except for a small number of specific data passes that we tend to store in other channels. I've not been doing much personally recently that could have used PIL, the main cases I've run into when I posted were external tools we brought into our pipeline that used PIL for their image reading, and we had to strip it away so we could run our 16bit float images through without the loss caused by going through 8bit, so yes, absolutely, if PIL supported those natively we wouldn't need to go out of our way to strip PIL away when somebody uses it, which would be great. |
PIL is used in many ML frameworks for reading images, like FastAI and detectron2 and countless ML projects. When someone tries to use these frameworks or projects as examples with their high bit depth multichannel images, often the first thing to cause grief is this issue. On multiple occasions I've had to rewrite image data loaders for ML because Pillow does not support multichannel float32 tifs. This imagery is really common in geospatial analysis, most satellite imagery comes in high bit depth. |
@cgohlke Does any of your code here potentially help us by way of example to implement high bit depth multichannel in Pillow? https://github.com/cgohlke/tifffile/blob/master/tifffile/_imagecodecs.py Thanks for any info |
Via @wiredfool , thanks!
So looking at that, I think there's two definite possibilities for progress.
|
Also possibly of interest: https://github.com/girder/large_image |
FWIW, some references on Arrow.
|
Can anyone suggest some test data we can use to develop this feature? This event is happening tomorrow and would be nice to have a success target in mind e.g. "If we can read/write this type of data …" https://www.meetup.com/dcpython/events/301086016/ |
In case it isn't too much pain to work with more than 4 bands, we host this example subset of Eurosat, here is an example image Each image is 13 bands, uint16, planar
|
@wiredfool If we use Arrow that implies adding a dependency on pyarrow, ideally optionally via extras like |
@aclark4life Maybe. There's definitely a C-only implementation (nanoarrow) that might be what we want, since all of our image allocations are in the C layer now. PyArrow might be easier for integration/interop at the high level, but my sense here is that it wouldn't necessarily be giving us a whole lot that we'd not already have with a C arrow implementation + our usual set of accessors. |
Folks interested in this issue, please test #8224 and give feedback, thanks all |
Hi, any updates on a potential merge of #8224? If I understand properly it would add support for reading pyramidal tiffs? |
@MyleneSimon No, but I haven't given up! May need to move ETA for more progress to Q1 2025. What we really need is some code reviews and opinions about which direction to go in… thanks for the interest. |
Can the community somehow help with the work on this feature? It is possible to divide what is possible into minimal parts and start implementing and testing them, at least those that can be divided, if any. |
Pillow (and PIL) is currently able to open 8 bit per channel multi-channel images (such as RGB) but is able to open higher bit depth images (e.g. I16, I32, or Float32 images) if they are single channel (e.g., grayscale).
Previous References
This has been requested many times: #1828, #1885, #1839, #1602, and farther back.
Requirements
Background Reference Info
The rough sequence for image loading is:
Image file is opened
Each of the ImagePlugin _accept functions have a chance to look at the first few bytes to determine if they should attempt to open the file
The
*ImagePlugin._open
method is called giving the image plugin a chance to read more of the image and determine if it still wants to consider it a valid image of it's particular type. If it does, it passes back a tile definition which includes a decoder and an image size.If there is a successful _open call, at some point later
*ImagePlugin._load
may be called on the image, which runs the decoder producing a set of bytes in a raw mode. This is where things like compression are handled, but the output of the decoder is not necessarily what we're storing in our internal structures.The image is unpacked (
Unpack.c
) from the raw mode (e.g.I16;BS
) into a storage (Storage.c
) mode (I
).It's now possible to operate on the image (e.g. crop, pixel access, etc)
There are 3 (or 4) image data pointers, as defined in Imaging.h:
The only one that is guaranteed to be set is
**image
, which is an array of pointers to row data.Changes Required
Core Imaging Structure
**image
pointer can be used for any width of pixel.**image32
pointer.IMAGING_TYPE_INT32
andIMAGING_TYPE_FLOAT32
imply 1 band. This will change.IMAGING_TYPE_INT16
Storage
Storage.c
,Unpack.c
,Pack.c
,Access.c
,PyAccess.py
, andConvert.c
Ways to Help
We need a better definition of the format requirements. What are the various types of images that are used in GIS, Medical, or other fields that we'd want to interpret? We need small, redistributable versions of images that we can test against.
[in progress]
The text was updated successfully, but these errors were encountered: