介紹如何使用 ITK 的 TransformFileWriter 與 TransformFileReader 寫入與讀取各種 Transform 影像轉換與參數。
寫入與讀取轉換
以下是一個簡單的儲存與載入轉換範例,先以 AffineTransform 與 BSplineTransform 組合建立一個 CompositeTransform 轉換,再使用 TransformFileWriter 將 CompositeTransform 轉換與其參數寫入檔案,最後再以 TransformFileReader 將轉換從檔案中讀取出來使用。
#include <itkTransformFileReader.h>
#include <itkTransformFileWriter.h>
#include <itkAffineTransform.h>
#include <itkBSplineTransform.h>
#include <itkCompositeTransform.h>
#include <itkTransformFactory.h>
int main(int argc, char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " transformFile" << std::endl;
return EXIT_FAILURE;
}
const char* transformFileName = argv[1];
// ================================== //
// 建立測試用 CompositeTransform 轉換 //
// ================================== //
// 指定轉換數值類型
using ScalarType = double;
// 影像維度
constexpr unsigned int Dimension = 3;
// 建立 CompositeTransform
using CompositeTransformType =
itk::CompositeTransform<ScalarType, Dimension>;
CompositeTransformType::Pointer composite = CompositeTransformType::New();
// 建立 AffineTransform
using AffineTransformType = itk::AffineTransform<ScalarType, Dimension>;
AffineTransformType::Pointer affine = AffineTransformType::New();
// 設定旋轉中心點
AffineTransformType::InputPointType center;
center.Fill(12);
affine->SetCenter(center);
// 將 AffineTransform 加入 CompositeTransform
composite->AddTransform(affine);
// 建立 BSplineTransform
constexpr unsigned int SplineOrder = 5;
using BSplineTransformType =
itk::BSplineTransform<ScalarType, Dimension, SplineOrder>;
using BSplineTransformFType =
itk::BSplineTransform<float, Dimension, SplineOrder>;
// 在預設狀況下只有 3 階 BSpline 的轉換有註冊,
// 此處手動註冊 5 階 BSpline 的轉換(包含 double 與 float)
// 這樣才能讀取到正確的轉換
itk::TransformFactory<BSplineTransformType>::RegisterTransform();
itk::TransformFactory<BSplineTransformFType>::RegisterTransform();
// 建立 BSplineTransform
BSplineTransformType::Pointer bspline = BSplineTransformType::New();
// 設定 BSplineTransform 相關參數
BSplineTransformType::OriginType origin;
origin.Fill(100);
bspline->SetTransformDomainOrigin(origin);
BSplineTransformType::PhysicalDimensionsType dimensions;
dimensions.Fill(1.5 * 9.0);
bspline->SetTransformDomainPhysicalDimensions(dimensions);
BSplineTransformType::ParametersType parameters(
bspline->GetNumberOfParameters());
bspline->SetParameters(parameters);
bspline->SetIdentity();
// 將 BSplineTransform 加入 CompositeTransform
composite->AddTransform(bspline);
// ================================== //
// 將 CompositeTransform 轉換寫入檔案 //
// ================================== //
// 建立 ScalarType 數值類型的 TransformFileWriter
// 在寫入時數值類型會在必要時自動轉換
using TransformWriterType = itk::TransformFileWriterTemplate<ScalarType>;
TransformWriterType::Pointer writer = TransformWriterType::New();
// TransformFileWriter 可接受各種 Transform 類型的轉換物件
writer->SetInput(composite);
// 設定檔案名稱
writer->SetFileName(transformFileName);
// 將轉換寫入檔案
try {
writer->Update();
} catch (itk::ExceptionObject & excp) {
std::cerr << "Error while saving the transforms" << std::endl;
std::cerr << excp << std::endl;
return EXIT_FAILURE;
}
// ================================== //
// 從檔案讀取 CompositeTransform 轉換 //
// ================================== //
// 指定轉換數值類型
using ReadScalarType = float;
// 建立 ReadScalarType 數值類型的 TransformFileReader
// 在讀取時數值類型會在必要時自動轉換
using TransformReaderType =
itk::TransformFileReaderTemplate<ReadScalarType>;
TransformReaderType::Pointer reader = TransformReaderType::New();
// 設定檔案名稱
reader->SetFileName(transformFileName);
// 讀取轉換
try {
reader->Update();
} catch (itk::ExceptionObject & excp) {
std::cerr << "Error while reading the transform file" << std::endl;
std::cerr << excp << std::endl;
std::cerr << "[FAILED]" << std::endl;
return EXIT_FAILURE;
}
// 取得轉換列表
const TransformReaderType::TransformListType * transforms =
reader->GetTransformList();
// 轉換數量
std::cout << "Number of transforms = " << transforms->size() << std::endl;
// 各個轉換可以使用 STL 的 iterator 取出,再轉型為適合的轉換型別
using ReadCompositeTransformType =
itk::CompositeTransform<ReadScalarType, Dimension>;
auto it = transforms->begin();
if (!strcmp((*it)->GetNameOfClass(), "CompositeTransform")) {
ReadCompositeTransformType::Pointer compositeRead =
static_cast<ReadCompositeTransformType *>((*it).GetPointer());
compositeRead->Print(std::cout);
}
return EXIT_SUCCESS;
}
將此程式碼儲存為 TransformReadWrite.cxx,搭配以下 CMakeLists.txt 以 CMake 編譯:
cmake_minimum_required(VERSION 3.10.2)
# 設定專案名稱
project(TransformReadWrite)
# 尋找並引入 ITK 函式庫
find_package(ITK REQUIRED)
include(${ITK_USE_FILE})
# 增加一個執行檔
add_executable(TransformReadWrite TransformReadWrite.cxx)
# 定義執行檔連結方式
target_link_libraries(TransformReadWrite ${ITK_LIBRARIES})
以下是編譯與執行的指令:
# 編譯程式
mkdir build
cd build
cmake ..
# 執行程式(以 txt 檔案儲存)
./TransformReadWrite transform.txt
# 執行程式(以 HDF5 檔案儲存)
./TransformReadWrite transform.h5
