介紹如何使用 ITK 的 BinaryMask3DMeshSource
將二元影像(binary image)轉為網格(mesh)構成的 surface。
BinaryMask3DMeshSource
可以將三維的二元遮罩影像轉換為網格,首先定義好來源遮罩影像的類型,以及轉出的網格類型:
import itk import matplotlib.pyplot as plt # 設定網格與影像的類型 MeshType = itk.Mesh[itk.F, 3] PixelType = itk.UC ImageType = itk.Image[PixelType, 3]
讀取二元遮罩影像(這裡使用 Allen Mouse Brain CCFv3 標註影像作為範例):
# 讀取二元遮罩影像 maskImageFilename = "structure_477.nrrd" maskImage = itk.imread(maskImageFilename, PixelType)
先以 matplotlib
查看遮罩影像各方向的截面:
# 查看遮罩影像各方向截面 nda = itk.GetArrayViewFromImage(maskImage) fig, axs = plt.subplots(1, 3, figsize=(15, 5)) axs[0].imshow(nda[nda.shape[0]//2,:,:], cmap = 'gray') axs[1].imshow(nda[:,nda.shape[1]//2,:], cmap = 'gray') axs[2].imshow(nda[:,:,nda.shape[2]//2], cmap = 'gray') plt.show()
建立 BinaryMask3DMeshSource
之後,設定來源影像與物件的遮罩數值,即可將遮罩轉為網格:
# 以 BinaryMask3DMeshSource 將遮罩影像轉為網格 MeshSourceType = itk.BinaryMask3DMeshSource[ImageType, MeshType] meshSource = MeshSourceType.New() meshSource.SetInput(maskImage) meshSource.SetObjectValue(1) meshSource.Update() # 取得產生的網格結果 mesh = meshSource.GetOutput()
以 itkwidgets
顯示網格:
# 以 itkwidgets 顯示網格 import itkwidgets itkwidgets.view(geometries = mesh)
若要將產生的網格資料儲存起來,可以使用 MeshFileWriter
:
# 儲存 Mesh 網格檔案 meshWriter = itk.MeshFileWriter[MeshType].New() meshIO = itk.OBJMeshIO.New() meshWriter.SetMeshIO(meshIO) meshWriter.SetInput(mesh) meshWriter.SetFileName("mesh.obj") meshWriter.Update()
在 C++ 中使用 BinaryMask3DMeshSource
的方式也都相同,只是以不同程式語言實作而已。
#include <itkImageFileReader.h> #include <itkBinaryMask3DMeshSource.h> #include <itkMeshFileWriter.h> #include <itkOBJMeshIO.h> #include <itkImage.h> int main() { // 設定網格與影像的類型 using MeshType = itk::Mesh<double, 3>; using PixelType = unsigned char; using ImageType = itk::Image<PixelType, 3>; // 讀取二元遮罩影像 using ReaderType = itk::ImageFileReader<ImageType>; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName("structure_477.nrrd"); // 以 BinaryMask3DMeshSource 將遮罩影像轉為網格 using MeshSourceType = itk::BinaryMask3DMeshSource<ImageType, MeshType>; MeshSourceType::Pointer meshSource = MeshSourceType::New(); meshSource->SetInput(reader->GetOutput()); meshSource->SetObjectValue(1); meshSource->Update(); // 儲存 Mesh 網格檔案 using MeshWriterType = itk::MeshFileWriter<MeshType>; MeshWriterType::Pointer meshWriter = MeshWriterType::New(); meshWriter->SetMeshIO(itk::OBJMeshIO::New()); meshWriter->SetInput(meshSource->GetOutput()); meshWriter->SetFileName("mesh.obj"); meshWriter->Update(); return EXIT_SUCCESS; }
將此 C++ 範例程式碼儲存於 ConvImage2Mesh.cpp
之後,搭配以下 CMakeLists.txt
設定以 CMake 編譯:
cmake_minimum_required(VERSION 3.10.2) # 設定專案名稱 project(ConvImage2Mesh) # 尋找並引入 ITK 函式庫 find_package(ITK REQUIRED) include(${ITK_USE_FILE}) # 增加一個執行檔 add_executable(ConvImage2Mesh ConvImage2Mesh.cpp) # 定義執行檔連結方式 target_link_libraries(ConvImage2Mesh ${ITK_LIBRARIES})
參考資料:SurfaceExtraction.cxx、VTK MarchingCubes Example、Medical1.py、vtkContourFilter Examples、VTK ExtractSurface Example