介紹如何從 IMS 檔案中讀取影像資料,轉換成其他的影像檔案。
IMARIS(IMS)是一種以 HDF5 格式為基礎的影像檔案格式,專門用於儲存大型的影像,在一個 IMS 影像檔案中除了原始解析度的影像之外,同時也會包含低解析度的影像資料,配合 HDF5 的 chunk 方式儲存,可加速影像的讀取與顯示速度。
h5ls
與 h5dump
指令h5ls
與 h5dump
指令是 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)。
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
的資料型態,可以先將資料轉換成 0
到 255
的值,再進行型別轉換:
# 轉換為 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')