介紹如何使用 SimpleElastix 影像對準(image registration)工具,以剛性、線性、非線性的方式對準影像。
從 GitHub 下載 SimpleElastix 的原始碼:
# 下載 SimpleElastix 原始碼
git clone https://github.com/SuperElastix/SimpleElastix
建立編譯用目錄,在該目錄中編譯:
# 編譯 SimpleElastix mkdir build cd build cmake -DWRAP_PYTHON=ON ../SimpleElastix/SuperBuild make -j4
安裝編譯完成的 SimpleElastix Python 模組:
# 安裝 SimpleElastix cd SimpleITK-build/Wrapping/Python/ sudo python3 Packaging/setup.py install
以下是一個使用 SimpleITK
進行影像對準的 hello world 範例程式碼,這裡我們使用 build/Elastix/dox/exampleinput
的範例影像來做示範。
在進行影像對準時,會拿一張基準影像(fixed image)固定不動,然將另一張調動影像(moving image)進行各種線性或非線性轉換,盡可能去對準基準影像。
一開始載入基準影像與調動影像:
import SimpleITK as sitk import matplotlib.pyplot as plt # 讀取影像 fixedImage = sitk.ReadImage("fixed.mhd") movingImage = sitk.ReadImage("moving.mhd")
檢查影像基本資訊:
# 影像基本資訊 print("Size:", fixedImage.GetSize()) print("Origin:", fixedImage.GetOrigin()) print("Spacing", fixedImage.GetSpacing()) print("Size:", movingImage.GetSize()) print("Origin:", movingImage.GetOrigin()) print("Spacing", movingImage.GetSpacing())
Size: (256, 256) Origin: (0.0, 0.0) Spacing (1.0, 1.0) Size: (256, 256) Origin: (0.0, 0.0) Spacing (1.0, 1.0)
顯示影像實際內容:
# 顯示影像 fig, axs = plt.subplots(1, 2) axs[0].imshow(sitk.GetArrayViewFromImage(fixedImage), cmap='gray') axs[0].set_title('Fixed Image') axs[1].imshow(sitk.GetArrayViewFromImage(movingImage), cmap='gray') axs[1].set_title('Moving Image') plt.show()
# 以 Elastix 進行影像對準 resultImage = sitk.Elastix(fixedImage, movingImage) # 顯示影像對準結果 plt.imshow(sitk.GetArrayViewFromImage(resultImage), cmap='gray') plt.show()
若需要比較兩張影像,可以將基準影像與對準結果合併,製作成彩色影像來觀看。
Elastix 在進行影像對準時,內部有大量的參數可以調整,而 Elastix 有內建一些預設的參數組合可以參考:
# 取得 translation 預設參數組合 parameterMap = sitk.GetDefaultParameterMap('translation')
可用參數組合有 translation
、rigid
、affine
、nonrigid
。
若要查看參數組合的內容,可以用 PrintParameterMap
函數來輸出每一個設定值:
# 查看參數組合
sitk.PrintParameterMap(parameterMap)
在實務上進行影像對準時,都會需要對某些參數進行調整,然後再套用自己的參數進行影像對準:
# 將影像轉換方法改為仿射變換(Affine Transformation) parameterMap['Transform'] = ['AffineTransform'] # 更改迭代次數上限值 parameterMap['MaximumNumberOfIterations'] = ['512'] # 以 Elastix 進行影像對準 resultImage = sitk.Elastix(fixedImage, movingImage, parameterMap)
我們也可以將所有的參數設定寫在一個文字設定檔中,再以 ReadParameterFile
來讀取設定檔,例如:
# 從設定檔案讀取參數組合 parameterMap = sitk.ReadParameterFile('Parameters_Affine.txt')
設定檔的格式與範例可以從 Elastix 的官方網站上查詢與下載。
在比較複雜的影像對準中,可能會需要將多個參數組合搭配使用:
# 取得多種參數組合 parameterMap1 = sitk.GetDefaultParameterMap('translation') parameterMap2 = sitk.GetDefaultParameterMap('affine') parameterMap3 = sitk.GetDefaultParameterMap('nonrigid') # 使用多組參數組合進行影像對準 resultImage = sitk.Elastix(fixedImage, movingImage, [parameterMap1, parameterMap2, parameterMap3])
SimpleElastix 也支援物件導向的語法,使用這種方式會有比較多的彈性,當進行比較複雜的影像處理工作時,就比較適合選用此種方式撰寫。最常見的狀況就是將影像對準完成後所得到的轉換參數,應用在其他影像的轉換上:
import SimpleITK as sitk # 讀取影像 fixedImage = sitk.ReadImage("fixed.mhd") movingImage = sitk.ReadImage("moving.mhd") # 參數組合 parameterMap = sitk.GetDefaultParameterMap('affine') # 影像對準 elastixImageFilter = sitk.ElastixImageFilter() elastixImageFilter.SetFixedImage(fixedImage) elastixImageFilter.SetMovingImage(movingImage) elastixImageFilter.SetParameterMap(parameterMap) elastixImageFilter.Execute() # 取得影像對準結果 resultImage = elastixImageFilter.GetResultImage() # 取得轉換影像的參數 transformParameterMap = elastixImageFilter.GetTransformParameterMap() # 建立影像轉換 Filter transformixImageFilter = sitk.TransformixImageFilter() # 設定影像轉換參數 transformixImageFilter.SetTransformParameterMap(transformParameterMap) # 進行後續影像轉換 otherImages = ['image1.hdr', 'image2.hdr', ... , 'imageN.hdr'] for filename in otherImages: transformixImageFilter.SetMovingImage(sitk.ReadImage(filename)) transformixImageFilter.Execute() sitk.WriteImage(transformixImageFilter.GetResultImage(), "result_" + filename)
如果在完成安裝 SimpleElastix Python 模組之後,在 Python 之中還是找不到 SimpleElastix 相關的工具,出現類似這樣的錯誤:
AttributeError: module 'SimpleITK' has no attribute 'Elastix'
遇到這種狀況可以檢查安裝時是否有安裝在正確的 Python 環境中(例如 conda 環境、不同版本 Python 等),另外如果系統上過去已安裝過 Python 的 SimpleITK
模組,也可以造成版本對不上,可以將過去安裝的 SimpleITK
模組先移除,再重新安裝一次 SimpleElastix,讓它自動附帶安裝 SimpleITK
。
參考資料:SimpleElastix