OSVR-Core
TransformFindingRoutine.h
Go to the documentation of this file.
1 
11 // Copyright 2016 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 #ifndef INCLUDED_TransformFindingRoutine_h_GUID_A09E7693_04E5_4FA2_C929_F23CBEC12306
26 #define INCLUDED_TransformFindingRoutine_h_GUID_A09E7693_04E5_4FA2_C929_F23CBEC12306
27 
28 // Internal Includes
29 #include "OptimizationBase.h"
30 #include "UtilityFunctions.h"
31 #include "newuoa.h"
32 
33 // Library/third-party includes
34 // - none
35 
36 // Standard includes
37 #include <numeric>
38 
39 namespace osvr {
40 namespace vbtracker {
41 
44  void computeRefTrackerTransform(MeasurementsRows const &data,
45  OptimCommonData const &commonData) {
46 
49 
50  TrackedSamples samples;
51  {
52 
53  std::cout << "Starting processing tracking..." << std::endl;
54  auto optim = OptimData::make(commonData);
56  RansacOneEuro ransacOneEuro;
58  for (auto const &rowPtr : data) {
59  // even though we aren't using the results, we have to
60  // include this first to update the LEDs.
61  mainAlgo(optim, *rowPtr);
62  ransacOneEuro(optim, *rowPtr);
63  if (ransacOneEuro.havePose()) {
64  TrackedDataPtr newSample(new TrackedData);
65  newSample->videoPose = ransacOneEuro.getPose();
66  newSample->refPose =
67  makeIsometry(rowPtr->xlate, rowPtr->rot);
68  samples.emplace_back(std::move(newSample));
69  }
70  }
71 
72  std::cout << "Initial tracking complete: " << samples.size()
73  << " valid samples, " << ransacOneEuro.getNumFlips()
74  << " flipped." << std::endl;
75  }
76 
77  if (samples.empty()) {
78 
79  std::cout << "No samples with pose?" << std::endl;
80  return;
81  }
82 
83  const auto numSamples = samples.size();
84  const double numSamplesDouble = static_cast<double>(numSamples);
85 
86  auto simpleCost = [](Eigen::Isometry3d const &a,
87  Eigen::Isometry3d const &b,
88  double angleScale = 1) {
89  auto angDistance =
91  .angularDistance(Eigen::Quaterniond(b.rotation()));
92  auto linearDistance = (a.translation() - b.translation()).norm();
93  return linearDistance + angleScale * angDistance;
94  };
95 
96  auto maxRuns = 30000;
97  std::cout << "Starting actual optimization procedures..." << std::endl;
98  Vec<3> baseXlate = -Vec<3>(-0.316523, -0.740873, -2.0701);
99 
100  {
101  std::cout << "Optimizing base translation" << std::endl;
102  auto ret = ei_newuoa_wrapped(
103  baseXlate, {1e-6, 1e-1}, 10000,
104  [&](Vec<3> const &vec) -> double {
105  Eigen::Isometry3d baseXform = makeIsometry(vec);
107  return std::accumulate(
108  samples.begin(), samples.end(), 0.0,
109  [&](double prev, TrackedDataPtr const &s) {
111  auto cost = simpleCost(s->videoPose,
112  baseXform * s->refPose, 0);
113  return prev + (cost / numSamplesDouble);
114  });
115  });
116 
117  std::cout << "Result: cost " << ret << std::endl;
118  std::cout << baseXlate.format(getFullFormat()) << "\n" << std::endl;
119  std::cout << "First sample:\n";
120  outputTransformedSample(makeIsometry(baseXlate),
121  Eigen::Isometry3d::Identity(),
122  *(samples[0]));
123  }
124  Vec<6> baseXlateRot = Vec<6>::Zero();
125  baseXlateRot.head<3>() = baseXlate;
126  {
127  std::cout << "\nOptimizing base transform, max runs = " << maxRuns
128  << std::endl;
129  auto ret = ei_newuoa_wrapped(
130  baseXlateRot, {1e-6, 1e-1}, 10000,
131  [&](Vec<6> const &vec) -> double {
132  Eigen::Isometry3d baseXform =
133  makeIsometry(vec.head<3>(), rot_exp(vec.tail<3>()));
135  return std::accumulate(
136  samples.begin(), samples.end(), 0.0,
137  [&](double prev, TrackedDataPtr const &s) {
138  auto cost = simpleCost(s->videoPose,
139  baseXform * s->refPose);
140  return prev + (cost / numSamplesDouble);
141  });
142  });
143  std::cout << "Result: cost " << ret << std::endl;
144  std::cout << baseXlateRot.format(getFullFormat()) << "\n"
145  << std::endl;
146  std::cout << "First sample:\n";
147  outputTransformedSample(
148  makeIsometry(baseXlateRot.head<3>(),
149  rot_exp(baseXlateRot.tail<3>())),
150  Eigen::Isometry3d::Identity(), *(samples[0]));
151  }
152 
153  {
154  using namespace reftracker;
155  TransformParams x = TransformParams::Zero();
156  x.head<3>() = baseXlateRot.head<3>();
157  x.segment<3>(BaseRot) = baseXlateRot.tail<3>();
158 
159  std::cout << "Starting optimization procedure for full transform, "
160  "max runs = "
161  << maxRuns << std::endl;
162  auto ret = ei_newuoa_wrapped(
163  x, {1e-6, 1e-1}, maxRuns,
164  [&](TransformParams const &paramVec) -> double {
165  Eigen::Isometry3d baseXform = getBaseTransform(paramVec);
166  Eigen::Isometry3d innerXform = getInnerTransform(paramVec);
168  return std::accumulate(
169  samples.begin(), samples.end(), 0.0,
170  [&](double prev, TrackedDataPtr const &s) {
171  auto cost = costMeasurement(s->videoPose,
172  baseXform * s->refPose *
173  innerXform);
174  return prev + (cost / numSamplesDouble);
175  });
176  });
177  {
178  std::cout << "Optimizer returned " << ret
179  << " and these parameter values:" << std::endl;
180  std::cout << x.format(getFullFormat()) << std::endl;
181 
182  Eigen::Isometry3d baseXform = getBaseTransform(x);
183  Eigen::Isometry3d innerXform = getInnerTransform(x);
184  std::cout << "The first three samples, transformed for your "
185  "viewing pleasure:\n";
186  for (std::size_t i = 0; i < 3; ++i) {
187  outputTransformedSample(baseXform, innerXform,
188  *(samples[i]));
189  }
190  }
191  }
192  }
193 } // namespace vbtracker
194 } // namespace osvr
195 #endif // INCLUDED_TransformFindingRoutine_h_GUID_A09E7693_04E5_4FA2_C929_F23CBEC12306
Eigen::IOFormat const & getFullFormat()
Use for output of parameters.
Definition: UtilityFunctions.h:61
ConstTranslationPart translation() const
Definition: Transform.h:153
The main namespace for all C++ elements of the framework, internal and external.
Definition: namespace_osvr.dox:3
double ei_newuoa_wrapped(long npt, Eigen::MatrixBase< Derived > &x, std::pair< double, double > rho, long maxfun, Function &&f)
Friendlier wrapper around newuoa: takes a vector for x, and the function takes a reference to const v...
Definition: newuoa.h:1943
Algorithm functor, call after either stage-2 functor: obtains a RANSAC pose and feeds it into a 1-eur...
Definition: OptimizationBase.h:142
LinearMatrixType rotation() const
Definition: Transform.h:598
void computeRefTrackerTransform(MeasurementsRows const &data, OptimCommonData const &commonData)
Optimization routine: compute the transform between the smoothed RANSAC results and the reference tra...
Definition: TransformFindingRoutine.h:44
Definition: UtilityFunctions.h:154
Header for M.J.D.
Algorithm functor to be called in a loop that processes measurements rows: all it does is feed in LED...
Definition: OptimizationBase.h:99
Definition: Quaternion.h:47
Isometry3< typename Derived1::Scalar > makeIsometry(Eigen::MatrixBase< Derived1 > const &translation, Eigen::RotationBase< Derived2, 3 > const &rotation)
A simpler, functional-style alternative to .fromPositionOrientationScale when no scaling is performed...
Definition: EigenExtras.h:93
Input from main to the optimization routine (wrapper)
Definition: OptimizationBase.h:47
double costMeasurement(Eigen::Isometry3d const &refPose, Eigen::Isometry3d const &expPose)
Definition: UtilityFunctions.h:137
Quaternion< double > Quaterniond
double precision quaternion type
Definition: Quaternion.h:211
The matrix class, also used for vectors and row-vectors.
Definition: Matrix.h:127
Definition: Transform.h:43