-
-
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
Wrong decoding of 15-bit JPEG2000 images #6194
Comments
This is the only change (edit: to JP2K decoding) I can see in the history between 8.4.0 and 9.0.0: 4b7b07d (a fix for big-endian architectures). It doesn't look to me like that should affect little-endian, |
The changes to Jpeg2KDecode in #5901 are indeed causing the difference. I've created #6197 to fix this. It would be good to add a test for this, so that we can ensure that this problem doesn't happen again. Do you have an image that we could add to our test suite, and distribute under the Pillow license? |
Oh, I see now what the issue is, the |
Feel free to take the example image |
I managed to derive a test image from one of our existing images, and have added it to the PR. |
Thanks for improving this. However, the issue is not yet completely solved. It turns out the test image from PIL import Image
import numpy as np
image = np.array(Image.open("img-15bit.jp2"))
image = image / 2 # A fix that produces correct values
print(np.mean(image))
>> 0.3041897339424886 Is this something you would be interested to improve? |
Just to be clear, you agree that we have fixed the regression. Your request is that we change the original behaviour. If I run ImageMagick's
and then run from PIL import Image
import numpy as np
image = np.array(Image.open("imagemagick.png"))
print(np.mean(image)) I get 0.6083794678849772 - the same value I get when running from PIL import Image
import numpy as np
image = np.array(Image.open("img-15bit.jp2"))
print(np.mean(image)) It seems to me that ImageMagick agrees with us - so I would be interested in more evidence that Pillow is doing something wrong, beyond just OpenCV and rasterio producing a different result. |
Yes, I confirm the regression has been fixed. 👍
Fair point. So far I don't have enough low-level understanding of the encoding used in this special case and about the formal definition of JPEG2000 encoding. So I'm not able to explain what exactly the problem is or which tools are correct. I can only say that according to my domain-specific knowledge the values of satellite images read by Pillow are not correct unless we divide them by I'll let you know more if I ever get a better understanding about this. However, at the moment this seems to be a low-priority issue for us so it is possible I won't have time to dig into it. |
What did you do?
Satellite images from Sentinel-2 satellite, released by European Space Agency, are originally encoded in JPEG2000 format with an unusual 15-bit encoding. Since early versions,
Pillow
is reading these images incorrectly.For
Pillow<9.0.0
the error was that the decoded values were twice as large as they should be. Therefore a simple fix of dividing values by2
solved the problem. This can be seen from code snippet 2.For
Pillow>=9.0.0
the decoded values seem to be completely arbitrary and such a fix doesn't work anymore. This can be seen from code snippet 1.What did you expect to happen?
It is expected that values would be read correctly, like this is done by OpenCV and
rasterio
packages (code snippets 3 and 4).What actually happened?
Pillow
reads values incorrectly.What are your OS, Python and Pillow versions?
3.8
)>=9.0.0
(used9.1.0
)Code snippets
For all code snippets we use a small 15-bit JP2 image from
sentinelhub
package unit tests. For simplicity we compare only mean values.Reading with
Pillow>=9.0.0
(usedPillow==9.1.0
):Reading with
Pillow<9.0.0
(usedPillow==8.4.0
):Reading with OpenCV (used
opencv-python==4.5.5.64
):Reading with
rasterio
(usedrasterio==1.2.10
):The text was updated successfully, but these errors were encountered: