it-swarm.com.de

Python: Lesen und Schreiben von TIFF-Bildern mit 16 Bit, drei Kanälen und Farbe

Hat jemand eine Methode zum Importieren eines 16-Bit-TIFF-Bilds mit 16 Bit pro Kanal in Python?

Ich muss noch eine Methode finden, die die 16-Bit-Tiefe pro Kanal beim TIFF-Format beibehält. Ich hoffe, dass eine hilfreiche Seele eine Lösung hat.

Hier ist eine Liste von dem, was ich bisher ohne Erfolg ausprobiert habe, und die Ergebnisse:

import numpy as np
import PIL.Image as Image
import libtiff
import cv2

im = Image.open('a.tif')
# IOError: cannot identify image file

tif = libtiff.TIFF.open('a.tif')
im = tif.read_image()
# im only contains one of the three channels. im.dtype is uint16 as desired.
im = []
for i in tif.iter_images():
    # still only returns one channel

im = np.array(cv2.imread('a.tif'))
# im.dtype is uint8 and not uint16 as desired.
# specifying dtype as uint16 does not correct this

Die einzige Lösung, die ich bisher gefunden habe, ist, das Image mit ImageMagick in PNG zu konvertieren. Dann liest der Sumpfstandard matplotlib.pyplot.imread die PNG-Datei ohne Probleme. 

Ein anderes Problem, das ich habe, ist das Speichern beliebiger numpy-Arrays als 16-Bit-PNG-Dateien, was bisher auch nicht einfach war.

23
Lars Chr

Es hat eine eingeschränkte Funktionalität, insbesondere wenn es um das Zurückschreiben auf Festplatten ohne RGB-Bilder geht, aber das Modul tifffile - von Christoph Gohlke liest problemlos 3-Kanal-16-Bit-TIFFs.

>>> import tifffile as tiff
>>> a = tiff.imread('Untitled-1.tif')
>>> a.shape
(100L, 100L, 3L)
>>> a.dtype
dtype('uint16')

Und Photoshop liest ohne zu klagen, was ich davon bekomme:

>>> tiff.imsave('new.tiff', a)
28
Jaime

Die Antwort von @Jaime funktioniert.

Inzwischen konnte ich das Problem auch mit cv2.imread in OpenCV lösen.

Standardmäßig konvertiert cv2.imread ein 16-Bit-Bild mit drei Kanälen in a.tif in 8 Bit, wie in der Frage gezeigt.

cv2.imread akzeptiert nach dem Dateinamen (cv2.imread(filename[, flags])) ein Flag, das den Farbtyp des geladenen Bildes angibt. die Dokumentation :

  1. > 0 gibt ein 3-Kanal-Farbbild zurück. Dies führt zu einer Umwandlung in 8 Bit, wie oben gezeigt.
  2. 0 gibt ein Graustufenbild zurück. Führt auch zur Umwandlung in 8 Bit.
  3. <0 gibt das Bild so zurück, wie es ist. Diese liefert ein 16-Bit-Bild.

Das folgende Bild wird also ohne Konvertierung gelesen:

>>> im = cv2.imread('a.tif', -1)
>>> im.dtype
dtype('uint16')
>>> im.shape
(288, 384, 3)

Beachten Sie, dass OpenCV die R-, G- und B-Kanäle in umgekehrter Reihenfolge zurückgibt, sodass im[:,:,0] der B-Kanal, im[:,:,1] der G-Kanal und im[:,:,2] der R-Kanal ist.

Ich habe auch festgestellt, dass cv2.imwrite 16-Bit-TIFF-Dateien mit drei Kanälen schreiben kann.

>>> cv2.imwrite('out.tif', im)

Überprüfen der Bittiefe mit ImageMagick:

$ identify -verbose out.tif
  Format: TIFF (Tagged Image File Format)
  Class: DirectClass
  Geometry: 384x288+0+0
  Resolution: 72x72
  Print size: 5.33333x4
  Units: PixelsPerInch
  Type: TrueColor
  Base type: TrueColor
  Endianess: MSB
  Colorspace: sRGB
  Depth: 16-bit
  Channel depth:
    red: 16-bit
    green: 16-bit
    blue: 16-bit
  ....
22
Lars Chr

Ich habe eine zusätzliche Alternative zu den beiden obigen Methoden gefunden.

Das scikit-image -Paket kann auch 16-Bit-TIFF-Dateien mit drei Kanälen lesen, wobei sowohl tifffile.py als auch FreeImage verwendet und diese als zu verwendendes Plugin angegeben werden.

Während das Lesen mit tifffile.py wahrscheinlich einfacher in der von @Jaime gezeigten Art erfolgt, dachte ich, ich würde zeigen, wie es zusammen mit dem Scikit-Image verwendet wird, falls jemand es auf diese Weise machen möchte.

Für alle, die Ubuntu verwenden, ist FreeImage als libfreeimage3 mit apt verfügbar.

Wenn die Option tifffile.py plugin verwendet wird, muss die Datei tifffile.py in das Verzeichnis skimage/io/_plugins kopiert werden (z. B. unter Ubuntu war der vollständige Pfad in meinem Fall /usr/local/lib/python2.7/dist-packages/skimage/io/_plugins/).

>>> import skimage.io
>>> im = skimage.io.imread('a.tif', plugin='tifffile')
>>> im.dtype
dtype('uint16')
>>> im.shape
(288, 384, 3)
>>> im = skimage.io.imread('a.tif', plugin='freeimage')
>>> im.dtype
dtype('uint16')
>>> im.shape
(288, 384, 3)

TIFF-Dateien schreiben:

>>> skimage.io.imsave('b.tif', im, plugin='tifffile')
>>> skimage.io.imsave('c.tif', im, plugin='freeimage')

Wenn Sie die Bit-Tiefe von b.tif und c.tif mit ImageMagick überprüfen, wird angezeigt, dass jeder Kanal in beiden Bildern 16 Bit hat.

10
Lars Chr

Bei mir funktionierten die bisherigen Alternativen nicht. Ich habe gdal verwendet, um 16Bit-Bilder von 1 GB erfolgreich zu lesen. 

Sie können ein Bild folgendermaßen öffnen:

from osgeo import gdal
import numpy as np
ds = gdal.Open("name.tif")
channel = np.array(ds.GetRasterBand(1).ReadAsArray())

Es gibt eine Liste von unterstützten Tauchern , die Sie zum Schreiben der Daten verwenden können.

4
G M

Ich empfehle die Verwendung der Python-Bindungen für OpenImageIO. Dies ist der Standard für den Umgang mit verschiedenen Bildformaten in der vfx-Domäne (normalerweise 16/32-Bit).

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