30 inline void dumpKalmanDebugOuput(
const char name[],
const char expr[],
32 std::cout <<
"\n(Kalman Debug Output) " << name <<
" [" << expr <<
"]:\n"
33 << value << std::endl;
50 #include <opencv2/core/eigen.hpp>
57 static const auto LOW_BEACON_CUTOFF = 5;
59 static const auto DIM_BEACON_CUTOFF_TO_SKIP_BRIGHTS = 4;
60 static const auto BRIGHT_PENALTY = 8.;
61 bool BeaconBasedPoseEstimator::m_kalmanAutocalibEstimator(LedGroup &leds,
63 int const beaconsSize = m_beacons.size();
65 double varianceFactor = 1;
70 auto inBoundsID = std::size_t{0};
72 auto skipBright =
false;
74 auto totalLeds = leds.size();
75 auto identified = std::size_t{0};
76 auto inBoundsBright = std::size_t{0};
77 auto inBoundsRound = std::size_t{0};
78 for (
auto const &led : leds) {
79 if (!led.identified()) {
83 auto id = led.getID();
84 if (
id >= beaconsSize) {
92 if (led.getMeasurement().knowBoundingBox()) {
93 auto boundingBoxRatio =
94 led.getMeasurement().boundingBoxSize().height /
95 led.getMeasurement().boundingBoxSize().width;
96 if (boundingBoxRatio > minBoxRatio &&
97 boundingBoxRatio < maxBoxRatio) {
108 if (inBoundsID < LOW_BEACON_CUTOFF) {
109 varianceFactor = 0.5;
113 if (inBoundsID - inBoundsBright >
114 DIM_BEACON_CUTOFF_TO_SKIP_BRIGHTS &&
118 if (0 == inBoundsID) {
119 m_framesWithoutIdentifiedBlobs++;
121 m_framesWithoutIdentifiedBlobs = 0;
126 cam.focalLength = m_camParams.focalLength();
127 cam.principalPoint = cvToVector(m_camParams.principalPoint());
128 ImagePointMeasurement meas{cam};
130 kalman::ConstantProcess<kalman::PureVectorState<>> beaconProcess;
132 const auto maxSquaredResidual =
135 kalman::predict(m_state, m_model, dt);
139 Eigen::Matrix3d rotate =
141 auto numBad = std::size_t{0};
142 auto numGood = std::size_t{0};
143 for (
auto &led : leds) {
144 if (!led.identified()) {
147 auto id = led.getID();
148 if (
id >= beaconsSize) {
152 auto &debug = m_beaconDebugData[id];
154 debug.measurement = led.getLocation();
155 if (skipBright && led.isBright()) {
167 (rotate * cvToVector(m_beaconEmissionDirection[
id])).z();
168 if (zComponent > 0.) {
170 std::cout <<
"Rejecting an LED at " << led.getLocation()
171 <<
" claiming ID " << led.getOneBasedID()
176 led.markMisidentified();
183 }
else if (zComponent > maxZComponent) {
190 if (led.getMeasurement().knowBoundingBox) {
195 auto boundingBoxRatio =
196 led.getMeasurement().boundingBox.height /
197 led.getMeasurement().boundingBox.width;
198 if (boundingBoxRatio < minBoxRatio ||
199 boundingBoxRatio > maxBoxRatio) {
207 auto localVarianceFactor = varianceFactor;
208 auto newIdentificationVariancePenalty =
209 std::pow(2.0, led.novelty());
213 if (m_beaconFixed[
id]) {
214 beaconProcess.setNoiseAutocorrelation(0);
216 beaconProcess.setNoiseAutocorrelation(
218 kalman::predict(*(m_beacons[
id]), beaconProcess, dt);
222 Eigen::Vector2d(led.getLocation().x, led.getLocation().y));
225 meas.updateFromState(state);
226 Eigen::Vector2d residual = meas.getResidual(state);
227 if (residual.squaredNorm() > maxSquaredResidual) {
234 debug.residual.x = residual.x();
235 debug.residual.y = residual.y();
236 auto effectiveVariance =
238 newIdentificationVariancePenalty *
239 (led.isBright() ? BRIGHT_PENALTY : 1.) *
240 m_beaconMeasurementVariance[id] / led.getMeasurement().area;
241 debug.variance = effectiveVariance;
242 meas.setVariance(effectiveVariance);
248 m_gotMeasurement =
true;
252 bool incrementProbation =
false;
253 if (0 == m_framesInProbation) {
256 incrementProbation = (numBad * 3 > numGood * 2);
261 incrementProbation = numBad * 2 > numGood;
262 if (!incrementProbation) {
264 m_framesInProbation = 0;
267 if (incrementProbation) {
268 m_framesInProbation++;
272 if (m_gotMeasurement) {
273 m_framesWithoutUtilizedMeasurements = 0;
275 if (inBoundsID > 0) {
278 m_framesWithoutUtilizedMeasurements++;
284 m_rvec = eiQuatToRotVec(m_state.getQuaternion());
285 cv::eigen2cv(m_state.position().eval(), m_tvec);
290 BeaconBasedPoseEstimator::GetPredictedState(
double dt)
const {
291 auto state = m_state;
292 auto model = m_model;
293 kalman::predict(state, model, dt);
296 util::eigen_interop::map(ret).
rotation() = state.getQuaternion();
297 util::eigen_interop::map(ret).translation() =
298 m_convertInternalPositionRepToExternal(state.position());
DeducedAugmentedProcessModel< ModelA, ModelB > makeAugmentedProcessModel(ModelA &a, ModelB &b)
float boundingBoxFilterRatio
double highResidualVariancePenalty
OSVR_Quaternion rotation
Orientation as a unit quaternion.
Header wrapping include of and for warning quieting.
Eigen::Quaterniond getCombinedQuaternion() const
bool extraVerbose
Extra verbose developer debugging messages.
Header file for class that tracks and identifies LEDs.
double beaconProcessNoise
bool shouldSkipBrightLeds
double measurementVarianceScaleFactor
A structure defining a 3D (6DOF) rigid body pose: translation and rotation.
Header for interoperation between the Eigen math library, the internal mini math library, and VRPN's quatlib.
bool correct(StateType &state, ProcessModelType &processModel, MeasurementType &meas, bool cancelIfNotFinite=true)
DeducedAugmentedState< StateA, StateB > makeAugmentedState(StateA &a, StateB &b)
Factory function, akin to std::tie(), to make an augmented state.