Working with TIFFs (import, export) in Python using numpy

PythonNumpyPython Imaging-LibraryTiff

Python Problem Overview


I need a python method to open and import TIFF images into numpy arrays so I can analyze and modify the pixel data and then save them as TIFFs again. (They are basically light intensity maps in greyscale, representing the respective values per pixel)

I couldn't find any documentation on PIL methods concerning TIFF. I tried to figure it out, but only got "bad mode" or "file type not supported" errors.

What do I need to use here?

Python Solutions


Solution 1 - Python

First, I downloaded a test TIFF image from this page called a_image.tif. Then I opened with PIL like this:

>>> from PIL import Image
>>> im = Image.open('a_image.tif')
>>> im.show()

This showed the rainbow image. To convert to a numpy array, it's as simple as:

>>> import numpy
>>> imarray = numpy.array(im)

We can see that the size of the image and the shape of the array match up:

>>> imarray.shape
(44, 330)
>>> im.size
(330, 44)

And the array contains uint8 values:

>>> imarray
array([[  0,   1,   2, ..., 244, 245, 246],
       [  0,   1,   2, ..., 244, 245, 246],
       [  0,   1,   2, ..., 244, 245, 246],
       ..., 
       [  0,   1,   2, ..., 244, 245, 246],
       [  0,   1,   2, ..., 244, 245, 246],
       [  0,   1,   2, ..., 244, 245, 246]], dtype=uint8)

Once you're done modifying the array, you can turn it back into a PIL image like this:

>>> Image.fromarray(imarray)
<Image.Image image mode=L size=330x44 at 0x2786518>

Solution 2 - Python

I use matplotlib for reading TIFF files:

import matplotlib.pyplot as plt
I = plt.imread(tiff_file)

and I will be of type ndarray.

According to the documentation though it is actually PIL that works behind the scenes when handling TIFFs as matplotlib only reads PNGs natively, but this has been working fine for me.

There's also a plt.imsave function for saving.

Solution 3 - Python

You could also use GDAL to do this. I realize that it is a geospatial toolkit, but nothing requires you to have a cartographic product.

Link to precompiled GDAL binaries for windows (assuming windows here) http://www.gisinternals.com/sdk/

To access the array:

from osgeo import gdal

dataset = gdal.Open("path/to/dataset.tiff", gdal.GA_ReadOnly)
for x in range(1, dataset.RasterCount + 1):
    band = dataset.GetRasterBand(x)
    array = band.ReadAsArray()


Solution 4 - Python

PyLibTiff worked better for me than PIL, which as of May 2022 still doesn't support color images with more than 8 bits per color.

from libtiff import TIFF

tif = TIFF.open('filename.tif') # open tiff file in read mode
# read an image in the current TIFF directory as a numpy array
image = tif.read_image()

# read all images in a TIFF file:
for image in tif.iter_images(): 
    pass

tif = TIFF.open('filename.tif', mode='w')
tif.write_image(image)

You can install PyLibTiff with

pip3 install numpy libtiff

The readme of PyLibTiff also mentions the tifffile library but I haven't tried it.

Solution 5 - Python

In case of image stacks, I find it easier to use scikit-image to read, and matplotlib to show or save. I have handled 16-bit TIFF image stacks with the following code.

from skimage import io
import matplotlib.pyplot as plt

# read the image stack
img = io.imread('a_image.tif')
# show the image
plt.imshow(img,cmap='gray')
plt.axis('off')
# save the image
plt.savefig('output.tif', transparent=True, dpi=300, bbox_inches="tight", pad_inches=0.0)

Solution 6 - Python

You can also use pytiff of which I am the author.

import pytiff

with pytiff.Tiff("filename.tif") as handle:
    part = handle[100:200, 200:400]

# multipage tif
with pytiff.Tiff("multipage.tif") as handle:
    for page in handle:
        part = page[100:200, 200:400]

It's a fairly small module and may not have as many features as other modules, but it supports tiled TIFFs and BigTIFF, so you can read parts of large images.

Solution 7 - Python

There is a nice package called tifffile which makes working with .tif or .tiff files very easy.

Install package with pip

pip install tifffile

Now, to read .tif/.tiff file in numpy array format:

from tifffile import tifffile
image = tifffile.imread('path/to/your/image')
# type(image) = numpy.ndarray

If you want to save a numpy array as a .tif/.tiff file:

tifffile.imwrite('my_image.tif', my_numpy_data, photometric='rgb')

or

tifffile.imsave('my_image.tif', my_numpy_data)

You can read more about this package here.

Solution 8 - Python

Using cv2

import cv2
image = cv2.imread(tiff_file.tif)
cv2.imshow('tif image',image)

Solution 9 - Python

I recommend using the python bindings to OpenImageIO, it's the standard for dealing with various image formats in the vfx world. I've ovten found it more reliable in reading various compression types compared to PIL.

import OpenImageIO as oiio
input = oiio.ImageInput.open ("/path/to/image.tif")

Solution 10 - Python

if you want save tiff encoding with geoTiff. You can use rasterio package

a simple code:

import rasterio

out = np.random.randint(low=10, high=20, size=(360, 720)).astype('float64')
new_dataset = rasterio.open('test.tiff', 'w', driver='GTiff',
                            height=out.shape[0], width=out.shape[1],
                            count=1, dtype=str(out.dtype),
                            )
new_dataset.write(out, 1)
new_dataset.close()

for more detail about numpy 2 GEOTiff .you can click this: https://gis.stackexchange.com/questions/279953/numpy-array-to-gtiff-using-rasterio-without-source-raster

Solution 11 - Python

Another method of reading tiff files is using tensorflow api

import tensorflow_io as tfio
image = tf.io.read_file(image_path)
tf_image = tfio.experimental.image.decode_tiff(image)
print(tf_image.shape)

Output:

(512, 512, 4)

tensorflow documentation can be found here

For this module to work, a python package called tensorflow-io has to installed.

Athough I couldn't find a way to look at the output tensor (after converting to nd.array), as the output image had 4 channels. I tried to convert using cv2.cvtcolor() with the flag cv2.COLOR_BGRA2BGR after looking at this post but still wasn't able to view the image.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJakobView Question on Stackoverflow
Solution 1 - PythonjterraceView Answer on Stackoverflow
Solution 2 - PythonMichael BrennanView Answer on Stackoverflow
Solution 3 - PythonJzl5325View Answer on Stackoverflow
Solution 4 - PythonBoris VerkhovskiyView Answer on Stackoverflow
Solution 5 - PythonClaireView Answer on Stackoverflow
Solution 6 - PythonhnflView Answer on Stackoverflow
Solution 7 - Pythonjd95View Answer on Stackoverflow
Solution 8 - PythonKukeshView Answer on Stackoverflow
Solution 9 - PythonzenoView Answer on Stackoverflow
Solution 10 - PythonyuanzzView Answer on Stackoverflow
Solution 11 - PythonAnik DeView Answer on Stackoverflow