OSVR-Core
ImagePointMeasurement.h
Go to the documentation of this file.
1 
11 // Copyright 2015 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_ImagePointMeasurement_h_GUID_BE292A08_8C31_4987_E179_CD2F0CE63183
26 #define INCLUDED_ImagePointMeasurement_h_GUID_BE292A08_8C31_4987_E179_CD2F0CE63183
27 
28 // Internal Includes
29 #include "ProjectPoint.h"
32 #include <osvr/Kalman/PoseState.h>
34 
35 // Library/third-party includes
36 // - none
37 
38 // Standard includes
39 // - none
40 
41 namespace osvr {
42 namespace vbtracker {
43  using AugmentedStateWithBeacon =
44  kalman::AugmentedState<kalman::pose_externalized_rotation::State,
45  kalman::PureVectorState<3>>;
46  struct CameraModel {
47  Eigen::Vector2d principalPoint;
48  double focalLength;
49  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
50  };
54  public:
55  static const kalman::types::DimensionType DIMENSION = 2;
59  using Jacobian =
60  kalman::types::Matrix<DIMENSION,
62  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
63  explicit ImagePointMeasurement(CameraModel const &cam,
64  Eigen::Vector3d const &targetFromBody)
65  : m_variance(SquareMatrix::Identity()), m_cam(cam),
66  m_targetFromBody(targetFromBody) {}
67 
69  void updateFromState(State const &state) {
70  // 3d position of beacon
71  m_beacon = m_targetFromBody + state.b().stateVector();
72  m_rot = state.a().getCombinedQuaternion().toRotationMatrix();
73  m_objExtRot = state.a().getQuaternion() * m_beacon;
74  m_incRot = state.a().incrementalOrientation();
75  m_rotatedObjPoint = m_rot * m_beacon;
76  m_rotatedTranslatedPoint = m_rotatedObjPoint + state.a().position();
77  m_xlate = state.a().position();
78  }
79 
80  Eigen::Vector3d const &getBeaconInCameraSpace() const {
81  return m_rotatedTranslatedPoint;
82  }
83 
84  Vector getResidual(State const &state) const {
85  // 3d position of beacon
86  Eigen::Vector2d predicted =
87  projectPoint(m_cam.focalLength, m_cam.principalPoint,
88  m_rotatedTranslatedPoint);
89  return m_measurement - predicted;
90  }
91 
92  void setMeasurement(Vector const &m) { m_measurement = m; }
93  Eigen::Matrix<double, 2, 3> getBeaconJacobian() const {
94  auto v1 = m_rot(0, 2) * m_beacon[2] + m_rot(0, 1) * m_beacon[1] +
95  m_beacon[0] * m_rot(0, 0) + m_xlate[0];
96  auto v2 = m_beacon[2] * m_rot(2, 2) + m_beacon[1] * m_rot(2, 1) +
97  m_beacon[0] * m_rot(2, 0) + m_xlate[2];
98  auto v3 = 1 / (v2 * v2);
99  auto v4 = 1 / v2;
100  auto v5 = m_rot(1, 2) * m_beacon[2] + m_beacon[1] * m_rot(1, 1) +
101  m_beacon[0] * m_rot(1, 0) + m_xlate[1];
103  ret << m_rot(0, 0) * v4 * m_cam.focalLength -
104  v1 * m_rot(2, 0) * v3 * m_cam.focalLength,
105  m_rot(0, 1) * v4 * m_cam.focalLength -
106  v1 * m_rot(2, 1) * v3 * m_cam.focalLength,
107  m_rot(0, 2) * v4 * m_cam.focalLength -
108  v1 * m_rot(2, 2) * v3 * m_cam.focalLength,
109  m_rot(1, 0) * v4 * m_cam.focalLength -
110  v5 * m_rot(2, 0) * v3 * m_cam.focalLength,
111  m_rot(1, 1) * v4 * m_cam.focalLength -
112  v5 * m_rot(2, 1) * v3 * m_cam.focalLength,
113  m_rot(1, 2) * v4 * m_cam.focalLength -
114  v5 * m_rot(2, 2) * v3 * m_cam.focalLength;
115  return ret;
116  }
117 
120  auto fl = m_cam.focalLength;
121  auto tmp0 = fl / (m_rotatedTranslatedPoint.z() *
122  m_rotatedTranslatedPoint.z());
123  auto tmp1 = 1.0 / m_rotatedTranslatedPoint.z();
124  auto tmp2 = fl * tmp1;
126  ret << -m_rotatedObjPoint.y() * tmp0 * m_rotatedTranslatedPoint.x(),
127  tmp2 * (m_rotatedObjPoint.x() * tmp1 *
128  m_rotatedTranslatedPoint.x() +
129  m_rotatedObjPoint.z()),
130  -m_rotatedObjPoint.y() * tmp2,
131  -tmp2 * (m_rotatedObjPoint.y() * tmp1 *
132  m_rotatedTranslatedPoint.y() +
133  m_rotatedObjPoint.z()),
134  m_rotatedObjPoint.x() * tmp0 * m_rotatedTranslatedPoint.y(),
135  m_rotatedObjPoint.x() * tmp2;
136  return ret;
137  }
138 
142  // just grabbing x and y as an array for component-wise manip right
143  // now.
144  Eigen::Array2d rotXlated =
145  m_rotatedTranslatedPoint.head<2>().array();
146  Eigen::Array2d rotObj = m_rotatedObjPoint.head<2>().array();
147 
148  // Utility because a lot of this requires negatives applied in one
149  // row but not the other.
150  Eigen::Array2d negativePositive(-1, 1);
151  Eigen::Array2d positiveNegative(1, -1);
152  // Some common Z stuff
153  double zRecip = 1. / m_rotatedTranslatedPoint.z();
154  double rotObjZ = m_rotatedObjPoint.z();
155  Eigen::Array2d mainDiagonal =
156  rotXlated * rotObj.reverse() * negativePositive * zRecip;
157  Eigen::Array2d otherDiagonal =
158  (rotObj * rotXlated * zRecip + rotObjZ) * positiveNegative;
159  Eigen::Array2d lastCol = rotObj.reverse() * negativePositive;
161  prelim.leftCols<2>() << mainDiagonal[0], otherDiagonal[0],
162  otherDiagonal[1], mainDiagonal[1];
163  prelim.rightCols<1>() << lastCol.matrix();
164  return prelim * zRecip * m_cam.focalLength;
165  }
166 
167 #if 0
168  Eigen::Matrix<double, 2, 3> getRotationJacobian() const {
173  Eigen::Matrix3d incrotOP;
174  incrotOP.triangularView<Eigen::Upper>() =
175  m_incRot * m_incRot.transpose();
176 
177  auto v1 = 0.5 - incrotOP(1, 2) / 24;
178  auto v2 = 2 * m_incRot[0] * v1;
179  auto v3 = -incrotOP(1, 2) / 6;
180  auto v4 = incrotOP(1, 2) / 6;
181  auto v5 = -(incrotOP(1, 1) * m_incRot[2]) / 24;
182  auto v6 =
183  m_objExtRot[0] * (v5 + v4) + m_objExtRot[1] * (v3 + v2 + 1);
184  auto v7 = -incrotOP(0, 2) / 6;
185  auto v8 = v7 + 1;
186  auto v9 = 0.5 - incrotOP(0, 2) / 24;
187  auto v10 = incrotOP(1, 1) * v9;
188  auto v11 = v3 + 1;
189  auto v12 = incrotOP(0, 0) * v1;
190  auto v13 = m_objExtRot[0] * (v10 - m_incRot[1] * v8) +
191  m_objExtRot[1] * (v12 + m_incRot[0] * v11) +
192  m_objExtRot[2] + m_xlate[2];
193  auto v14 = 1 / (v13 * v13);
194  auto v15 = -incrotOP(0, 1) / 6;
195  auto v16 = v15 + 1;
196  auto v17 = 0.5 - incrotOP(0, 1) / 24;
197  auto v18 = incrotOP(2, 2) * v17;
198  auto v19 = m_objExtRot[2] * (m_incRot[1] * v8 + v10) +
199  m_objExtRot[1] * (v18 - m_incRot[2] * v16) +
200  m_objExtRot[0] + m_xlate[0];
201  auto v20 = 1 / v13;
202  auto v21 = -(m_incRot[1] * incrotOP(2, 2)) / 24;
203  auto v22 = 2 * m_incRot[1] * v9;
204  auto v23 = incrotOP(0, 2) / 6;
205  auto v24 = -(m_incRot[0] * incrotOP(2, 2)) / 24;
206  auto v25 = -(incrotOP(0, 0) * m_incRot[2]) / 24;
207  auto v26 =
208  m_objExtRot[1] * (v7 + v25) + m_objExtRot[0] * (v23 + v22 - 1);
209  auto v27 = incrotOP(0, 1) / 6;
210  auto v28 = 2 * m_incRot[2] * v17;
211  auto v29 = -(m_incRot[0] * incrotOP(1, 1)) / 24;
212  auto v30 = -(incrotOP(0, 0) * m_incRot[1]) / 24;
213  auto v31 =
214  m_objExtRot[1] * (v30 + v15) + m_objExtRot[0] * (v29 + v27);
215  auto v32 = m_objExtRot[0] * (v18 + m_incRot[2] * v16) +
216  m_objExtRot[2] * (v12 - m_incRot[0] * v11) +
217  m_objExtRot[1] + m_xlate[1];
219  ret << v20 * (m_objExtRot[1] * (v21 + v4) +
220  (v5 + v3) * m_objExtRot[2]) *
221  m_cam.focalLength -
222  v6 * v14 * v19 * m_cam.focalLength,
223  v20 * (m_objExtRot[1] * (v24 + v23) +
224  (v22 + v7 + 1) * m_objExtRot[2]) *
225  m_cam.focalLength -
226  v26 * v14 * v19 * m_cam.focalLength,
227  v20 * ((v29 + v15) * m_objExtRot[2] +
228  m_objExtRot[1] * (v28 + v27 - 1)) *
229  m_cam.focalLength -
230  v31 * v14 * v19 * m_cam.focalLength,
231  v20 * (m_objExtRot[0] * (v21 + v3) +
232  (v4 + v2 - 1) * m_objExtRot[2]) *
233  m_cam.focalLength -
234  v6 * v14 * v32 * m_cam.focalLength,
235  v20 * (m_objExtRot[0] * (v24 + v7) +
236  (v25 + v23) * m_objExtRot[2]) *
237  m_cam.focalLength -
238  v26 * v14 * v32 * m_cam.focalLength,
239  v20 * ((v30 + v27) * m_objExtRot[2] +
240  m_objExtRot[0] * (v28 + v15 + 1)) *
241  m_cam.focalLength -
242  v31 * v14 * v32 * m_cam.focalLength;
243  return ret;
244  }
245 #endif
246 
247  Eigen::Matrix<double, 2, 3> getRotationJacobian() const {
248  // return getRotationJacobianNoIncrotElegant();
249  return getRotationJacobianNoIncrot();
250  }
251 
252  Jacobian getJacobian(State const &state) const {
253  Jacobian ret;
254  ret <<
255  // with respect to change in x or y
256  Eigen::Matrix2d::Identity() *
257  (m_cam.focalLength /
258  std::abs(m_rotatedTranslatedPoint.z())),
259  // with respect to change in z
260  -m_rotatedTranslatedPoint.head<2>() * m_cam.focalLength /
261  (m_rotatedTranslatedPoint.z() *
262  m_rotatedTranslatedPoint.z()),
263  // with respect to change in incremental rotation
264  getRotationJacobian(),
265  // with respect to change in linear/angular velocity
267  // with respect to change in beacon position
268  getBeaconJacobian();
269  return ret;
270  }
271 
272  void setVariance(double s) {
273  if (s > 0) {
274 #if 0
275  static const auto VARIANCE_Y_FACTOR = 3.;
276  m_variance << s, 0, 0, (s / VARIANCE_Y_FACTOR);
277 #else
278  m_variance = SquareMatrix::Identity() * s;
279 #endif
280  }
281  }
282  SquareMatrix const &getCovariance(State &state) const {
284  return m_variance;
285  }
286 
287  private:
288  SquareMatrix m_variance;
289  Vector m_measurement;
290  CameraModel m_cam;
291  Eigen::Vector3d m_targetFromBody;
292  Eigen::Vector3d m_beacon;
293  Eigen::Vector3d m_objExtRot;
294  Eigen::Vector3d m_incRot;
295  Eigen::Vector3d m_rotatedObjPoint;
296  Eigen::Vector3d m_rotatedTranslatedPoint;
297  Eigen::Vector3d m_xlate;
298  Eigen::Matrix3d m_rot;
299  };
300 } // namespace vbtracker
301 } // namespace osvr
302 
303 #endif // INCLUDED_ImagePointMeasurement_h_GUID_BE292A08_8C31_4987_E179_CD2F0CE63183
void updateFromState(State const &state)
Updates some internal cached partial solutions.
Definition: ImagePointMeasurement.h:69
typename detail::Dimension_impl< T >::type Dimension
Given a state or measurement, get the dimension as a std::integral_constant.
Definition: FlexibleKalmanBase.h:87
The main namespace for all C++ elements of the framework, internal and external.
Definition: namespace_osvr.dox:3
Eigen::Matrix< double, 2, 3 > getRotationJacobianNoIncrot() const
This version assumes incrot == 0.
Definition: ImagePointMeasurement.h:119
Eigen::Vector2d projectPoint(double focalLength, Eigen::Vector2d const &principalPoint, Eigen::Vector3d const &camPoint)
Project point for a simple pinhole camera model, with focal lengths equal on both axes and no distort...
Definition: ProjectPoint.h:44
View matrix as an upper triangular matrix.
Definition: Constants.h:169
Measurement class for auto-calibrating Kalman filter in video-based tracker.
Definition: ImagePointMeasurement.h:53
Eigen::Matrix< double, 2, 3 > getRotationJacobianNoIncrotElegant() const
This version also assumes incrot == 0 but does the computation in a more elegant (manually factored) ...
Definition: ImagePointMeasurement.h:141
Definition: ImagePointMeasurement.h:46
State type that consists entirely of references to two independent sub-states.
Definition: AugmentedState.h:41
Header.
StateTypeB & b()
Access the second part of the state.
Definition: AugmentedState.h:116
SquareMatrix const & getCovariance(State &state) const
Definition: ImagePointMeasurement.h:282
std::size_t DimensionType
Type for dimensions.
Definition: FlexibleKalmanBase.h:51
The matrix class, also used for vectors and row-vectors.
Definition: Matrix.h:127