opynsim
Unofficial C++ Documentation
Loading...
Searching...
No Matches
scaling_cache.h
Go to the documentation of this file.
1#pragma once
2
9#include <libopynsim/tps3d.h>
10
18#include <OpenSim/Simulation/Model/Model.h>
19#include <SimTKcommon/internal/Transform.h>
20#include <SimTKcommon/internal/Rotation.h>
21#include <SimTKcommon/SmallMatrix.h>
22
23#include <memory>
24#include <utility>
25
26namespace opyn
27{
28 // A cache that is (presumed to be) persisted between multiple executions of the
29 // model warping pipeline, in order to improve runtime performance.
30 class ScalingCache final {
31 public:
32 std::unique_ptr<InMemoryMesh> lookupTPSMeshWarp(
33 const OpenSim::Model& sourceModel,
34 const OpenSim::Model& resultModel,
35 const OpenSim::Mesh& sourceMesh,
36 const OpenSim::Mesh& resultMesh,
37 const OpenSim::Frame& sourceLandmarksFrame,
38 const OpenSim::Frame& resultLandmarksFrame,
39 const ThinPlateSplineCommonInputs& tpsInputs,
40 bool compensateForFrameChanges)
41 {
42 // Compile the TPS coefficients from the source+destination landmarks
43 const TPSCoefficients3D<float>& coefficients = lookupTPSCoefficients(tpsInputs);
44
45 // Calculate transforms to use before/after TPS warping
46 const Transforms transforms = calculateTransforms(
47 sourceModel,
48 resultModel,
49 sourceMesh.getFrame(),
50 resultMesh.getFrame(),
51 sourceLandmarksFrame,
52 resultLandmarksFrame,
53 compensateForFrameChanges
54 );
55
56 // Convert the input mesh into an OSC mesh, so that it's suitable for warping.
57 osc::Mesh resultOscMesh = ToOscMesh(
58 resultModel,
59 resultModel.getWorkingState(),
60 resultMesh
61 );
62
63 // Warp the vertices in-place.
64 auto vertices = resultOscMesh.vertices();
65 for (auto& vertex : vertices) {
66 vertex = transform_point(transforms.localToLandmarks, vertex); // put vertex into landmark frame
67 }
68 static_assert(alignof(decltype(vertices.front())) == alignof(SimTK::fVec3));
69 static_assert(sizeof(decltype(vertices.front())) == sizeof(SimTK::fVec3));
70 auto* punned = std::launder(reinterpret_cast<SimTK::fVec3*>(vertices.data()));
71 tps3d_warp_points_in_place(coefficients, {punned, vertices.size()}, static_cast<float>(tpsInputs.blendingFactor));
72 for (auto& vertex : vertices) {
73 vertex = transform_point(transforms.landmarksToLocal, vertex); // put vertex back into mesh frame
74 }
75
76 // Assign the vertices back to the OSC mesh and emit it as an `InMemoryMesh` component
77 resultOscMesh.set_vertices(vertices);
78 resultOscMesh.recalculate_normals(); // maybe should be a runtime param
79 return std::make_unique<InMemoryMesh>(resultOscMesh);
80 }
81
83 const OpenSim::Model& sourceModel,
84 const OpenSim::Model& resultModel,
85 [[maybe_unused]] const SimTK::Vec3& sourceLocation,
86 const SimTK::Vec3& resultLocation,
87 const OpenSim::Frame& sourceParentFrame,
88 const OpenSim::Frame& resultParentFrame,
89 const OpenSim::Frame& sourceLandmarksFrame,
90 const OpenSim::Frame& resultLandmarksFrame,
91 const ThinPlateSplineCommonInputs& tpsInputs,
92 bool compensateForFrameChanges)
93 {
94 // Compile the TPS coefficients from the source+destination landmarks
95 const TPSCoefficients3D<float>& coefficients = lookupTPSCoefficients(tpsInputs);
96
97 // Calculate transforms to use before/after TPS warping
98 const Transforms transforms = calculateTransforms(
99 sourceModel,
100 resultModel,
101 sourceParentFrame,
102 resultParentFrame,
103 sourceLandmarksFrame,
104 resultLandmarksFrame,
105 compensateForFrameChanges
106 );
107
108 const auto resultLocationInLandmarkFrame = transform_point(transforms.localToLandmarks, osc::to<osc::Vector3>(resultLocation));
109 const auto warpedLocationInLandmarkFrame = tps3d_warp_point(coefficients, osc::to<SimTK::fVec3>(resultLocationInLandmarkFrame), static_cast<float>(tpsInputs.blendingFactor));
110 return osc::to<SimTK::Vec3>(osc::transform_point(transforms.landmarksToLocal, osc::to<osc::Vector3>(warpedLocationInLandmarkFrame)));
111 }
112
114 const ThinPlateSplineCommonInputs& tpsInputs)
115 {
116 OSC_ASSERT_ALWAYS(tpsInputs.applyAffineRotation && "affine rotation must be requested in order to figure out the transform");
117 OSC_ASSERT_ALWAYS(tpsInputs.applyAffineTranslation && "affine translation must be requested in order to figure out the transform");
118 const TPSCoefficients3D<float>& coefficients = lookupTPSCoefficients(tpsInputs);
119
120 const SimTK::Vec<3, float> x = coefficients.a2.normalize();
121 const SimTK::Vec<3, float> y = coefficients.a3.normalize();
122 const SimTK::Vec<3, float> z = coefficients.a4.normalize();
123 const SimTK::Mat33 rotationMatrix{
124 x[0], y[0], z[0],
125 x[1], y[1], z[1],
126 x[2], y[2], z[2],
127 };
128 const SimTK::Rotation rotation{rotationMatrix};
129 const auto translation = osc::to<SimTK::Vec3>(coefficients.a1);
130 return SimTK::Transform{rotation, translation};
131 }
132 private:
133 struct Transforms final {
134 osc::Matrix4x4 localToLandmarks;
135 osc::Matrix4x4 landmarksToLocal;
136 };
137
138 Transforms calculateTransforms(
139 const OpenSim::Model& sourceModel,
140 const OpenSim::Model& resultModel,
141 const OpenSim::Frame& sourceFrame,
142 const OpenSim::Frame& resultFrame,
143 const OpenSim::Frame& sourceLandmarksFrame,
144 const OpenSim::Frame& resultLandmarksFrame,
145 bool compensateForFrameChanges) const
146 {
147 const SimTK::Transform resultTransform = resultFrame.findTransformBetween(resultModel.getWorkingState(), resultLandmarksFrame);
148
149 if (compensateForFrameChanges) {
150 const SimTK::Transform sourceTransform = sourceFrame.findTransformBetween(sourceModel.getWorkingState(), sourceLandmarksFrame);
151 const SimTK::Transform frameWarpTransform = sourceTransform.invert() * resultTransform;
152 return Transforms{
153 .localToLandmarks = osc::to<osc::Matrix4x4>(sourceTransform),
154 .landmarksToLocal = osc::to<osc::Matrix4x4>(frameWarpTransform.invert() * sourceTransform.invert()),
155 };
156 } else {
157 return Transforms{
158 .localToLandmarks = osc::to<osc::Matrix4x4>(resultTransform),
159 .landmarksToLocal = osc::to<osc::Matrix4x4>(SimTK::Transform{resultTransform.invert()}),
160 };
161 }
162 }
163
164 const TPSCoefficients3D<float>& lookupTPSCoefficients(const ThinPlateSplineCommonInputs& tpsInputs)
165 {
166 // Read source+destination landmark files into independent collections
167 const auto sourceLandmarks = ReadLandmarksFromCSVIntoVectorOrThrow(tpsInputs.sourceLandmarksPath);
168 const auto destinationLandmarks = ReadLandmarksFromCSVIntoVectorOrThrow(tpsInputs.destinationLandmarksPath);
169
170 // Pair the source+destination landmarks together into a TPS coefficient solver's inputs
171 TPSCoefficientSolverInputs3D<float> inputs;
172 inputs.landmarks.reserve(osc::max(sourceLandmarks.size(), destinationLandmarks.size()));
173 TryPairingLandmarks(sourceLandmarks, destinationLandmarks, [&inputs, &tpsInputs](const MaybeNamedLandmarkPair& p)
174 {
175 if (auto landmark3d = p.tryGetPairedLocations()) {
176 landmark3d->source = tpsInputs.sourceLandmarksPrescale * landmark3d->source;
177 landmark3d->destination = tpsInputs.destinationLandmarksPrescale * landmark3d->destination;
178 inputs.landmarks.push_back(*landmark3d);
179 }
180 else {
181 osc::log_warn("The landmarks %s could not be paired, might be missing in the source/destination?", p.name().c_str());
182 }
183 });
184 inputs.apply_affine_translation = tpsInputs.applyAffineTranslation;
185 inputs.apply_affine_scale = tpsInputs.applyAffineScale;
186 inputs.apply_affine_rotation = tpsInputs.applyAffineRotation;
187 inputs.apply_non_affine_warp = tpsInputs.applyNonAffineWarp;
188 inputs.warping_penalty = static_cast<float>(tpsInputs.warpingPenalty);
189
190 // Solve the coefficients
191 m_CoefficientsTODO = opyn::tps3d_solve_coefficients(inputs);
192
193 return m_CoefficientsTODO;
194 }
195
196 TPSCoefficients3D<float> m_CoefficientsTODO;
197 };
198}
#define OSC_ASSERT_ALWAYS(expr)
Definition assertions.h:20
Definition scaling_cache.h:30
SimTK::Transform lookupTPSAffineTransformWithoutScaling(const ThinPlateSplineCommonInputs &tpsInputs)
Definition scaling_cache.h:113
SimTK::Vec3 lookupTPSWarpedRigidPoint(const OpenSim::Model &sourceModel, const OpenSim::Model &resultModel, const SimTK::Vec3 &sourceLocation, const SimTK::Vec3 &resultLocation, const OpenSim::Frame &sourceParentFrame, const OpenSim::Frame &resultParentFrame, const OpenSim::Frame &sourceLandmarksFrame, const OpenSim::Frame &resultLandmarksFrame, const ThinPlateSplineCommonInputs &tpsInputs, bool compensateForFrameChanges)
Definition scaling_cache.h:82
std::unique_ptr< InMemoryMesh > lookupTPSMeshWarp(const OpenSim::Model &sourceModel, const OpenSim::Model &resultModel, const OpenSim::Mesh &sourceMesh, const OpenSim::Mesh &resultMesh, const OpenSim::Frame &sourceLandmarksFrame, const OpenSim::Frame &resultLandmarksFrame, const ThinPlateSplineCommonInputs &tpsInputs, bool compensateForFrameChanges)
Definition scaling_cache.h:32
Definition mesh.h:33
void set_vertices(std::span< const Vector3 >)
void recalculate_normals()
std::vector< Vector3 > vertices() const
Definition component_registry.h:14
void tps3d_warp_points_in_place(const TPSCoefficients3D< float > &, std::span< SimTK::Vec< 3, float > >, 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)
void TryPairingLandmarks(std::vector< Landmark >, std::vector< Landmark >, const std::function< void(const MaybeNamedLandmarkPair &)> &consumer)
std::vector< Landmark > ReadLandmarksFromCSVIntoVectorOrThrow(const std::filesystem::path &)
osc::Mesh ToOscMesh(osc::SceneCache &, const OpenSim::Model &, const SimTK::State &, const OpenSim::Mesh &, const OpenSimDecorationOptions &, float fixupScaleFactor)
Vector3 transform_point(const Matrix4x4 &mat, const Vector3 &point)
Definition math_helpers.h:140
constexpr auto max(Angle< Rep1, Units1 > x, Angle< Rep2, Units2 > y) -> std::common_type_t< decltype(x), decltype(y)>
Definition angle.h:283
constexpr U to(T &&value)
Definition conversion.h:56
Definition tps3d.h:131
SimTK::Vec< 3, T > a1
Definition tps3d.h:138
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
Definition thin_plate_spline_common_inputs.h:10
bool applyAffineTranslation
Definition thin_plate_spline_common_inputs.h:32
double blendingFactor
Definition thin_plate_spline_common_inputs.h:36
bool applyAffineRotation
Definition thin_plate_spline_common_inputs.h:34