python-pillow / python-pillow/Pillow

Image conversion should scale pixel values accordingly

Open
#3,159 10 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Conversion NumPy
Dominant language
Python
Stars
13.8k
Forks
2.5k
Avg merge
2d 8h
Merged PRs (30d)
89

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No source file or test is named. Reproduce the reported conversions from 16-bit and floating-point grayscale images to 'L', then trace Pillow's image-mode conversion entry points; done means values are scaled to the destination range rather than clamped, with coverage for the examples shown.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
computer-graphics
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.