Arbeiten mit TIFFs (Importieren, Exportieren) in Python mit numpy

84

Ich benötige eine Python-Methode, um TIFF-Bilder zu öffnen und in Numpy-Arrays zu importieren, damit ich die Pixeldaten analysieren und ändern und sie dann erneut als TIFFs speichern kann. (Es handelt sich im Grunde genommen um Lichtintensitätskarten in Graustufen, die die jeweiligen Werte pro Pixel darstellen.)

Ich konnte keine Dokumentation zu PIL-Methoden in Bezug auf TIFF finden. Ich habe versucht, es herauszufinden, habe aber nur die Fehler "Bad Mode" oder "Dateityp nicht unterstützt" erhalten.

Was muss ich hier verwenden?

Jakob
quelle

Antworten:

103

Zuerst habe ich ein Test-TIFF-Bild von dieser Seite mit dem Namen heruntergeladen a_image.tif. Dann habe ich mit PIL so geöffnet:

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

Dies zeigte das Regenbogenbild. Das Konvertieren in ein Numpy-Array ist so einfach wie:

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

Wir können sehen, dass die Größe des Bildes und die Form des Arrays übereinstimmen:

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

Und das Array enthält uint8Werte:

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

Sobald Sie das Array geändert haben, können Sie es wieder in ein PIL-Image wie das folgende umwandeln:

>>> Image.fromarray(imarray)
<Image.Image image mode=L size=330x44 at 0x2786518>
jterrace
quelle
4
Ich habe Probleme mit Datentypen. funktioniert gut für einige, zB wenn ich numpy.int16 Zahlen in meinem Array habe, aber für numpy.uint16 image.fromarray ergibt: "TypeError: Kann diesen Datentyp nicht verarbeiten"
Jakob
4
Wenn man sich die Quelle von fromarray ansieht, sieht es nicht so aus, als würde es vorzeichenlose 16-Bit-Arrays verarbeiten.
Jterrace
@Jakob ab Juni 2020 PIL unterstützt keine Farbbilder mit mehr als 8 Bit pro Farbe . Sie müssen eine andere Bibliothek verwenden (oder die Funktionalität selbst bereitstellen).
Boris
56

Ich benutze matplotlib zum Lesen von TIFF-Dateien:

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

und Iwird vom Typ sein ndarray.

Laut der Dokumentation ist es tatsächlich PIL, das hinter den Kulissen funktioniert, wenn TIFFs als Matplotlib behandelt werden, die PNGs nur nativ lesen, aber das hat für mich gut funktioniert.

Es gibt auch eine plt.imsaveFunktion zum Speichern.

Michael Brennan
quelle
Dies ist bei weitem der einfachste Weg, mit TIFFs zu arbeiten! Versuchte ein Dutzend Wege und das alles war das Ticket. Upvote sicher!
zachd1_618
Wie wäre es mit dem Betrachtungsteil?
Monica Heddneck
4
Es scheint, Matplotlib Strategie geändert:ValueError: Only know how to handle extensions: ['png']; with Pillow installed matplotlib can handle more images
Strpeter
17

Sie können dazu auch GDAL verwenden. Mir ist klar, dass es sich um ein Geodaten-Toolkit handelt, aber für nichts ist ein kartografisches Produkt erforderlich.

Link zu vorkompilierten GDAL-Binärdateien für Windows (vorausgesetzt, Windows hier) http://www.gisinternals.com/sdk/

So greifen Sie auf das Array zu:

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
quelle
ist der obige Code für ein einzelnes TIF oder ein mehrseitiges TIF? Ich möchte gdal verwenden, um 16-Bit-TIFF-Stapel in Nparrays zu laden.
user391339
Dies sollte entweder den Eingabedatentyp einlesen oder alles in numpys float64 verschieben. Sie können .astype(sometype)am Ende des zu besetzenden Anrufs einen Anruf hinzufügen ReadAsArray(). Nicht sicher, ob dies eine Kopie macht (nur nicht getestet).
Jzl5325
@Chikinn Aus Review: stackoverflow.com/review/suggested-edits/17962780 xrange ist kein Tippfehler, xrangeist die Python 2-Version von range. Ich habe diese Änderung akzeptiert, da Python 3 immer noch aktiv verbessert wird, Python 2 jedoch nicht.
Abccd
12

pylibtiff hat bei mir besser funktioniert als PIL, das ab Juni 2020 keine Farbbilder mit mehr als 8 Bit pro Farbe unterstützt .

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)

Sie können pylibtiff mit installieren

pip3 install numpy libtiff

In der Readme-Datei von pylibtiff wird ebenfalls erwähnt tifffile, aber ich habe es nicht ausprobiert, und obwohl es angeblich Open Source ist, glaube ich nicht, dass der Code irgendwo mehr verfügbar ist (abgesehen davon, dass er manuell aus dem PyPI-Paket extrahiert wurde).

Boris
quelle
2
Das ist sehr gut. Inzwischen ist tifffile in SciKit skimage.external.tifffile enthalten, kann aber auch als Modul importiert werden, wenn Sie tifffile.py von Herrn Christoph Gohlke
lesolorzanov am
7

Sie können auch pytiff verwenden, dessen Autor ich bin.

    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 ist ein ziemlich kleines Modul und verfügt möglicherweise nicht über so viele Funktionen wie andere Module, unterstützt jedoch gekachelte Tiffs und Bigtiffs, sodass Sie Teile großer Bilder lesen können.

hnfl
quelle
Diese Funktion ist genau das, was ich brauche! (In der Lage sein, einen kleinen Teil einer großen Datei zu lesen). Wenn ich jedoch versuche, es
per
Wenn Sie ein Problem mit der Fehlermeldung erstellen , werde ich prüfen, ob ich das Problem herausfinden kann.
hnfl
Ja, ich bin auch interessiert, habe aber auch einen Fehler erhalten, als ich versucht habe, es zu installieren. Ich habe das mittels Pip gemacht - unter Windows und unter Ubuntu. Es ist bedauerlich, dass es nicht funktioniert! Ich habe hier ein Problem erstellt: github.com/FZJ-INM1-BDA/pytiff/issues/15
Dobedani
6

Bei Bildstapeln fällt es mir leichter, sie scikit-imagezu lesen, matplotlibanzuzeigen oder zu speichern. Ich habe 16-Bit-TIFF-Bildstapel mit dem folgenden Code verarbeitet.

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
quelle
0

Ich empfehle die Verwendung der Python-Bindungen für OpenImageIO, dies ist der Standard für den Umgang mit verschiedenen Bildformaten in der vfx-Welt. Ich habe festgestellt, dass es beim Lesen verschiedener Komprimierungsarten im Vergleich zu PIL zuverlässiger ist.

import OpenImageIO as oiio
input = oiio.ImageInput.open ("/path/to/image.tif")
Zeno
quelle
Borderline kann unter Windows nur installiert werden, wenn Sie bereits über Compiler verfügen.
Jimmy Carter