6

I want to use TIFF images to effectively save large arrays of measurement data. With setting them to mode="I;16" (corresponding to my 16 bit data range), they yield 2MB files (~1000x1000 "pixel"). Which is good.

However I am having troubles reconverting them into arrays when it comes to analysing them. For 32bit data (-> "I") the numpy.array command works fine. In case of "I;16" the result is a 0D numpy array with the TIFF as the [0,0] entry.

Is there a way to get that to work? I would really like to avoid using 32bit images, as I don't need the range and it doubles the HDD space required (lots and lots of those measurements planned...)

Jakob
  • 1,897
  • 2
  • 16
  • 17
  • 1
    Can you show us the code how you load the image? Are you using PIL's `Image` class? – Ferdinand Beyer Oct 07 '11 at 08:45
  • I use the Image class, and to load the images I simply use Image.open("im.tif") – Jakob Oct 07 '11 at 08:58
  • 1
    PIL bug: http://stackoverflow.com/questions/7247371/python-and-16-bit-tiff – mankoff Oct 09 '11 at 01:11
  • Thanks for the hint mankoff, but I still don't quite get it. So I have to convert it to 32bit -> mode 'I' right? When I do that and load the result into a numpy array I get wrong data (a full uint16 scale, from 0 to 65000something). I don't want to work with images, I need to convert the TIFF grayscale into the actual values! Is the answer in there? – Jakob Oct 10 '11 at 08:41
  • Maybe I should elaborate what it is that I am doing here: I get the data in a numpy array, rescale it a bit, to use the 16bit dataspace better (log10, linear expansion), round and set it to numpy.int16. My range in the array is about -20000 < x < +20000 then. Generate my Image with PIL.fromarray (automatic mode "I;16") and save it. Those are the images/datamaps I will open and reconvert later on. – Jakob Oct 10 '11 at 08:50

3 Answers3

6

This should work (pillow/PIL solution, slow for 16-bit image, see below).

from PIL import Image
import numpy as np

data = np.random.randint(0,2**16-1,(1000,1000))
im = Image.fromarray(data)
im.save('test.tif')

im2 = Image.open('test.tif')
data2 = np.array(im2.getdata()).reshape(im2.size[::-1])

Another solution using tifffile by C. Gohlke (very fast):

import tifffile

fp = r'path\to\image\image.tif'

with tifffile.TIFFfile(fp) as tif:
    data = tif.asarray()
otterb
  • 2,660
  • 2
  • 29
  • 48
  • 2
    I managed to somehow not notice your answer before I posted mine. I agree, this is the best workaround, but I think you need to reorder the size of the reshape... It should be `...reshape(im2.size[::-1])` – Joe Kington Oct 10 '11 at 18:53
  • Right! im.size => (width, height) but we want our numpy array to be in (height, width). Thanks for the correction. – otterb Oct 11 '11 at 09:34
  • Using a relatively modern version of PIL (2.6.1), this doesn't seem to work. The fromarray() method throws an exception `Cannot handle this data type`. Thanks for the tifffile reference though, I'll try that. – gatoatigrado Dec 31 '14 at 23:02
  • oh, snap, tifffile is really fast!! Thanks! – gatoatigrado Dec 31 '14 at 23:15
3

You could use GDAL + Numpy/Scipy to read raster images with 16bit channel data:

import gdal
tif = gdal.Open('path.tif')
arr = tif.ReadAsArray()
xyz-123
  • 2,227
  • 4
  • 21
  • 27
0

Convert an (ImageJ) TIFF to an 8 bit numpy array

im = numpy.array(Image.open('my.tiff'))
n = (im / numpy.amax(im) * 255).astype(numpy.uint8)
Adam Gradzki
  • 139
  • 2
  • 9