Python: lectura y escritura de imágenes en color TIFF de 16 bits, tres canales

¿Alguien tiene un método para importar una imagen TIFF de 16 bits por canal y 3 canales en Python?

Todavía tengo que encontrar un método que conserve la profundidad de 16 bits por canal al tratar con el formato TIFF. Espero que alguna alma útil tenga una solución.

Aquí hay una lista de lo que he intentado hasta ahora sin éxito y los resultados:

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 

Hasta ahora, la única solución que he encontrado es convertir la imagen a PNG con ImageMagick. Entonces el bog standard matplotlib.pyplot.imread lee el archivo PNG sin ningún problema.

Otro problema que tengo es guardar las matrices numpy como archivos PNG de 16 bits que hasta ahora tampoco han sido sencillos.

Tiene una funcionalidad limitada, especialmente cuando se trata de escribir de nuevo en el disco imágenes no RGB, pero el módulo tifffile Christoph Gohlke lee en tifffile de 3 canales de 16 bits sin problemas, simplemente lo probé:

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

Y Photoshop lee sin quejarse de lo que obtengo al hacer:

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

La respuesta de @Jaime funciona.

Mientras tanto, también logré resolver el problema utilizando cv2.imread en OpenCV.

Por defecto, cv2.imread convertirá una imagen de 16 bits, tres canales en a.tif a 8 bits, como se muestra en la pregunta.

cv2.imread acepta un indicador después del nombre de archivo ( cv2.imread(filename[, flags]) ) que especifica el tipo de color de la imagen cargada cf. la documentación :

  1. > 0 devuelve una imagen en color de 3 canales. Esto resulta en la conversión a 8 bits como se muestra arriba.
  2. 0 devuelve una imagen en escala de grises. También resulta en la conversión a 8 bits.
  3. <0 devuelve la imagen como está. Esto devolverá una imagen de 16 bits.

Entonces lo siguiente leerá la imagen sin conversión:

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

Tenga en cuenta que OpenCV devuelve los canales R, G y B en orden inverso, por lo que im[:,:,0] es el canal B, im[:,:,1] el canal G e im[:,:,2] es el Canal r

También he encontrado que cv2.imwrite puede escribir archivos TIFF de 16 bits, tres canales.

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

Comprobando la profundidad de la broca con 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 .... 

He encontrado una alternativa adicional a los dos métodos anteriores.

El paquete scikit-image también puede leer archivos TIFF de 16 bits y tres canales utilizando tifffile.py y FreeImage y especificándolos como el complemento que se utilizará.

Si bien la lectura con tifffile.py se hace más sencillamente de la manera mostrada por @Jaime , pensé que mostraría cómo se usa junto con scikit-image en caso de que alguien quiera hacerlo de esta manera.

Para cualquier persona que use Ubuntu, FreeImage está disponible como libfreeimage3 usando apt .

Si se usa la opción tifffile.py plugin, se debe copiar tifffile.py en el directorio skimage / io / _plugins (f.ex. en Ubuntu, la ruta completa en mi caso era /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) 

Escribiendo archivos TIFF:

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

Al verificar la b.tif c.tif b.tif y c.tif usando ImageMagick, se muestra que cada canal en ambas imágenes es de 16 bits.

Para mí las alternativas anteriores no funcionaron. He utilizado gdal con éxito para leer imágenes de 16 bits de 1 GB.

Puedes abrir una imagen con algo como esto:

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

Hay una lista de buzos admitidos que puede usar para escribir los datos.

Recomiendo usar los enlaces de python para OpenImageIO, es el estándar para tratar con varios formatos de imagen en el dominio vfx (que generalmente son 16 / 32bit).

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