it-swarm.com.ru

Python: чтение и запись TIFF 16 бит, три канала, цветные изображения

У кого-нибудь есть метод для импорта 16-битного на канал 3-канального изображения 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. 

Еще одна проблема, которую я имею, - это сохранение любых массивов в виде 16-битных файлов PNG, что до сих пор не было простым.

23
Lars Chr

Он имеет ограниченную функциональность, особенно когда дело доходит до записи на диск не RGB-образов, но модуль 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)
28
Jaime

Ответ по @Jaime работает.

В то же время мне удалось решить проблему, используя cv2.imread в OpenCV.

По умолчанию cv2.imread преобразует 16-битное трехканальное изображение в a.tif в 8-битное, как показано в вопросе.

cv2.imread принимает флаг после имени файла (cv2.imread(filename[, flags])), который указывает тип цвета загруженного изображения cf. документация :

  1. > 0 возвращает 3-канальное цветное изображение. Это приводит к преобразованию в 8 бит, как показано выше.
  2. 0 возвращает изображение в оттенках серого. Также приводит к преобразованию в 8 бит.
  3. <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
  ....
22
Lars Chr

Я нашел дополнительную альтернативу двум методам выше.

Пакет scikit-image также может читать 16-битные трехканальные TIFF-файлы, используя tifffile.py и FreeImage, и указывать их в качестве подключаемого модуля.

Хотя чтение с использованием tifffile.py, вероятно, выполняется проще, как показано в @Jaime , я подумал, что покажу, как оно используется вместе с scikit-image, на случай, если кто-то захочет сделать это таким образом.

Для тех, кто использует Ubuntu, FreeImage доступен как libfreeimage3 с использованием apt.

Если используется опция плагина tifffile.py, файл tifffile.py необходимо скопировать в каталог skimage/io/_plugins (например, в 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-битным.

10
Lars Chr

Для меня предыдущие альтернативы не сработали. Я успешно использовал gdal для чтения 16-битных изображений размером 1 ГБ. 

Вы можете открыть изображение примерно так:

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

Существует список поддерживаемых diver , который вы можете использовать для записи данных.

4
G M

Я рекомендую использовать привязки Python к OpenImageIO, это стандарт для работы с различными форматами изображений в домене vfx (которые обычно 16/32-битные).

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