web-dev-qa-db-fra.com

Python: lecture et écriture d'images couleur TIFF 16 bits, trois canaux

Quelqu'un a-t-il une méthode pour importer une image TIFF 3 canaux 16 canaux par canal en Python?

Je n'ai pas encore trouvé de méthode qui préserve la profondeur de 16 bits par canal pour le format TIFF. J'espère qu'une âme utile aura une solution.

Voici une liste de ce que j'ai essayé jusqu'à présent sans succès et des résultats:

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

Jusqu'à présent, la seule solution que j'ai trouvée consiste à convertir l'image au format PNG avec ImageMagick. Ensuite, le standard bogue matplotlib.pyplot.imread lit le fichier PNG sans aucun problème. 

Un autre problème que j'ai est de sauvegarder tous les tableaux numpy sous forme de fichiers PNG 16 bits, ce qui n’a pas encore été simple.

23
Lars Chr

Ses fonctionnalités sont limitées, en particulier lorsqu'il s'agit d'écrire des images non RVB sur disque, mais le module tifffile de Christoph Gohlke lit en TIFF 16 bits à 3 canaux sans aucun problème, je viens de le tester:

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

Et Photoshop lit sans se plaindre de ce que je reçois en faisant:

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

La réponse de @Jaime fonctionne.

Entre-temps, j'ai également résolu le problème en utilisant cv2.imread dans OpenCV.

Par défaut, cv2.imread convertira une image 16 bits à trois canaux dans a.tif en 8 bits, comme indiqué dans la question.

cv2.imread accepte un drapeau après le nom de fichier (cv2.imread(filename[, flags])) qui spécifie le type de couleur de l'image chargée, cf. la documentation :

  1. > 0 renvoie une image couleur à 3 canaux. Cela se traduit par une conversion en 8 bits, comme indiqué ci-dessus.
  2. 0 renvoie une image en niveaux de gris. Il en résulte également une conversion en 8 bits.
  3. <0 renvoie l'image telle quelle. Ceci renverra une image 16 bits.

Ainsi, les éléments suivants liront l'image sans conversion:

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

Notez que OpenCV renvoie les canaux R, V et B dans l’ordre inverse, de sorte que im[:,:,0] est le canal B, im[:,:,1] le canal G et im[:,:,2] est le canal R.

J'ai également constaté que cv2.imwrite peut écrire des fichiers TIFF 16 bits sur trois canaux.

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

Vérification de la profondeur de bits avec 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

J'ai trouvé une alternative supplémentaire aux deux méthodes ci-dessus.

Le paquet scikit-image peut également lire des fichiers TIFF 16 bits à trois canaux en utilisant tifffile.py et FreeImage et en les spécifiant comme plug-in à utiliser.

Bien que la lecture avec tifffile.py se fasse probablement plus simplement de la manière indiquée par @Jaime , je pensais montrer comment il était utilisé avec scikit-image au cas où quelqu'un voudrait le faire de cette manière.

Pour tous ceux qui utilisent Ubuntu, FreeImage est disponible sous la forme libfreeimage3 en utilisant apt.

Si l'option tifffile.py est utilisée, le fichier tifffile.py doit être copié dans le répertoire skimage/io/_plugins (par exemple, sur Ubuntu, le chemin d'accès complet dans mon cas était /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)

Écrire des fichiers TIFF:

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

Vérifier la taille en bits de b.tif et c.tif à l’aide de ImageMagick montre que chaque canal des 16 images est en 16 bits.

10
Lars Chr

Pour moi, les alternatives précédentes ne fonctionnaient pas. J'ai utilisé gdal avec succès pour lire des images 16 bits de 1 Go. 

Vous pouvez ouvrir une image avec quelque chose comme ça:

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

Il existe une liste de plongeurs pris en charge que vous pouvez utiliser pour écrire les données.

4
G M

Je recommande d’utiliser les liaisons python à OpenImageIO, c’est le standard pour traiter avec divers formats d’image dans le domaine vfx (qui sont généralement 16/32 bits).

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