Repository navigation
Image conversion should scale pixel values accordingly #3159
Description
Activity
With regards to the floating point data, if I change if from
2**16-1to2**8-1, it works fine.import numpy from PIL import Image img = Image.open('/Users/andrewmurray/Desktop/16bit_image.png') img_float = Image.fromarray(numpy.divide(numpy.array(img), 2**8-1)) print(numpy.array(img_float)) img_oct = img_float.convert('L') print(numpy.array(img_oct))
[[202.19215 206.76863 199.50981 ... 119.58039 121.53333 117.28236 ] [202.91373 204.64706 200.86667 ... 120.9451 117.333336 120.75687 ] [201.09412 198.17255 200.50197 ... 123.6549 120.988235 120.2 ] ... [110.933334 109.28628 109.92941 ... 134.77255 134.2549 134.55687 ] [105.4902 108.10588 110.27451 ... 142.07451 135.71373 130.97647 ] [109.670586 110.68235 109.6549 ... 142.05098 140.59216 135.20392 ]] [[202 206 199 ... 119 121 117] [202 204 200 ... 120 117 120] [201 198 200 ... 123 120 120] ... [110 109 109 ... 134 134 134] [105 108 110 ... 142 135 130] [109 110 109 ... 142 140 135]]
With regards to the first part, I've created PR #3838 to address this.
Reacted by Nathan GrauleThanks a lot for that. It'll help a lot for my terrain generation library!
#3838 has been merged.
It turns out that this situation is more complicated. See #3838 (comment)
I don't understand is this happening or not?
fp = "/home/max/dev_projects/cuda_blob/data/S_000_1752450056/Tile_r1-c1_S_000_1752450056.tif" img = Image.open(fp).convert('I').convert('F') imarray = cp.array(img) print(imarray.min(), imarray.max())
gives
0.0 254.0Shouldn't the pixel values be scaled to
[0,1]?using
pillow 8.0.1 python 3.8.5This issue is more complex to resolve than I initially thought, and there is not even a consensus that it should be fixed.
I think this is related. I noticed that https://github.com/python-pillow/Pillow/blob/3f960d9a94e5f2cd789da8b9fd0d1d6db8a60cba/src/libImaging/Fill.c uses the same 0-255 range for every image type.
I am currently using this snippet to work around this issue:
def safe_image_loading(path: str) -> Image: img = Image.open(path) bit_size = re.findall(r"\d+", img.mode) bit_size = int(bit_size[0]) if bit_size else 8 if bit_size not in [8, 16, 32]: raise ValueError(f"Unsupported file type, supported bit size is {bit_size}") if bit_size != 8: max_value = 2**bit_size - 1 img_arr = (np.array(img) / max_value) * 255.0 img = Image.fromarray(img_arr.astype(np.uint8)) return img.convert("L")
would be great to have native support for bit sizes in PIL.
What did you do?
I tried to convert grayscale images of different modes together
What did you expect to happen?
Conversion should scale values; for example, converting from float to 8-bit should have the values scaled by 255, converting from 8-bit to 16-bit should have the values scaled by 65535/255, etc.
What actually happened?
Values are being clamped
Floating point data really doesn't go over well either
The input image is a 16 bit PNG made with GIMP, as attached below.
terrain_input.png
What versions of Pillow and Python are you using?
Using Python 3.6.5 and Pillow 5.1.0