Анализ изображений Python: чтение многомерного файла TIFF из конфокальной микроскопии
У меня есть файл изображения TIFF из конфокального микроскопа, который я могу открыть в ImageJ, но который я хотел бы получить в Python.
Формат TIFF выглядит следующим образом: в измерении Z имеется 30 стеков. Каждый слой Z имеет три канала от разных флуоресцентных маркеров. Каждый канал имеет глубину 8 бит. Размеры изображения 1024х1024.
В принципе, я могу прочитать файл с помощью Skimage (который я планирую использовать для дальнейшего анализа данных) с помощью плагина tifffile. Однако то, что я получаю, не совсем то, что я ожидаю.
merged = io.imread("merge.tif", plugin="tifffile")
merged.shape
# (30, 3, 3, 1024, 1024)
# (zslice, RGB?, channel?, height, width)
merged.dtype
# dtype('uint16')
Поначалу меня смутило то, что я получил две оси длины 3. Я думаю, что это потому, что tifffile обрабатывает каждый канал как отдельные изображения RGB, но я могу обойти это путем поднабора или использования skimage.color.rgb2grey
на отдельных каналах. Больше всего меня беспокоит то, что файл импортируется как 16-битное изображение. Я могу преобразовать его обратно, используя skimage.img_as_ubyte
, но после этого гистограмма больше не соответствует той, которую я вижу в ImageJ.
Я не зациклен на использовании Skimage для импорта файла, но я хотел бы в конечном итоге получить изображение в массиве, чтобы использовать в нем функции Skimage.
2 ответа
Я столкнулся с той же проблемой при работе с файлами.tif. Рекомендую использовать биоформаты пакета python.
import javabridge
import bioformats
javabridge.start_vm(class_path=bioformats.JARS)
path_to_data = '/path/to/data/file_name.tif'
# get XML metadata of complete file
xml_string = bioformats.get_omexml_metadata(path_to_data)
ome = bioformats.OMEXML(xml_string) # be sure everything is ascii
print ome.image_count
в зависимости от данных один файл может содержать несколько изображений. Каждое изображение может быть доступно следующим образом:
# read some metadata
iome = ome.image(0) # e.g. first image
print iome.get_Name()
print iome.get_ID()
# get pixel meta data
print iome.Pixels.get_DimensionOrder()
print iome.Pixels.get_PixelType()
print iome.Pixels.get_SizeX()
print iome.Pixels.get_SizeY()
print iome.Pixels.get_SizeZ()
print iome.Pixels.get_SizeT()
print iome.Pixels.get_SizeC()
print iome.Pixels.DimensionOrder
загрузка необработанных данных изображения 0 в массив numpy выполняется следующим образом:
reader = bioformats.ImageReader(path_to_data)
raw_data = []
for z in range(iome.Pixels.get_SizeZ()):
# returns 512 x 512 x SizeC array (SizeC = number of channels)
raw_image = reader.read(z=z, series=0, rescale=False)
raw_data.append(raw_image)
raw_data = np.array(raw_data) # 512 x 512 x SizeC x SizeZ array
Надеюсь, что это помогает обрабатывать файлы.tif, ура!
Я не уверен, что 'hyperstack to stack'
Функция это то, что вы хотите. Гиперстеки - это просто многомерные изображения, которые могут быть 4D или 5D (ширина, высота, срезы, каналы (например, 3 для RGB) и временные рамки). В ImageJ у вас есть ползунок для каждого измерения в гиперстеке.
Стеки - это просто двухмерные изображения, которые как-то связаны, и у вас есть только один ползунок, в простейшем случае он представляет z-срезы в наборе трехмерных данных.
'hyperstack to stack'
функция суммирует все измерения в вашем гиперштеке. Таким образом, если у вас есть гиперстек с 3 каналами, 4 срезами и 5 таймфреймами (3 слайдера), вы получите стек 3x4x5 = 60
изображения (один слайдер). В основном то же самое, что вы упомянули выше со скольжением через фокальные плоскости для каждого канала. Вы можете пойти другим путем, используя 'stack to hyperstack'
и сделайте гиперстек, определив, какие срезы из вашего стека представляют какое измерение. В упомянутом выше примере файла выберите порядок xyzct, 3 канала и 7 временных точек.
Так что, если ваш TIFF-файл имеет 2 ползунка, кажется, что это 4-мерный гиперстек с высотой, шириной, 30 срезами и 3 каналами. 'hyperstack to stack'
сложит все размеры друг на друга, так что вы получите 3x30=90 slices
,
Однако, по словам читателя tiff скимаджа, кажется, что ваш tiff-файл - это своего рода 5-мерный гиперстек. Ширина, высота (1024x1024), 30 z-слайсов, 3 канала (RGB) и другое измерение с 3 записями (например, временные рамки).
Чтобы выяснить, что не так, я бы посоветовал сравнить размеры с 3 записями массива, которые вы получаете из лыжного мага. Узнайте, какой из них представляет каналы RGB, а какой - другой. Вы можете, например, использовать функцию изображения pyqtgraph:
import pyqtgraph as pg
merged = io.imread("merge.tif", plugin="tifffile")
#pg.image takes the dimensions in the following order: z-slider,x,y,RGB channel
#if merged.shape = (30, 3, 3, 1024, 1024), you have to compare the 1st and 2nd dimension
pg.image(merged[:,0,:,:,:].transpose(0, 2, 3, 1))
pg.image(merged[:,1,:,:,:].transpose(0, 2, 3, 1))
pg.image(merged[:,2,:,:,:].transpose(0, 2, 3, 1))
pg.image(merged[:,:,0,:,:].transpose(0, 2, 3, 1))
pg.image(merged[:,:,1,:,:].transpose(0, 2, 3, 1))
pg.image(merged[:,:,2,:,:].transpose(0, 2, 3, 1))