Trabajar con TIFF (importar, exportar) en Python usando numpy

84

Necesito un método de Python para abrir e importar imágenes TIFF en matrices numerosas para poder analizar y modificar los datos de píxeles y luego guardarlos como TIFF nuevamente. (Básicamente son mapas de intensidad de luz en escala de grises, que representan los respectivos valores por píxel)

No pude encontrar ninguna documentación sobre los métodos PIL relacionados con TIFF. Traté de averiguarlo, pero solo obtuve errores de "modo incorrecto" o "tipo de archivo no admitido".

¿Qué necesito usar aquí?

Jakob
fuente

Respuestas:

103

Primero, descargué una imagen TIFF de prueba de esta página llamada a_image.tif. Luego abrí con PIL así:

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

Esto mostró la imagen del arco iris. Para convertir a una matriz numpy, es tan simple como:

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

Podemos ver que el tamaño de la imagen y la forma de la matriz coinciden:

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

Y la matriz contiene uint8valores:

>>> 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)

Una vez que haya terminado de modificar la matriz, puede volver a convertirla en una imagen PIL como esta:

>>> Image.fromarray(imarray)
<Image.Image image mode=L size=330x44 at 0x2786518>
terraza
fuente
4
Tengo problemas con los tipos de datos. funciona bien para algunos, fe si tengo números numpy.int16 en mi matriz, pero para numpy.uint16 image.fromarray produce: "TypeError: No se puede manejar este tipo de datos"
Jakob
4
Mirando el origen de fromarray, no parece que maneje arreglos de 16 bits sin firmar.
jterrace
@Jakob a partir de junio de 2020, PIL no admite imágenes en color con más de 8 bits por color , tendrá que usar una biblioteca diferente (o contribuir con la funcionalidad usted mismo).
Boris
56

Yo uso matplotlib para leer archivos TIFF:

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

y I será de tipo ndarray.

De acuerdo con la documentación, aunque en realidad es PIL el que funciona detrás de escena cuando se manejan TIFF, ya que matplotlib solo lee PNG de forma nativa, pero esto me ha funcionado bien.

También hay una plt.imsavefunción para guardar.

Michael Brennan
fuente
¡Esta es, con mucho, la forma más fácil de trabajar con TIFF! Probé una docena de formas y todo esto fue el boleto. ¡Vota a favor seguro!
zachd1_618
¿Qué tal la parte de visualización?
Monica Heddneck
5
Parece cambió matplotlib estrategia:ValueError: Only know how to handle extensions: ['png']; with Pillow installed matplotlib can handle more images
strpeter
17

También puede usar GDAL para hacer esto. Me doy cuenta de que es un conjunto de herramientas geoespaciales, pero nada requiere que tengas un producto cartográfico.

Enlace a los binarios GDAL precompilados para Windows (asumiendo Windows aquí) http://www.gisinternals.com/sdk/

Para acceder a la matriz:

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()
Jzl5325
fuente
¿Es el código anterior para un solo TIF o TIF de varias páginas? Me gustaría usar gdal para cargar pilas tiff de 16 bits en nparrays.
user391339
Esto debería leer en el tipo de datos de entrada o mover todo a float64 de numpy. Puede agregar una .astype(sometype)llamada al final de la ReadAsArray()llamada para transmitir. No estoy seguro si esto hace una copia (simplemente no lo he probado).
Jzl5325
@Chikinn De la revisión: stackoverflow.com/review/suggested-edits/17962780 xrange no es un error tipográfico, xrangees la versión de Python 2 de range. Acepté esta edición porque Python 3 todavía se está mejorando activamente, mientras que Python 2 no.
abccd
12

pylibtiff funcionó mejor para mí que PIL, que a partir de junio de 2020 no admite imágenes en color con más de 8 bits por color .

from libtiff import TIFF

tif = TIFF.open('filename.tif') # open tiff file in read mode
# read an image in the currect 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)

Puede instalar pylibtiff con

pip3 install numpy libtiff

El archivo léame de pylibtiff también menciona tifffile, pero no lo he probado y aunque es aparentemente de código abierto, no creo que el código esté disponible en ninguna parte (además de extraerlo manualmente del paquete PyPI).

Boris
fuente
2
Esto es muy bueno. Por ahora, tifffile está incluido en SciKit skimage.external.tifffile pero también se puede importar como un módulo si descarga tifffile.py del Sr. Christoph Gohlke
lesolorzanov
7

También puede usar pytiff del que soy autor.

    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]

Es un módulo bastante pequeño y puede que no tenga tantas funciones como otros módulos, pero admite tiffs en mosaico y bigtiff, por lo que puede leer partes de imágenes grandes.

hnfl
fuente
¡Esta característica es exactamente lo que necesito! (Ser capaz de leer una pequeña parte de un archivo grande). Sin embargo, cuando intento instalarlo con pip
aparece
Si crea un problema con el mensaje de error, veré si puedo resolver el problema.
hnfl
Sí, también estoy interesado, pero también recibí un error cuando intenté instalarlo. Lo hice por medio de pip, en Windows y en Ubuntu. ¡Es una pena que no funcione! He creado un problema aquí: github.com/FZJ-INM1-BDA/pytiff/issues/15
Dobedani
6

En el caso de las pilas de imágenes, me resulta más fácil de usar scikit-imagepara leer y matplotlibmostrar o guardar. He manejado pilas de imágenes TIFF de 16 bits con el siguiente código.

from skimage import io
import matplotlib.pyplot as plt

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

Recomiendo usar los enlaces de Python a OpenImageIO, es el estándar para tratar con varios formatos de imagen en el mundo de vfx. A menudo lo he encontrado más confiable para leer varios tipos de compresión en comparación con PIL.

import OpenImageIO as oiio
input = oiio.ImageInput.open ("/path/to/image.tif")
Zenón
fuente
Casi imposible de instalar en Windows a menos que ya tenga compiladores.
Jimmy Carter