Pillow
Pillow copied to clipboard
Image conversion should scale pixel values accordingly
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
>>> img = Image.open('16bit_image.png')
>>> img.mode
'I'
>>> numpy.array(img)
array([[51559, 52726, 50875, ..., 30493, 30991, 29907],
[51743, 52185, 51221, ..., 30841, 29920, 30793],
[51279, 50534, 51128, ..., 31532, 30852, 30651],
...,
[28288, 27868, 28032, ..., 34367, 34235, 34312],
[26900, 27567, 28120, ..., 36229, 34607, 33399],
[27966, 28224, 27962, ..., 36223, 35851, 34477]], dtype=int32)
>>> numpy.array(img.convert('L'))
array([[255, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255],
...,
[255, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255]], dtype=uint8)
Floating point data really doesn't go over well either
>>> img_float = Image.fromarray(numpy.divide(numpy.array(img), 2**16-1))
>>> numpy.array(img_float)
array([[0.7867399 , 0.8045472 , 0.77630275, ..., 0.46529335, 0.47289234,
0.45635158],
[0.78954756, 0.79629207, 0.78158236, ..., 0.4706035 , 0.45654994,
0.46987107],
[0.78246737, 0.7710994 , 0.7801633 , ..., 0.48114747, 0.47077134,
0.46770427],
...,
[0.4316472 , 0.42523843, 0.4277409 , ..., 0.5244068 , 0.52239263,
0.52356756],
[0.41046768, 0.42064545, 0.4290837 , ..., 0.55281913, 0.52806896,
0.50963604],
[0.4267338 , 0.43067065, 0.42667276, ..., 0.5527275 , 0.5470512 ,
0.5260853 ]], dtype=float32)
>>> img_oct = img_float.convert('L')
>>> numpy.array(img_oct)
array([[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0],
[0, 0, 0, ..., 0, 0, 0]], dtype=uint8)
>>>
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
With regards to the floating point data, if I change if from 2**16-1 to 2**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.
Thanks 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 https://github.com/python-pillow/Pillow/pull/3838#discussion_r292114051
#4044 also reports this issue for I to RGBA conversion, and #5642 for I to RGB conversion.
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.0
Shouldn't the pixel values be scaled to [0,1]?
using
pillow 8.0.1
python 3.8.5
This 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.