介紹如何使用 ITK 的 TriangleMeshToBinaryImageFilter 將網格(mesh)包圍的範圍轉為二元影像(binary image)。
相關文章:
ITK 使用 BinaryMask3DMeshSource 將二元影像轉為 Surface 教學與範例
VTK 使用 vtkDiscreteMarchingCubes 將二元遮罩影像轉為 Mesh 網格教學與範例
Python 語言版本
在使用 ITK 的 TriangleMeshToBinaryImageFilter 將網格轉為二元影像的時候,需要指定網格與影像的類型,可用的類型可以用 GetTypes 函數查詢:
import SimpleITK as sitk
import numpy as np
import itk
import matplotlib.pyplot as plt
# 查詢 TriangleMeshToBinaryImageFilter 支援的類型
itk.TriangleMeshToBinaryImageFilter.GetTypes()
<itkTemplate itk::TriangleMeshToBinaryImageFilter> Options: [<class 'itk.itkMeshBasePython.itkMeshD3'>, <class 'itk.itkImagePython.itkImageD3'>] [<class 'itk.itkMeshBasePython.itkMeshF3'>, <class 'itk.itkImagePython.itkImageF3'>] [<class 'itk.itkMeshBasePython.itkMeshSS3'>, <class 'itk.itkImagePython.itkImageSS3'>] [<class 'itk.itkMeshBasePython.itkMeshUC3'>, <class 'itk.itkImagePython.itkImageUC3'>] [<class 'itk.itkMeshBasePython.itkMeshUS3'>, <class 'itk.itkImagePython.itkImageUS3'>]
這裡我們設定網格與影像的類型皆為無號短整數:
# 設定網格與影像的類型
meshType = itk.Mesh[itk.US, 3]
imageType = itk.Image[itk.US, 3]
接著讀取網格與影像檔案:
# 讀取 Mesh 網格檔案
meshReader = itk.MeshFileReader[meshType].New()
meshIO = itk.OBJMeshIO.New()
meshReader.SetMeshIO(meshIO)
meshReader.SetFileName("annotation/ccf_2017/structure_meshes/477.obj")
meshReader.Update()
mesh = meshReader.GetOutput()
# 讀取影像檔案
image = itk.imread("average_template/average_template_25.nrrd")
若要查看網格的資料,可以使用 itkwidgets 來顯示:
# 顯示網格資料
import itkwidgets
itkwidgets.view(geometries = mesh)

透過 TriangleMeshToBinaryImageFilter 將網格轉為二元影像(遮罩影像):
# 建立 TriangleMeshToBinaryImageFilter
mesh2binFilter = itk.TriangleMeshToBinaryImageFilter[meshType, imageType].New()
# 設定輸入網格
mesh2binFilter.SetInput(mesh)
# 根據影像設定影像資訊(spacing、size、origin)
mesh2binFilter.SetInfoImage(image)
# 亦可自行設定影像資訊
#mesh2binFilter.SetSpacing(spacing)
#mesh2binFilter.SetSize(size)
#mesh2binFilter.SetOrigin(origin)
# 設定值區域內外值
mesh2binFilter.SetInsideValue(255)
mesh2binFilter.SetOutsideValue(0)
# 實際執行
mesh2binFilter.Update()
mask = mesh2binFilter.GetOutput()
這裡產生的 mask 就是遮罩影像,網格內部的值會是 255,外部則會是 0。
# 顯示影像切面
nda = itk.GetArrayViewFromImage(mask)
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()

C++ 語言版本
這是要 C++ 語言中使用 TriangleMeshToBinaryImageFilter 的範例,基本概念都相同,只是以不同程式語言實作而已。
#include <itkMesh.h>
#include <itkMeshFileReader.h>
#include <itkImage.h>
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include <itkCastImageFilter.h>
#include <itkTriangleMeshToBinaryImageFilter.h>
int main() {
// 設定 Mesh 資料型態(浮點數、維度 3)
constexpr unsigned int Dimension = 3;
using MeshPixelType = double;
using MeshType = itk::Mesh<MeshPixelType, Dimension>;
// 建立 Mesh Reader
using MeshReaderType = itk::MeshFileReader<MeshType>;
MeshReaderType::Pointer meshReader = MeshReaderType::New();
// 指定 Mesh 檔案名稱
meshReader->SetFileName("input_mesh.obj");
// 設定影像資料型態
using PixelType = unsigned char;
using ImageType = itk::Image<PixelType, Dimension>;
// 建立 Image Reader
using ImageReaderType = itk::ImageFileReader<ImageType>;
ImageReaderType::Pointer imageReader = ImageReaderType::New();
// 指定影像檔案名稱
imageReader->SetFileName("input_image.nrrd");
// 建立 TriangleMeshToBinaryImageFilter
using FilterType = itk::TriangleMeshToBinaryImageFilter<MeshType, ImageType>;
FilterType::Pointer filter = FilterType::New();
// 指定輸入 Mesh
filter->SetInput(meshReader->GetOutput());
// 設定影像資訊
filter->SetInfoImage(imageReader->GetOutput());
// 設定 Mesh 內部數值
filter->SetInsideValue(itk::NumericTraits<PixelType>::max());
// 實際進行轉換
try {
filter->Update();
} catch (itk::ExceptionObject & error) {
std::cerr << "Error: " << error << std::endl;
return EXIT_FAILURE;
}
// 建立 Image Writer,輸出轉換結果影像
using WriterType = itk::ImageFileWriter<ImageType>;
WriterType::Pointer writer = WriterType::New();
writer->SetFileName("output_image.nrrd");
writer->SetInput(filter->GetOutput());
// 實際寫入檔案
try {
writer->Update();
} catch (itk::ExceptionObject & error) {
std::cerr << "Error: " << error << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
搭配以下 CMakeLists.txt 以 CMake 編譯:
cmake_minimum_required(VERSION 3.10.2)
# 設定專案名稱
project(ConvMesh)
# 尋找並引入 ITK 函式庫
find_package(ITK REQUIRED)
include(${ITK_USE_FILE})
# 增加一個執行檔
add_executable(ConvMesh ConvMesh.cpp)
# 定義執行檔連結方式
target_link_libraries(ConvMesh ${ITK_LIBRARIES})
