Python и 16-битный Tiff

Как я могу преобразовать и сохранить 16-битный одноканальный TIF в Python?

Я могу без проблем загрузить 16- и 32-битное изображение и вижу, что 32-битное изображение имеет режим F, а 16-битное изображение — режим I;16S:

import Image
i32 = Image.open('32.tif')
i16 = Image.open('16.tif')
i32
# <TiffImagePlugin.TiffImageFile image mode=F size=2000x1600 at 0x1098E5518>
i16
# <TiffImagePlugin.TiffImageFile image mode=I;16S size=2000x1600 at 0x1098B6DD0>

Но у меня проблемы с работой с 16-битным изображением. Если я хочу сохранить как PNG, я не могу сделать это напрямую:

i32.save('foo.png')
# IOError: cannot write mode F as PNG
i16.save('foo.png')
# ValueError: unrecognized mode

Если я конвертирую 32-битное изображение, я могу его сохранить:

i32.convert('L').save('foo.png')

Но эта же команда не будет работать с 16-битным образом:

i16.convert('L').save('foo.png')
# ValueError: unrecognized mode

person mankoff    schedule 30.08.2011    source источник
comment
У Pil должна быть поддержка: effbot.org/zone/pil-changes-114.htm (выпущена версия 1.1.4a2) Улучшена поддержка 16-битных целочисленных изображений без знака (режим «I;16»). Это включает в себя поддержку чтения TIFF и поддержку «getextrema» и «point» (от Klamer Shutte). Можете ли вы предоставить образец файла?   -  person Mark Ransom    schedule 30.08.2011
comment
В ПОРЯДКЕ. Я использую PIL 1.1.7, поэтому поддержка есть. Отредактировал вопрос. Проблема не в PIL, но я до сих пор не знаю, что я делаю неправильно...   -  person mankoff    schedule 30.08.2011
comment
Еще хотелось бы увидеть образец файла.   -  person Mark Ransom    schedule 30.08.2011
comment
вот пример файла: sidads.colorado.edu/pub/DATASETS/ ICESHELVES/сосна/   -  person mankoff    schedule 30.08.2011
comment
И 32-разрядная версия: sidads.colorado.edu/pub/ НАБОРЫ ДАННЫХ/ПОЛОЧНЫЕ ЛЬДА/   -  person mankoff    schedule 30.08.2011


Ответы (4)


Для преобразования без потерь из 16-битного TIFF в оттенках серого в PNG используйте PythonMagick:

from PythonMagick import Image
Image('pinei_2002300_1525_modis_ch02.tif').write("foo.png")
person cgohlke    schedule 30.08.2011
comment
Как это может быть без потерь? Вы переходите с 16 бит на пиксель к 8. - person Mark Ransom; 31.08.2011
comment
Формат PNG поддерживает 16 бит на канал для оттенков серого (1 канал). en.wikipedia.org/wiki/Portable_Network_Graphics#Color_depth - person cgohlke; 31.08.2011
comment
Я использую PNG уже много лет и никогда не знал, что он поддерживает 16 бит на канал. Возвращаясь к RFC 2083, я вижу, что так было с самого начала. Спасибо, что научили меня кое-чему сегодня! - person Mark Ransom; 31.08.2011
comment
Хорошее решение, но PythonMagick не включен во многие установки по умолчанию (EPD, sage), что делает код менее переносимым. - person mankoff; 10.09.2011

Наткнулся на эту тему, пытаясь сохранить 16-битные изображения TIFF с помощью PIL/numpy.

Версии: python 2.7.1 - numpy 1.6.1 - PIL 1.1.7

Вот быстрый тест, который я написал. Массив uint16 numpy -> преобразованный в строку -> преобразованный в изображение PIL типа «I; 16» -> сохраненный как 16-битный TIFF.

При открытии изображения в ImageJ отображается правый шаблон горизонтального градиента, а тип изображения — «Бит на пиксель: 16 (без знака)».

import Image
import numpy

data = numpy.zeros((1024,1024),numpy.uint16)

h,w = data.shape

for i in range(h):
    data[i,:] = numpy.arange(w)

im = Image.fromstring('I;16',(w,h),data.tostring())
im.save('test_16bit.tif')

Изменить: Начиная с версии 1.1.7, PIL не поддерживает запись сжатых файлов, но pylibtiff делает (сжатие lzw). Таким образом, тестовый код становится (проверено с помощью pylibtiff 0.3):

import Image
import numpy
from libtiff import TIFFimage

data = numpy.zeros((1024,1024),numpy.uint16)

h,w = data.shape

for i in range(w):
    data[:,i] = numpy.arange(h)

tiff = TIFFimage(data, description='')
tiff.write_file('test_16bit.tif', compression='lzw')
#flush the file to disk:
del tiff

Обратите внимание: тестовый код изменен для создания вертикального градиента, в противном случае сжатие не достигается (обратитесь к предупреждению: в настоящее время pylibtiff поддерживает чтение и запись изображений, которые хранятся с использованием полос TIFF).

person EgorZ    schedule 27.01.2012

Похоже, вы наткнулись на ошибку PIL или нереализованный краеугольный случай.

Вот обходной путь:

i16.mode = 'I'
i16.point(lambda i:i*(1./256)).convert('L').save('foo.png')
person Mark Ransom    schedule 30.08.2011
comment
Я получаю: ValueError: unknown raw mode - person mankoff; 30.08.2011
comment
@mankoff: извините, я, должно быть, попробовал два разных способа и скопировал не тот. Я изменил ответ с mode='I;16' на mode='I', попробуйте сейчас. - person Mark Ransom; 30.08.2011
comment
Кажется, это работает. Данные теряются? Я думаю (?) что режим I 8-битный. - person mankoff; 31.08.2011
comment
@mankoff, по крайней мере, преобразование в режим «L» будет усечено до 8 бит. Если вы хотите увидеть необработанные данные, попробуйте getpixel или load после того, как режим установлен на 'I'. - person Mark Ransom; 31.08.2011

Преобразуйте ImageJ TIFF в JPEG с помощью PIL 4.1+

im = numpy.array(Image.open('my.tiff'))
image = Image.fromarray(im / numpy.amax(im) * 255)
image.save('my.jpg')
person Adam Gradzki    schedule 18.04.2017