Skip to content

Commit 407addb

Browse files
committed
ENH: Add DeformAVolumeWithAThinPlateSpline
Adapted from: https://itk.org/Doxygen/html/Examples_2RegistrationITKv4_2ThinPlateSplineWarp_8cxx-example.html However, we use itk mesh IO to read the point sets, and use the reference image interface to ResampleImageFilter. Both were added since that example was created.
1 parent 490c5fa commit 407addb

14 files changed

+301
-1
lines changed

ITKRepositoryImport.todo

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,6 @@
249249
* ../ITK/Examples/Registration/DeformationFieldJacobian.cxx
250250
* ../ITK/Examples/Registration/ImageRegistration5.tcl
251251
* ../ITK/Examples/Registration/ImageRegistration5.py
252-
* ../ITK/Examples/Registration/ThinPlateSplineWarp.cxx
253252
* ../ITK/Examples/Registration/ImageRegistration4.tcl
254253
* ../ITK/Examples/Registration/ImageRegistration16.cxx
255254
* ../ITK/Examples/Registration/ImageRegistration4.py

src/Core/Transform/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,8 @@ add_example(GlobalRegistrationTwoImagesBSpline)
3939
compare_to_baseline(EXAMPLE_NAME GlobalRegistrationTwoImagesBSpline
4040
BASELINE_PREFIX GlobalRegistrationTwoImagesBSpline
4141
)
42+
43+
add_example(DeformAVolumeWithAThinPlateSpline)
44+
compare_to_baseline(EXAMPLE_NAME DeformAVolumeWithAThinPlateSpline
45+
BASELINE_PREFIX DeformedImageBaseline
46+
)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
cmake_minimum_required(VERSION 3.16.3)
2+
3+
project(DeformAVolumeWithAThinPlateSpline)
4+
5+
find_package(ITK REQUIRED)
6+
include(${ITK_USE_FILE})
7+
8+
add_executable(DeformAVolumeWithAThinPlateSpline Code.cxx)
9+
target_link_libraries(DeformAVolumeWithAThinPlateSpline ${ITK_LIBRARIES})
10+
11+
install(TARGETS DeformAVolumeWithAThinPlateSpline
12+
DESTINATION bin/ITKSphinxExamples/Core/Transform
13+
COMPONENT Runtime
14+
)
15+
16+
install(FILES Code.cxx CMakeLists.txt Code.py
17+
DESTINATION share/ITKSphinxExamples/Code/Core/Transform/DeformAVolumeWithAThinPlateSpline
18+
COMPONENT Code
19+
)
20+
21+
enable_testing()
22+
23+
set(source_landmarks ${CMAKE_CURRENT_BINARY_DIR}/SourceLandmarks.vtk)
24+
set(target_landmarks ${CMAKE_CURRENT_BINARY_DIR}/TargetLandmarks.vtk)
25+
set(input_image ${CMAKE_CURRENT_BINARY_DIR}/brainweb165a10f17.mha)
26+
set(deformed_image DeformedImage.mha)
27+
set(checkerboard_image CheckerBoardImage.mha)
28+
29+
add_test(NAME DeformAVolumeWithAThinPlateSplineTest
30+
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/DeformAVolumeWithAThinPlateSpline
31+
${source_landmarks}
32+
${target_landmarks}
33+
${input_image}
34+
${deformed_image}
35+
${checkerboard_image}
36+
)
37+
38+
if(ITK_WRAP_PYTHON)
39+
find_package(PythonInterp REQUIRED)
40+
string(REPLACE . "Python." deformed_image "${deformed_image}")
41+
add_test(NAME DeformAVolumeWithAThinPlateSplineTestPython
42+
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/Code.py
43+
${source_landmarks}
44+
${target_landmarks}
45+
${input_image}
46+
${deformed_image}
47+
${checkerboard_image}
48+
)
49+
endif()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bafybeido67mh6ekbf4ksqnvohvhjeae3kps6lynmucjiz4goyjafujm6ki
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*=========================================================================
2+
*
3+
* Copyright NumFOCUS
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0.txt
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*=========================================================================*/
18+
19+
#include "itkImageFileReader.h"
20+
#include "itkImageFileWriter.h"
21+
#include "itkImage.h"
22+
#include "itkResampleImageFilter.h"
23+
#include "itkThinPlateSplineKernelTransform.h"
24+
#include "itkPointSet.h"
25+
#include "itkMesh.h"
26+
#include "itkMeshFileReader.h"
27+
#include "itkCheckerBoardImageFilter.h"
28+
29+
int
30+
main(int argc, char * argv[])
31+
{
32+
if (argc != 6)
33+
{
34+
std::cerr << "Usage: " << argv[0];
35+
std::cerr << " <SourceLandmarks>";
36+
std::cerr << " <TargetLandmarks>";
37+
std::cerr << " <InputImage>";
38+
std::cerr << " <DeformedImage>";
39+
std::cerr << " <CheckerBoardImage>";
40+
std::cerr << std::endl;
41+
return EXIT_FAILURE;
42+
}
43+
const char * sourceLandmarksFile = argv[1];
44+
const char * targetLandmarksFile = argv[2];
45+
const char * inputImageFile = argv[3];
46+
const char * deformedImageFile = argv[4];
47+
const char * checkerboardImageFile = argv[5];
48+
49+
constexpr unsigned int Dimension = 3;
50+
using CoordinateRepType = double;
51+
52+
using TransformType = itk::ThinPlateSplineKernelTransform<CoordinateRepType, Dimension>;
53+
using PointSetType = TransformType::PointSetType;
54+
55+
using PixelType = unsigned char;
56+
using MeshType = itk::Mesh<PointSetType::PixelType, Dimension, PointSetType::MeshTraits>;
57+
using ImageType = itk::Image<PixelType, Dimension>;
58+
59+
auto sourceLandmarks = PointSetType::New();
60+
auto targetLandmarks = PointSetType::New();
61+
ImageType::Pointer inputImage;
62+
try
63+
{
64+
auto sourceLandmarksMesh = itk::ReadMesh<MeshType>(sourceLandmarksFile);
65+
sourceLandmarks->SetPoints(sourceLandmarksMesh->GetPoints());
66+
67+
auto targetLandmarksMesh = itk::ReadMesh<MeshType>(targetLandmarksFile);
68+
targetLandmarks->SetPoints(targetLandmarksMesh->GetPoints());
69+
70+
inputImage = itk::ReadImage<ImageType>(inputImageFile);
71+
}
72+
catch (itk::ExceptionObject & error)
73+
{
74+
std::cerr << "Error: " << error << std::endl;
75+
return EXIT_FAILURE;
76+
}
77+
78+
using TransformType = itk::ThinPlateSplineKernelTransform<CoordinateRepType, Dimension>;
79+
80+
auto thinPlateSpline = TransformType::New();
81+
thinPlateSpline->SetSourceLandmarks(sourceLandmarks);
82+
thinPlateSpline->SetTargetLandmarks(targetLandmarks);
83+
thinPlateSpline->ComputeWMatrix();
84+
85+
using ResamplerType = itk::ResampleImageFilter<ImageType, ImageType>;
86+
auto resampler = ResamplerType::New();
87+
88+
resampler->SetInput(inputImage);
89+
90+
using InterpolatorType = itk::LinearInterpolateImageFunction<ImageType, CoordinateRepType>;
91+
auto interpolator = InterpolatorType::New();
92+
resampler->SetInterpolator(interpolator);
93+
94+
resampler->SetUseReferenceImage(true);
95+
resampler->SetReferenceImage(inputImage);
96+
97+
resampler->SetTransform(thinPlateSpline);
98+
99+
using CheckerBoardFilterType = itk::CheckerBoardImageFilter<ImageType>;
100+
auto checkerboardFilter = CheckerBoardFilterType::New();
101+
checkerboardFilter->SetInput1(inputImage);
102+
checkerboardFilter->SetInput2(resampler->GetOutput());
103+
104+
try
105+
{
106+
resampler->Update();
107+
checkerboardFilter->Update();
108+
109+
itk::WriteImage(resampler->GetOutput(), deformedImageFile);
110+
itk::WriteImage(checkerboardFilter->GetOutput(), checkerboardImageFile);
111+
}
112+
catch (itk::ExceptionObject & error)
113+
{
114+
std::cerr << "Error: " << error << std::endl;
115+
return EXIT_FAILURE;
116+
}
117+
118+
return EXIT_SUCCESS;
119+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright NumFOCUS
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# https://www.apache.org/licenses/LICENSE-2.0.txt
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import argparse
18+
import itk
19+
import numpy as np
20+
21+
parser = argparse.ArgumentParser(
22+
description="Deform a Volume With a Thin Plate Spline."
23+
)
24+
parser.add_argument("source_landmarks")
25+
parser.add_argument("target_landmarks")
26+
parser.add_argument("input_image")
27+
parser.add_argument("deformed_image")
28+
parser.add_argument("checker_board_image")
29+
args = parser.parse_args()
30+
31+
Dimension = 3
32+
thin_plate_spline = itk.ThinPlateSplineKernelTransform[itk.D, Dimension].New()
33+
34+
source_landmarks_mesh = itk.meshread(args.source_landmarks)
35+
# Cast points from float32 to float64
36+
points = itk.array_from_vector_container(source_landmarks_mesh.GetPoints())
37+
points = points.astype(np.float64)
38+
source_landmarks = thin_plate_spline.GetSourceLandmarks()
39+
source_landmarks.SetPoints(itk.vector_container_from_array(points.flatten()))
40+
41+
target_landmarks_mesh = itk.meshread(args.target_landmarks)
42+
# Cast points from float32 to float64
43+
points = itk.array_from_vector_container(target_landmarks_mesh.GetPoints())
44+
points = points.astype(np.float64)
45+
target_landmarks = thin_plate_spline.GetTargetLandmarks()
46+
target_landmarks.SetPoints(itk.vector_container_from_array(points.flatten()))
47+
48+
thin_plate_spline.ComputeWMatrix()
49+
50+
input_image = itk.imread(args.input_image)
51+
52+
deformed_image = itk.resample_image_filter(
53+
input_image,
54+
use_reference_image=True,
55+
reference_image=input_image,
56+
transform=thin_plate_spline,
57+
)
58+
itk.imwrite(deformed_image, args.deformed_image)
59+
60+
checker_board = itk.checker_board_image_filter(input_image, deformed_image)
61+
itk.imwrite(checker_board, args.checker_board_image)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bafybeif7peygrvroniic5yqavvxzuctdxqyuzz5tfmba5f63ew6ozpyl4u
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bafybeih4kal3lobtzwsnsoc2vszskc46on3p5ojwa6tqriikca32c6ixum
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
:name: DeformAVolumeWithAThinPlateSpline
2+
3+
Deform a Volume With a Thin Plate Spline
4+
========================================
5+
6+
.. index::
7+
single: ThinPlateSplineKernelTransform
8+
9+
Synopsis
10+
--------
11+
12+
13+
This example deforms a 3D volume with the thin plate spline.
14+
15+
16+
Results
17+
-------
18+
19+
.. figure:: InputImage.png
20+
:width: 640px
21+
:alt: Input image
22+
23+
Input image
24+
25+
.. figure:: DeformedImage.png
26+
:width: 640px
27+
:alt: Deformed image
28+
29+
Deformed image
30+
31+
.. figure:: CheckerBoard.png
32+
:width: 640px
33+
:alt: CheckerBoard image
34+
35+
CheckerBoard image
36+
37+
Code
38+
----
39+
40+
Python
41+
......
42+
43+
.. literalinclude:: Code.py
44+
:language: python
45+
:lines: 1,16-
46+
47+
C++
48+
...
49+
50+
.. literalinclude:: Code.cxx
51+
:language: c++
52+
:lines: 18-
53+
54+
55+
56+
Classes demonstrated
57+
--------------------
58+
59+
.. breathelink:: itk::ThinPlateSplineKernelTransform
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bafybeibzkxiedmtayg43pkunxie6hf6k3oqubepsh4luxjbx4onjeo5ep4

0 commit comments

Comments
 (0)