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

16-bit integer TIFF fails to load as expected #5248

Closed
pkgw opened this issue Feb 3, 2021 · 6 comments
Closed

16-bit integer TIFF fails to load as expected #5248

pkgw opened this issue Feb 3, 2021 · 6 comments
Labels
Anaconda Issues with Anaconda's Pillow TIFF

Comments

@pkgw
Copy link

pkgw commented Feb 3, 2021

edit: the actual issue might have to do with 16-bit-int TIFF loading; see next comment. At first I thought that the issue was application of the color profile, but now I think probably not.

What did you do?

I am trying to work with this image (55 MiB TIFF) in Pillow. It's an astronomical image of a galaxy.

What did you expect to happen?

I want to convert the image to sRGB. If I do the transformation using GIMP, most of the image comes out close to black as you'd expect:

# before running code: convert image to PNG in GIMP, save as `gimp-good.png`
import numpy as np
from PIL import Image, ImageCms

img_cnv = Image.open('gimp-good.png')
arr_cnv = np.asarray(img_cnv)
print(arr_cnv[200,200])  # corners of image are full black
<<< [7 3 1] 

What actually happened?

Doing the conversion myself, nothing happens, and the resulting values are very wrong:

import numpy as np
from PIL import Image, ImageCms
from io import BytesIO

img_orig = Image.open('gemini1210a.tif')
img_orig = img_orig.convert('RGB')  # image reads as RGBX mode, but X channel is all 255s; seems to be unrelated
arr_orig = np.asarray(img_orig)

in_prof = ImageCms.getOpenProfile(BytesIO(img_orig.info['icc_profile']))
out_prof = ImageCms.createProfile('sRGB')
xform = ImageCms.buildTransform(in_prof, out_prof, 'RGB', 'RGB')
img_xform = ImageCms.applyTransform(img_orig, xform)
arr_xform = np.asarray(img_xform)

print(arr_orig[200,200], arr_xform[200,200])
<<< [132  10 120] [132  10 120]

I'm not an expert in this stuff but I've experimented with various mode conversions, rendering intents, etc. and can't figure out a way to get the profile transform to actually do anything.

What are your OS, Python and Pillow versions?

  • OS: Linux, Fedora 33
  • Python: 3.8.6 (conda-forge)
  • Pillow: 8.1.0 (conda-forge)

Side note

The image's profile is labeled as being "sRGB IEC61966-2.1", so I am surprised that the values that GIMP obtains are so far off from the ones in the raw image as read by Pillow. Maybe an indication that there's a data format issue?

@pkgw
Copy link
Author

pkgw commented Feb 3, 2021

Oh, of course, after filing one makes progress. GIMP reports that the image is in 16-bit integer format. The 4.3.0 release notes say:

"Pillow now can read 16-bit multichannel TIFF files including files with alpha transparency. The image data is truncated to 8-bit precision."

For my sample pixel at x,y = 200,200, GIMP reports RGB = 1924, 738, 376 = 0x0784, 0x02E2, 0x0178, which truncates to (about) the 7, 3, 1 as found by GIMP. It's not obvious to me where the Pillow values (132, 10, 120 = 0x84, 0x0A, 0x78) are coming from although you can see overlaps in the hex representations.

@radarhere radarhere added NumPy and removed NumPy labels Feb 4, 2021
@radarhere
Copy link
Member

If I take your image (converted to a smaller PNG for display purposes)
gemini1210a

and run

from PIL import Image
img_orig = Image.open('gemini1210a.tif')
img_orig.convert('RGB').resize((500, 299)).save('out.png')

then the result is
out

So, perhaps in line with your second comment, your problem is more fundamental than image profiles, yes?

@radarhere radarhere added the TIFF label Feb 4, 2021
@pkgw
Copy link
Author

pkgw commented Feb 4, 2021

@radarhere I've had cases where I've had comparable differences between what I've seen in an image viewer and what I've gotten out of Pillow, and the ultimate culprit has been color profiles, but yes, now I think the issue is the handling of the 16-bit integer data.

@pkgw pkgw changed the title Image's color profile fails to apply 16-bit integer TIFF fails to load as expected Feb 4, 2021
@kmilos
Copy link
Contributor

kmilos commented Feb 5, 2021

For my sample pixel at x,y = 200,200, GIMP reports RGB = 1924, 738, 376 = 0x0784, 0x02E2, 0x0178, which truncates to (about) the 7, 3, 1 as found by GIMP. It's not obvious to me where the Pillow values (132, 10, 120 = 0x84, 0x0A, 0x78) are coming from although you can see overlaps in the hex representations.

Well it's pretty clear this is just truncation and just the LSB is taken by Pillow. I've tested loading via imageio and the three possible backends: Pillow, FreeImage, and default tifffile:

import imageio
img0 = imageio.imread('gemini1210a.tif', 'TIFF-PIL')[...,0:3]
img1 = imageio.imread('gemini1210a.tif', 'TIFF-FI')[...,0:3]
img2 = imageio.imread('gemini1210a.tif')[...,0:3]

FI/tifffile return a uint16 array and for your pixel at (200,200) the value ['0x0784', '0x030a', '0x0178']
Pillow returns uint8 and ['0x84', '0x0a', '0x78'], i.e. exactly just the LSB.

@pkgw
Copy link
Author

pkgw commented Feb 5, 2021

@kmilos I had the G channel being 738 = 0x02E2, not ending in 0x0A. Probably I just made a typo above, though — I remember that I had at least one other one.

@radarhere
Copy link
Member

Testing, this image now loads correctly in Pillow 8.2.0 and later, thanks to #5364.

import numpy as np
from PIL import Image, ImageCms

img_cnv = Image.open('gemini1210a.tif')
arr_cnv = np.asarray(img_cnv)
print(arr_cnv[200,200])

gives [ 7 3 1 255].

@aclark4life aclark4life added the Anaconda Issues with Anaconda's Pillow label May 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Anaconda Issues with Anaconda's Pillow TIFF
Projects
None yet
Development

No branches or pull requests

4 participants