Python: чтение и запись TIFF 16-битных, трехканальных, цветных изображений
Есть ли у кого-нибудь метод импорта 16-битного канала, трехканального TIFF-изображения в Python?
Мне еще предстоит найти метод, который сохранит 16-битную глубину на канал при работе с форматом TIFF. Я надеюсь, что у некоторой полезной души будет решение.
Вот список того, что я пробовал до сих пор без успеха и результатов:
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
Пока единственным решением, которое я нашел, является преобразование изображения в PNG с ImageMagick. Тогда стандарт болота matplotlib.pyplot.imread
без проблем читает PNG файл.
Еще одна проблема, которую я имею, заключается в том, чтобы сохранить любые массивы numpy в виде 16-битных PNG файлов, которые до сих пор не были простыми.
Ответы
Ответ 1
Он имеет ограниченную функциональность, особенно когда речь заходит о записи на диски без RGB-изображений, но модуль Christoph Gohlke tifffile
читается в 3 канальные 16-битные TIFF без проблем, я только что протестировал его:
>>> import tifffile as tiff
>>> a = tiff.imread('Untitled-1.tif')
>>> a.shape
(100L, 100L, 3L)
>>> a.dtype
dtype('uint16')
И Photoshop читает, не жалуясь на то, что я получаю:
>>> tiff.imsave('new.tiff', a)
Ответ 2
Ответ @Jaime работает.
В то же время мне удалось решить проблему, используя cv2.imread
в OpenCV.
По умолчанию cv2.imread
преобразует 16-битное трехканальное изображение в a.tif
в 8 бит, как показано в вопросе.
cv2.imread
принимает флаг после имени файла (cv2.imread(filename[, flags])
), который указывает тип цвета загруженного изображения cf. документация:
- 0 возвращает трехканальное цветное изображение. Это приводит к преобразованию в 8 бит, как показано выше.
- 0 возвращает изображение в оттенках серого. Также приводит к преобразованию в 8 бит.
- < 0 возвращает изображение как есть. Этот будет возвращать 16-битное изображение.
Итак, следующее изображение будет читаться без преобразования:
>>> im = cv2.imread('a.tif', -1)
>>> im.dtype
dtype('uint16')
>>> im.shape
(288, 384, 3)
Обратите внимание, что OpenCV возвращает каналы R, G и B в обратном порядке, поэтому im[:,:,0]
является каналом B, im[:,:,1]
канал G и im[:,:,2]
является каналом R.
Я также обнаружил, что cv2.imwrite
может писать 16-битные трехканальные файлы TIFF.
>>> cv2.imwrite('out.tif', im)
Проверка глубины бит с помощью 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
....
Ответ 3
Я нашел дополнительную альтернативу двум описанным выше методам.
Пакет scikit-image также может читать 16-битные трехканальные файлы TIFF, используя как tifffile.py
, так и FreeImage, и указывая их как плагин для использования.
В то время как чтение с использованием tifffile.py
возможно выполняется более просто, как показано @Jaime, я думал, что покажу, как он используется вместе с scikit-image в случае, если кто-то захочет сделать это таким образом.
Для тех, кто использует Ubuntu, FreeImage доступен как libfreeimage3
с помощью apt
.
Если используется опция плагина tifffile.py
, tifffile.py необходимо скопировать в каталог skimage/io/_plugins (f.ex. на Ubuntu полный путь в моем случае был /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:
>>> skimage.io.imsave('b.tif', im, plugin='tifffile')
>>> skimage.io.imsave('c.tif', im, plugin='freeimage')
Проверка битдапа как b.tif
, так и c.tif
с помощью ImageMagick показывает, что каждый канал на обоих изображениях 16 бит.
Ответ 4
Для меня предыдущие альтернативы не работали. Я успешно использовал gdal для чтения 16-битных изображений объемом 1 ГБ.
Вы можете открыть изображение примерно так:
from osgeo import gdal
import numpy as np
ds = gdal.Open("name.tif")
channel = np.array(ds.GetRasterBand(1).ReadAsArray())
Существует список поддерживаемого дайвера, который вы можете использовать для записи данных.
Ответ 5
Я рекомендую использовать привязки Python к OpenImageIO, это стандарт для работы с различными форматами изображений в домене vfx (которые обычно 16/32-битные).
import OpenImageIO as oiio
input = oiio.ImageInput.open ("/path/to/image.tif")