简体   繁体   中英

How does PIL Image save NumPy arrays with non-integer and non-positive values?

I have a NumPy array of size 28 x 280, which contains real number values (both positive and negative values). I am using the following code to save this array to file through a PIL Image -

img = Image.fromarray(img)
img.save(save_path, "PNG")

Now, when I load this saved image using PIL using the following code -

img = Image.open(save_path)
img = np.array(img)
print(img[:,:,0]) # since the image is saved in RGB by default, and the channels are simply all the same, I am printing out only one of the channels
print(img.shape) # printing shape of loaded image for sanity check

The above gives me the following output -

array([[ 0,  0,  0],
       [ 0,  0,  0],
       [ 0,  0,  0],
       [14, 14, 14],
       [ 0,  0,  0],
       [14, 14, 14],
       [ 0,  0,  0],
       [ 2,  2,  2],
       [10, 10, 10],
       [ 0,  0,  0],
       [ 0,  0,  0],
       [ 0,  0,  0],
       [ 6,  6,  6],
       [ 0,  0,  0],
       [19, 19, 19],
       [16, 16, 16],
       [ 0,  0,  0],
       [ 9,  9,  9],
       [14, 14, 14],
       [ 5,  5,  5],
-- omitting the remaining matrix for spatial reasons

The original matrix looks something like the following if that helps -

   1.54009545e+00  1.14122391e-01 -5.44282794e-01 -1.66106954e-01]
 [-2.70073628e+00 -6.25280142e+00  1.77814519e+00 -8.72797012e+00
   9.91206944e-01  6.63580036e+00  6.84081888e+00 -1.18705761e+00
  -4.54479456e+00 -5.26672935e+00  4.91975927e+00 -5.48409176e+00
  -3.93164325e+00  5.19110155e+00  1.26516495e+01  9.93665600e+00
  -5.70824432e+00  5.72582603e-01 -4.31831169e+00 -9.31297874e+00
   2.13714447e-02 -9.82507896e+00 -2.47176766e+00 -1.94778728e+00
  -1.85507727e+00 -8.01630592e+00 -4.42644596e+00  5.74180269e+00]
 [ 3.32923412e+00  1.50732050e+01 -1.01800518e+01  1.85193479e-01
  -1.77801073e+00 -4.91134501e+00 -4.94232035e+00  5.52533197e+00
  -3.84771490e+00 -5.61370182e+00 -2.91945863e+00 -9.53506768e-01
   7.03971624e-01  1.26758552e+00 -1.29794350e+01 -1.08105397e+00
  -5.57984650e-01 -1.50801647e+00 -3.45247960e+00 -6.14299655e-01
  -4.83907032e+00  5.44770575e+00  2.50088573e+00 -2.45785332e+00
  -3.94766003e-01  7.80810177e-01 -1.66951954e+00 -5.23118067e+00]
 [ 1.24226892e+00 -4.30912447e+00  1.14384556e+00 -5.38896322e+00
  -5.95073175e+00  5.03882837e+00  4.15563917e+00 -7.99412632e+00
  -1.68129158e+00 -2.23124218e+00  2.24080634e+00 -5.57195246e-01
  -2.29391623e+00 -2.70431495e+00  9.87635612e+00 -2.90223390e-01
   3.25407982e+00  3.67051101e+00 -2.86848998e+00 -4.53229618e+00
  -3.80941963e+00  3.66697168e+00  3.98574305e+00 -1.50027335e-01
  -8.77485275e+00  2.20300531e+00  4.97666216e+00  2.27730870e+00]]

-- again, omitting large chunks for spatial reasons

Question -

  1. Here, from what I understand, PIL is implicitly converting the reals to uint8 format (0 to 255 pixel values), but I want to know how exactly conversion of reals to uint8 takes place? Are the real pixel values rounded off or truncated to the closest integer, if so, what happens to the negative pixel values?
  2. Also, when I try to visualize the PIL image by simply opening it, it just shows me a black screen, like so - 在此处输入图像描述

But, the weird thing is that, when I multiply the np array by 255, like so - img = img * 255 , and then save it, it shows some values, like so -

在此处输入图像描述

Is it just that the pixel values initially are too light to be perceived by my eyes? I think so, but I just want to confirm.

If you want to save negative and floating point data as an image, you should probably use TIFF format.

PNG is only able to store unsigned integer data at up to 16-bit/channel, ie in range 0..65535.


Here is a demonstration of saving positive and negative floating point numbers in a TIFF and then retrieving them:

import numpy as np
from PIL import Image

# Set height and width
h, w = 5, 4

# Create image from Numpy array of float32 and save as TIFF
naA = np.linspace(-1000, 1000, h*w, dtype=np.float32).reshape((h,w))
Image.fromarray(naA).save('floats.tif')

# Read back image and compare
imB = Image.open('floats.tif')
naB = np.array(imB)

Now print both and check same:

In [101]: naA
Out[101]: 
array([[-1000.     ,  -894.7368 ,  -789.4737 ,  -684.2105 ],
       [ -578.9474 ,  -473.6842 ,  -368.42105,  -263.1579 ],
       [ -157.89473,   -52.63158,    52.63158,   157.89473],
       [  263.1579 ,   368.42105,   473.6842 ,   578.9474 ],
       [  684.2105 ,   789.4737 ,   894.7368 ,  1000.     ]],
      dtype=float32)

In [102]: naB
Out[102]: 
array([[-1000.     ,  -894.7368 ,  -789.4737 ,  -684.2105 ],
       [ -578.9474 ,  -473.6842 ,  -368.42105,  -263.1579 ],
       [ -157.89473,   -52.63158,    52.63158,   157.89473],
       [  263.1579 ,   368.42105,   473.6842 ,   578.9474 ],
       [  684.2105 ,   789.4737 ,   894.7368 ,  1000.     ]],
      dtype=float32)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM