Python PIL борется с несжатыми 16-битными изображениями TIFF

Моя система — Mac OS X v10.8.2. У меня есть несколько несжатых 16-битных изображений TIFF 2560x500 (оттенки серого, 16-битные целые числа без знака). Сначала я пытаюсь загрузить их с помощью PIL (устанавливается через Homebrew, версия 1.7.8):

from PIL import Image
import numpy as np

filename = 'Rocks_2ptCal_750KHz_20ms_1ma_120KV_2013-03-06_20-02-12.tif'
img = Image.open(filename)

# >>> img
# <PIL.TiffImagePlugin.TiffImageFile image mode=I;16B size=2560x500 at 0x10A383C68>

img.show() 

# almost all pixels displayed as white.  Not correct.  
# MatLab, EZ-draw, even Mac Preview show correct images in grayscale.

imgdata = list(img.getdata()) 

# most values negative:
# >>> imgdata[0:10]
# [-26588, -24079, -27822, -26045, -27245, -25368, -26139, -28454, -30675, -28455]

imgarray = np.asarray(imgdata, dtype=np.uint16) 

# values now correct
# >>> imgarray
# array([38948, 41457, 37714, ..., 61922, 59565, 60035], dtype=uint16)

Отрицательные значения отличаются на 65 536... вероятно, это не совпадение.

Если я сделаю вид, что изменяю пиксели и вернусь обратно к изображению TIFF через PIL (просто вернув массив в виде изображения):

newimg = Image.fromarray(imgarray)

Я получаю ошибки:

File "/usr/local/lib/python2.7/site-packages/PIL/Image.py", line 1884, in fromarray
    raise TypeError("Cannot handle this data type")
TypeError: Cannot handle this data type

Я не могу найти Image.fromarray() в документации PIL. Я пробовал загружать через Image.fromstring(), но я не понимаю документацию PIL, и примеров мало.

Как показано в приведенном выше коде, PIL «обнаруживает» данные как I;16B. Из того, что я могу сказать из документов PIL, режим I:

*I* (32-bit signed integer pixels)

Очевидно, что это неправильно.

Я нахожу много сообщений на SX, предполагающих, что PIL не поддерживает 16-битные изображения. Я нашел предложения по использованию pylibtiff, но я полагаю, что это только для Windows?

Я ищу «легкий» способ работы с этими изображениями TIFF в Python. Я удивлен, что это так сложно, и это заставляет меня поверить, что проблема будет очевидна для других.


person ph0t0n    schedule 08.03.2013    source источник
comment
Не могли бы вы выложить пример файла где-нибудь?   -  person nneonneo    schedule 08.03.2013
comment
PIL борется со многими вещами, даже такими простыми, как чересстрочные PNG. Я склонен подозревать, что он просто неправильно поддерживает 16-битные изображения.   -  person    schedule 08.03.2013
comment
@nneonneo К сожалению, данные в файлах, с которыми я работаю, являются собственностью, и я не знаю, как привести пример TIFF, который не работает, как этот. Я знаю, что это очень затрудняет устранение неполадок, но я надеялся, что кто-то просто знает, что здесь делать... Я попытался сделать сценарий как можно более полным.   -  person ph0t0n    schedule 08.03.2013
comment
@duskwuff Я боялся этого. Есть ли лучший способ работы с TIFF в Python (желательно что-то очень легкое и с хорошей документацией?)   -  person ph0t0n    schedule 08.03.2013


Ответы (2)


Оказывается, Matplotlib обрабатывает 16-битные несжатые изображения TIFF в двух строках кода:

import matplotlib.pyplot as plt
img = plt.imread(filename)

# >>> img
# array([[38948, 41457, 37714, ..., 61511, 61785, 61824],
#       [39704, 38083, 36690, ..., 61419, 60086, 61910],
#       [41449, 39169, 38178, ..., 60192, 60969, 63538],
#       ...,
#       [37963, 39531, 40339, ..., 62351, 62646, 61793],
#       [37462, 37409, 38370, ..., 61125, 62497, 59770],
#       [39753, 36905, 38778, ..., 61922, 59565, 60035]], dtype=uint16)

И вуаля. Я полагаю, что это не соответствует моим требованиям как «легкий», поскольку Matplotlib является (для меня) тяжелым модулем, но получить изображение в массив Numpy невероятно просто. Я надеюсь, что это поможет кому-то быстро найти решение, поскольку для меня это не было очевидным.

person ph0t0n    schedule 08.03.2013
comment
Я также работаю с 16-битными несжатыми изображениями TIFF. У меня должна быть немного другая сборка Matplotlib или немного другие изображения TIFF, потому что этот код у меня не работал. Matplotlib вернул массив с размерами (1024, 1024, 4) вместо (1024, 1024), а максимальное значение изображения, указанное вызовом max(img.ravel()), было неправильно уменьшено до 255. Что бы это ни стоило, я прибегнул к загрузке своих изображений в Matlab и сохранению их обратно в виде файлов mat, которые можно надежно загрузить с помощью scipy. - person Mike Roberts; 06.07.2013
comment
@Mike Roberts, последнее измерение массива (4) может содержать каждый компонент пикселя. Каждый компонент пикселя RGB (A) обычно имеет длину 8 бит, поэтому максимальное значение равно 255, что означает, что это даже лучше, чем получение простого массива 1024x1024. Вы по-прежнему можете преобразовать 4 компонента в один 32-битный, выполнив операцию ИЛИ для каждого компонента с двоичным сдвигом, например. красный | зеленый ‹‹ 8 | синий ‹‹ 16 | альфа ‹‹ 24 - person Steve K; 12.08.2013
comment
@SteveK Привет, СтивК, спасибо за предложение. Я не согласен с вашим утверждением о том, что необходимость выполнять операции по битовому преобразованию возвращаемого массива даже лучше, чем получение простого массива 1024x1024. OP спрашивает о 16-битных изображениях TIFF в оттенках серого, поэтому единственным подходящим типом возвращаемого значения является 1024x1024 uint16, по крайней мере, на мой взгляд. Кроме того, как клиент этого интерфейса с перестановкой битов, как я должен знать, что альфа содержит старший байт, а красный содержит младший байт? Это соглашение не всегда соблюдается (например, данные цветного изображения иногда сохраняются как BGRA). - person Mike Roberts; 22.08.2013
comment
о, я пропустил эту важную часть информации (оттенки серого). Очевидно, что в этом случае гораздо лучше иметь только одно целое число (16-битное слово) на пиксель. Кроме того, для порядка пикселей вы правы. Но в любом случае с изображением RGBA вам придется возиться с байтами и с поиском их порядка (BGRA, RGBA, ARGB...). На самом деле не так очевидно. - person Steve K; 22.08.2013

Попробуйте Pillow, «дружественный» форк PIL. Недавно они добавили лучшую поддержку 16- и 32-битных изображений, в том числе в интерфейсе массива numpy. Этот код будет работать с последней версией Pillow:

from PIL import Image
import numpy as np

img = Image.open('data.tif')
data = np.array(img)
person Jeremy Muhlich    schedule 14.02.2014