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.
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)
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 :
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
....
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.
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.
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")