Python

讀取 IMARIS(IMS)檔案原始影像、後設資料教學與範例

介紹如何從 IMS 檔案中讀取影像資料,轉換成其他的影像檔案。

IMARIS(IMS)是一種以 HDF5 格式為基礎的影像檔案格式,專門用於儲存大型的影像,在一個 IMS 影像檔案中除了原始解析度的影像之外,同時也會包含低解析度的影像資料,配合 HDF5 的 chunk 方式儲存,可加速影像的讀取與顯示速度。

h5lsh5dump 指令

h5lsh5dump 指令是 HDF Group 官方所提供的指令工具,可用於查看 HDF5 檔案內的資訊以及匯出原始資料。

首先以 h5ls 查看 IMS 檔案整體結構:

# 檔案整體結構
h5ls -r image.ims

影像的後設資料(metadata)儲存於 /DataSetInfo,可用 h5ls 查看:

# 查詢影像基本後設資料
h5ls -v image.ims/DataSetInfo

或是使用 h5dump 也可以查詢影像的後設資料:

# 查詢影像基本後設資料
h5dump -g /DataSetInfo image.ims

若想要從 IMS 檔案中匯出指定解析度的原始影像資料,可以使用 h5dump 配合 --binary 參數指定資料匯出格式,以及 --output 參數指定匯出的檔案名稱:

# 匯出 ResolutionLevel 3 原始影像資料
h5dump -d "/DataSet/ResolutionLevel 3/TimePoint 0/Channel 0/Data" \
  --binary=MEMORY --output=h5dump_output.raw image.ims

這裡的 --binary 可用的參數有 LE(Little-endian)、BE(Big-endian)、MEMORY(Memory datatype)、FILE(File datatype)。

Python h5py 模組

Python 的 h5py 模組也可以用來讀取 IMS 檔案內的影像資料,首先以 h5py.File 開啟 IMS 檔案:

import h5py

# 開啟 IMS 檔案
imsFile = h5py.File('image.ims', 'r')

查看 HDF5 的頂層節點名稱:

# 查看頂層節點
list(imsFile.keys())
['DataSet', 'DataSetInfo', 'DataSetTimes', 'Scene', 'Scene8', 'Thumbnail']

影像主要的後設資料都放在 DataSetInfo 中,查看有哪些欄位名稱:

# 查看影像主要後設資料欄位名稱
list(imsFile['DataSetInfo']['Image'].attrs.keys())
['Description', 'ExtMax0', 'ExtMax1', 'ExtMax2', 'ExtMin0', 'ExtMin1', 'ExtMin2', 'Name', 'OriginalFormat', 'OriginalFormatFileIOVersion', 'RecordingDate', 'ResampleDimensionX', 'ResampleDimensionY', 'ResampleDimensionZ', 'Unit', 'X', 'Y', 'Z']

若要取得指定的後設資料內容,可以用以下方式:

# 查看指定 attribute 值
description = imsFile['DataSetInfo']['Image'].attrs['Description']
description.tobytes().decode('utf-8')
'(description not specified)'

取得影像的實際大小:

info = imsFile['DataSetInfo']['Image']

# 影像實際大小
ext0 = float(info.attrs['ExtMax0'].tobytes()) - float(info.attrs['ExtMin0'].tobytes())
ext1 = float(info.attrs['ExtMax1'].tobytes()) - float(info.attrs['ExtMin1'].tobytes())
ext2 = float(info.attrs['ExtMax2'].tobytes()) - float(info.attrs['ExtMin2'].tobytes())
unit = info.attrs['Unit'].tobytes().decode('utf-8')
print("Real Size: {} x {} x {} {}".format(ext0, ext1, ext2, unit))
Real Size: 13468 x 16016 x 8400 um

取得原始影像的大小:

# 原始影像大小
xPixels = int(info.attrs['X'].tobytes())
yPixels = int(info.attrs['Y'].tobytes())
zPixels = int(info.attrs['Z'].tobytes())
print("Image Size: {} x {} x {} pixels".format(xPixels, yPixels, zPixels))
Image Size: 7400 x 8800 x 2100 pixels

計算影像的 voxel size:

# Voxel Size
voxelSize = [ext0/xPixels, ext1/yPixels, ext2/zPixels]
print("Voxel Size: {}".format(voxelSize))
Voxel Size: [1.82, 1.82, 4.0]

若要讀取影像資料,方法也都差不多,不過由於 HDF5 的儲存格式問題,取出原始資料之後,還要依照影像的大小將實際的影像資料取出。例如讀取 ResolutionLevel 3 原始影像資料:

# 讀取 ResolutionLevel 3 原始資料
rawdata = imsFile['DataSet']['ResolutionLevel 3']['TimePoint 0']['Channel 0']['Data']

# 取得影像大小
channel = imsFile['DataSet']['ResolutionLevel 3']['TimePoint 0']['Channel 0']
imageSizeX = int(channel.attrs['ImageSizeX'].tobytes())
imageSizeY = int(channel.attrs['ImageSizeY'].tobytes())
imageSizeZ = int(channel.attrs['ImageSizeZ'].tobytes())

# 取得影像資料
image = rawdata[:imageSizeZ, :imageSizeY, :imageSizeX]

查看影像大小:

# 影像大小
image.shape
(262, 1100, 925)

讀取影像的實際像素值:

# 影像像素值
image[12][34][56]
108

若要將資料匯出為一般的影像檔案,可以轉為 NumPy 的陣列後,再儲存成檔案:

import numpy as np

# 轉為 NumPy 陣列
npArr = np.array(image)

# 輸出檔案
npArr.tofile('h5py_output.raw')

若需要把影像轉為 uint8 的資料型態,可以先將資料轉換成 0255 的值,再進行型別轉換:

# 轉換為 0 ~ 255 的像素值
pmin = npArr.min()
pmax = npArr.max()
rescale = (npArr - pmin) / (pmax - pmin) * 255

# 轉型為 uint8 型別
imageUInt8 = rescale.astype(np.uint8)

若想要把影像資料連同一些後設資料一起匯出成其他各種影像格式,可以使用 SimpleITK:

import SimpleITK as sitk

# 從 NumPy 轉為 SimpleITK 影像
sitkImage = sitk.GetImageFromArray(npArr)

# 設定 Voxel Size
sitkImage.SetSpacing(voxelSize)

# 輸出 Nrrd 檔案
sitk.WriteImage(sitkImage, 'output.nrrd')
Share
Published by
Office Guide

Recent Posts

Python 使用 PyAutoGUI 自動操作滑鼠與鍵盤

本篇介紹如何在 Python ...

1 年 ago

Ubuntu Linux 以 WireGuard 架設 VPN 伺服器教學與範例

本篇介紹如何在 Ubuntu ...

1 年 ago

Linux 網路設定 ip 指令用法教學與範例

本篇介紹如何在 Linux 系...

1 年 ago

Linux 以 Cryptsetup、LUKS 加密 USB 隨身碟教學與範例

介紹如何在 Linux 系統中...

1 年 ago