介紹如何使用 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