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

Image conversion should scale pixel values accordingly #3159

Open
SolarLiner opened this issue Jun 7, 2018 · 9 comments
Open

Image conversion should scale pixel values accordingly #3159

SolarLiner opened this issue Jun 7, 2018 · 9 comments

Comments

@SolarLiner
Copy link

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

@radarhere
Copy link
Member

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]]

@radarhere
Copy link
Member

With regards to the first part, I've created PR #3838 to address this.

@SolarLiner
Copy link
Author

Thanks a lot for that. It'll help a lot for my terrain generation library!

@aclark4life aclark4life added this to Backlog in Pillow May 11, 2019
@aclark4life aclark4life moved this from Backlog to In progress in Pillow May 11, 2019
@radarhere radarhere moved this from In progress to Review/QA in Pillow May 11, 2019
@radarhere
Copy link
Member

#3838 has been merged.

Pillow automation moved this from Review/QA to Closed Jun 5, 2019
@radarhere
Copy link
Member

It turns out that this situation is more complicated. See #3838 (comment)

@radarhere radarhere reopened this Jun 11, 2019
Pillow automation moved this from Closed to New Issues Jun 11, 2019
@radarhere radarhere moved this from New Issues to In progress in Pillow Jun 11, 2019
@radarhere
Copy link
Member

radarhere commented Sep 5, 2019

#4044 also reports this issue for I to RGBA conversion, and #5642 for I to RGB conversion.

@makslevental
Copy link

makslevental commented Dec 31, 2020

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

@radarhere
Copy link
Member

radarhere commented Mar 2, 2022

This issue is more complex to resolve than I initially thought, and there is not even a consensus that it should be fixed.

@Yay295
Copy link
Contributor

Yay295 commented Sep 1, 2022

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Pillow
  
In progress
Development

No branches or pull requests

5 participants