Grant Petty
Grant Petty

Reputation: 1271

Converting float32 to bit-equivalent int32

The Pillow module in Python insists on opening a 32-bit/pixel TIFF file I have as if the pixels were of type float32, whereas I believe the correct interpretation is unsigned int32. If I go ahead and load the data into a 640x512 array of type float32, how can I retype it as uint32 while preserving the underlying binary representation?

In Fortran and C, it's easy to have pointers or data structures of different type pointing to the same block of physical memory so that the raw memory contents can be easily be interpreted according to whatever type I want. Is there an equivalent procedure in Python?

Sample follows (note that I have no information about compression etc.; the file in question was extracted by a commercial software program from a proprietary file format):

from PIL import Image

infile = "20181016_071207_367_R.tif"        
im = Image.open(infile)

data = np.array(im.getdata())
print(data)

[ -9.99117374 -10.36103535 -9.80696869 ... -18.41988373 -18.35027885 -18.69905663]

Upvotes: 1

Views: 2890

Answers (2)

Craig
Craig

Reputation: 4855

The answer, in this case, is that Pillow is loading the image with the correct type (float 32) as specified in the image exported from the thermal camera. There is no need to cast the image to integer, and doing so would cause an incorrect result.

Upvotes: 0

KT.
KT.

Reputation: 11440

Assuming you have im.mode originally equal to F, you can force Pillow to re-load the same data under a different mode (an very unusual desire indeed) in a somewhat hackish way like that:

imnew = im.convert(mode='I')
imnew.frombytes(im.tobytes())

More generally (outside the context of PIL), whenever you encounter the need to deal with raw memory representation in Python, you should usually rely on numpy or Python's built-in memoryview class with the struct module.

Here is an example of reinterpreting an array of numpy float32 as int32:

a = np.array([1.0, 2.0, 3.0], dtype='float32')
a_as_int32 = a.view('int32')

Here is an example of doing the same using memoryview:

# Create a memory buffer
b = bytearray(4*3)

# Write three floats
struct.pack_into('fff', b, 0, *[1.0, 2.0, 3.0])

# View the same memory as three ints
mem_as_ints = memoryview(b).cast('I')

Upvotes: 2

Related Questions