opynsim
Unofficial C++ Documentation
Loading...
Searching...
No Matches
tps3d.h
Go to the documentation of this file.
1#pragma once
2
5
6#include <SimTKcommon/SmallMatrix.h>
8
9#include <concepts>
10#include <iosfwd>
11#include <span>
12#include <utility>
13#include <vector>
14
15// Thin Plate Spline (TPS), 3D implementation.
16//
17// Most of the background behind this is discussed in OpenSim Creator's TPS documentation.
18//
19// Here are links to some of the reference material used to write this implementation:
20//
21// - Primary literature source: https://ieeexplore.ieee.org/document/24792
22// - Blog explanation: https://profs.etsmtl.ca/hlombaert/thinplates/
23// - Blog explanation #2: https://khanhha.github.io/posts/Thin-Plate-Splines-Warping/
24namespace opyn
25{
26 // Represents the inputs of the Thin-Plate Spline (TPS) warping algorithm.
27 //
28 // These are supplied by the caller to solve the necessary TPS coefficients.
29 template<std::floating_point T>
31
33
34 explicit TPSCoefficientSolverInputs3D(std::vector<LandmarkPair3D<T>> landmarks_) :
35 landmarks{std::move(landmarks_)}
36 {}
37
39
40 // A sequence of source-to-destination point pairs in 3D that the TPS
41 // warping algorithm is trying to fit a warping equation to.
42 std::vector<LandmarkPair3D<T>> landmarks;
43
44 // A warping penalty term that smooths out the solution. The term originates
45 // in the academic literature from:
46 //
47 // > "Do we need medical imaging-informed musculoskeletal models..."?
48 // > E. Stansfield, W. Koller, B. Goncalves, H. Zainz, PLOS Comp. Biol.
49 // > https://doi.org/10.1371/journal.pcbi.1014073
50 //
51 // Which used a Python library (PyPi: thin-plate-spline) that provides
52 // the functionality via a term it calls `alpha`:
53 //
54 // > https://github.com/raphaelreme/tps/blob/v1.2.2/src/tps/thin_plate_spline.py#L141
55 //
56 // The academic paper refers to it as "[TPS] bending strength was penalized" (p13). Whereas
57 // the library calls it "regularization strength".
58 //
59 // This can be a useful parameter to fiddle when working with some datasets (e.g. in the paper
60 // they used a `warping_penalty` of `0.001` for muscle points, determined experimentally.
61 T warping_penalty{}; // By default, no penalty is applied.
62
63 // Set this to `true` if the resulting warping equation should translate
64 // points in the source coordinate system to the destination coordinate
65 // system (i.e. enable/disable writing `a1`).
67
68 // Set this to `true` if the resulting warping equation should scale
69 // points in the source coordinate system to the destination coordinate
70 // system (i.e. disable/enable normalizing `a2`-`a4`).
71 bool apply_affine_scale = true;
72
73 // Set this to `true` if the resulting warping equation should rotate
74 // points in the source coordinate system to the destination coordinate
75 // system (i.e. disable/enable the change-of-basis part of `a2`-`a4`).
77
78 // Set this to `true` if the resulting warping equation should apply
79 // non-affine warping to points in the source coordinate system when
80 // mapping to the destination coordinate system (i.e. "the bendy parts"
81 // of the warp, or `non_affine_terms`.
83 };
84
85 // Pretty-prints solver inputs for readability/debugging.
86 std::ostream& operator<<(std::ostream&, const TPSCoefficientSolverInputs3D<float>&);
87
88 // Pretty-prints solver inputs for readability/debugging.
89 std::ostream& operator<<(std::ostream&, const TPSCoefficientSolverInputs3D<double>&);
90
91 // Represents a non-affine term of the 3D Thin-Plate Spline (TPS) equation.
92 //
93 // In the literature, the TPS warping equation is usually written:
94 //
95 // f(p) = a1 + a2*p.x + a3*p.y + a4*p.z + SUM{ wi * U(||control_point - p||) }
96 //
97 // This class encodes the `wi` and `control_point` parts of that equation. It can
98 // be colloquially thought of as the "non-affine" or "bendy" parts of the warping
99 // operation.
100 template<std::floating_point T>
101 struct TPSNonAffineTerm3D final {
102
104 const SimTK::Vec<3, T>& weight_,
105 const SimTK::Vec<3, T>& control_point_) :
106
107 weight{weight_},
108 control_point{control_point_}
109 {}
110
111 friend bool operator==(const TPSNonAffineTerm3D&, const TPSNonAffineTerm3D&) = default;
112
113 SimTK::Vec<3, T> weight;
114 SimTK::Vec<3, T> control_point;
115 };
116
117 // Pretty-prints a non-affine term for readability/debugging.
118 std::ostream& operator<<(std::ostream&, const TPSNonAffineTerm3D<float>&);
119
120 // Pretty-prints a non-affine term for readability/debugging.
121 std::ostream& operator<<(std::ostream&, const TPSNonAffineTerm3D<double>&);
122
123 // Represents all the coefficients of a 3D Thin-Plate Spline (TPS) point
124 // warping equation.
125 //
126 // In the literature, these are usually represented as the `a1`, `a2`, `a3`,
127 // `a4`, and `{w, control_point}` terms. These coefficients can be used to
128 // warp a point in the source coordinate system into the destination coordinate
129 // system.
130 template<std::floating_point T>
131 struct TPSCoefficients3D final {
132
133 // Constructs the coefficients of an identity warping operation.
134 TPSCoefficients3D() = default;
135
136 friend bool operator==(const TPSCoefficients3D&, const TPSCoefficients3D&) = default;
137
138 SimTK::Vec<3, T> a1 = {T{0.0}, T{0.0}, T{0.0}};
139 SimTK::Vec<3, T> a2 = {T{1.0}, T{0.0}, T{0.0}};
140 SimTK::Vec<3, T> a3 = {T{0.0}, T{1.0}, T{0.0}};
141 SimTK::Vec<3, T> a4 = {T{0.0}, T{0.0}, T{1.0}};
142 std::vector<TPSNonAffineTerm3D<T>> non_affine_terms;
143 };
144
145 // Pretty-prints the coefficients for readability/debugging.
146 std::ostream& operator<<(std::ostream&, const TPSCoefficients3D<float>&);
147
148 // Pretty-prints the coefficients for readability/debugging.
149 std::ostream& operator<<(std::ostream&, const TPSCoefficients3D<double>&);
150
151 // Returns the coefficients of a 3D Thin-Plate Spline (TPS) point warping equation
152 // computed from the inputs.
154
155 // Returns the coefficients of a 3D Thin-Plate Spline (TPS) point warping equation
156 // computed from the inputs.
158
159 // Returns the coefficients of a 3D Thin-Plate Spline (TPS) point warping equation
160 // computed by reading source/destination landmark pairs from two strided
161 // multidimensional spans.
162 //
163 // This enables providing the point data from arbitrary third-party representations,
164 // such as the buffer layout of a Python scripting environment.
166 cpp23::mdspan<const double, cpp23::extents<size_t, std::dynamic_extent, 3>, cpp23::layout_stride> source_landmarks,
167 cpp23::mdspan<const double, cpp23::extents<size_t, std::dynamic_extent, 3>, cpp23::layout_stride> destination_landmarks,
168 double warping_penalty = 0.0
169 );
170
171 // Returns a warped point computed by evaluating a 3D Thin-Plate Spline (TPS)
172 // warping equation with `p`, which should be a point in the source coordinate
173 // system.
174 SimTK::Vec<3, float> tps3d_warp_point(
176 const SimTK::Vec<3, float>& p
177 );
178
179 // Returns a warped point computed by evaluating a 3D Thin-Plate Spline (TPS)
180 // warping equation with `p`, which should be a point in the source coordinate
181 // system.
182 SimTK::Vec<3, double> tps3d_warp_point(
184 const SimTK::Vec<3, double>&
185 );
186
187 // Returns a point that is linearly interpolated between `p` and a warped point
188 // computed by evaluating a 3D Thin-Plate Spline (TPS) warping equation with `p`
189 // by `linear_interpolant`.
190 //
191 // - `p` should be a point in the source coordinate system
192 // - `linear_interpolant` should be a floating point value that indicates the
193 // linear interpolation factor between `p` and the warped point. `0.0` means
194 // `p`, `1.0` means "the warped point". Values outside [0.0, 1.0] are
195 // linearly extrapolated.
196 SimTK::Vec<3, float> tps3d_warp_point(
198 const SimTK::Vec<3, float>& p,
199 float linear_interpolant
200 );
201
202 // returns points that are the equivalent of applying the 3D TPS warp to each input point
203 std::vector<SimTK::Vec<3, float>> tps3d_warp_points(
205 std::span<const SimTK::Vec<3, float>>,
206 float linear_interpolant
207 );
208
209 // applies the 3D TPS warp in-place to each SimTK::Vec3 in the provided span
212 std::span<SimTK::Vec<3, float>>,
213 float linear_interpolant
214 );
215
218 const osc::Mesh&,
219 float linear_interpolant
220 );
221}
Definition mesh.h:33
Definition component_registry.h:14
void tps3d_warp_points_in_place(const TPSCoefficients3D< float > &, std::span< SimTK::Vec< 3, float > >, float linear_interpolant)
osc::Mesh tps3d_warp_mesh(TPSCoefficients3D< float > &, const osc::Mesh &, float linear_interpolant)
TPSCoefficients3D< float > tps3d_solve_coefficients(const TPSCoefficientSolverInputs3D< float > &)
SimTK::Vec< 3, float > tps3d_warp_point(const TPSCoefficients3D< float > &, const SimTK::Vec< 3, float > &p)
std::ostream & operator<<(std::ostream &out, const DataFrame &data_frame)
Writes a pretty-printed representation of data_frame to out.
std::vector< SimTK::Vec< 3, float > > tps3d_warp_points(const TPSCoefficients3D< float > &, std::span< const SimTK::Vec< 3, float > >, float linear_interpolant)
Definition landmark_pair_3d.h:14
bool apply_affine_translation
Definition tps3d.h:66
bool apply_non_affine_warp
Definition tps3d.h:82
bool apply_affine_rotation
Definition tps3d.h:76
TPSCoefficientSolverInputs3D(std::vector< LandmarkPair3D< T > > landmarks_)
Definition tps3d.h:34
T warping_penalty
Definition tps3d.h:61
bool apply_affine_scale
Definition tps3d.h:71
std::vector< LandmarkPair3D< T > > landmarks
Definition tps3d.h:42
friend bool operator==(const TPSCoefficientSolverInputs3D &, const TPSCoefficientSolverInputs3D &)=default
Definition tps3d.h:131
SimTK::Vec< 3, T > a1
Definition tps3d.h:138
friend bool operator==(const TPSCoefficients3D &, const TPSCoefficients3D &)=default
SimTK::Vec< 3, T > a3
Definition tps3d.h:140
SimTK::Vec< 3, T > a4
Definition tps3d.h:141
SimTK::Vec< 3, T > a2
Definition tps3d.h:139
std::vector< TPSNonAffineTerm3D< T > > non_affine_terms
Definition tps3d.h:142
Definition tps3d.h:101
friend bool operator==(const TPSNonAffineTerm3D &, const TPSNonAffineTerm3D &)=default
SimTK::Vec< 3, T > control_point
Definition tps3d.h:114
TPSNonAffineTerm3D(const SimTK::Vec< 3, T > &weight_, const SimTK::Vec< 3, T > &control_point_)
Definition tps3d.h:103
SimTK::Vec< 3, T > weight
Definition tps3d.h:113