Repository navigation
Converting this 16-bit grayscale image to 'L' mode destroys it #3011
Description
Activity
- changed the title
[-]Converting this 16-bit image to grayscale destroys it[/-][+]Converting this 16-bit grayscale image to 'L' mode destroys it[/+]on Feb 20, 2018 There's a longstanding behavioral issue with Pillow where conversions don't intelligently use the range of the target mode.
So, in this case, you're taking an image with values from 0-65k and converting it to 0-255, with clipping. Most of the values are > 255, so they're all white. When you start with an 8 bit image, you convert 0-255 to 0-65k, but since there's no promotion, it's still just a 0-255 image. Converting back is then not a problem.
- addedBugAny unexpected behavior, until confirmed feature.Any unexpected behavior, until confirmed feature.
on Apr 1, 2018 - added and removedBugAny unexpected behavior, until confirmed feature.Any unexpected behavior, until confirmed feature.
on Apr 2, 2018 - added a commit that references this issue
on Jun 28, 2018 This looks related to #3159
I've created PR #3838 to resolve this.
Resolved by #3838
It turns out that this situation is more complicated. See #3838 (comment)
FYI, my work around for my use case (large gray-scale images):
x = np.linspace(0, 65535, 1000, dtype=np.uint16) image = np.tile(x, (1000, 1)).T plt.imshow(image) plt.show() im32 = image.astype(np.int32) pil = Image.fromarray(im32, mode='I')
Shouldn't lose precision.
For I to L conversion, this works for me:
def convert_I_to_L(img) array = np.uint8(np.array(img) / 256) return Image.fromarray(array)
I wanted a non-numpy based solution and came up with:
def convert_I_to_L(im: Image): return ImageMath.eval('im >> 8', im=im.convert('I')).convert('L')
comparing this to
machin3io's numpy code,ImageMathis faster for smaller images whilenumpywins for larger ones:conversion time in ms dimensions ImageMath Numpy 640x 480 1.0 1.3 1280x 960 4.1 3.5 1920x1440 9.3 8.4Reacted by MACHIN3, Hugo van Kemenade, Sun Jeong, Yury Belousov, Andrii Oriekhov, Giles Bathgate and chrisrogers3dReacted by Giulio MennaClosing as part of #3159
- added a commit that references this issue
on Jan 11, 2023 - added a commit that references this issue
on Jul 1, 2023
Here is a 16-bit grayscale image:
It clearly contains a gradient of grays.
If I open it with Pillow, convert it to 8-bit grayscale, and save it, like so...
... then I get this, which is mostly completely white:
This conversion should work; according to http://pillow.readthedocs.io/en/4.2.x/handbook/tutorial.html#converting-between-modes
and according to http://pillow.readthedocs.io/en/latest/handbook/concepts.html#modes,
Iis a supported mode.Notably, I don't see this same problem if I start by loading an 8-bit RGB image from a JPG and then do
.convert('I').convert('L'), so it's not simply the case thatI->Lconversion is broken in general. I'm not what specifically leads to the breakage in this case.