OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
HDKLedIdentifier.cpp
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 // Internal Includes
26 #include "LED.h"
27 #include "HDKLedIdentifier.h"
28 #include "IdentifierHelpers.h"
29 
30 // Library/third-party includes
31 // - none
32 
33 // Standard includes
34 #include <stdexcept>
35 
36 namespace osvr {
37 namespace vbtracker {
38  static const auto VALIDCHARS = "*.";
39  OsvrHdkLedIdentifier::~OsvrHdkLedIdentifier() {}
40  // Convert from string encoding representations into lists
41  // of boolean values for use in comparison.
43  const PatternStringList &PATTERNS) {
44  // Ensure that we have at least one entry in our list and
45  // find the length of the first valid entry.
46  d_length = 0;
47  if (PATTERNS.empty()) {
48  return;
49  }
50 
51  for (auto &pat : PATTERNS) {
52  if (!pat.empty() && pat.find_first_not_of(VALIDCHARS) == pat.npos) {
53  // All characters in this pattern are valid - we can consider
54  // this to be a valid pattern and thus establish the size.
55  d_length = pat.length();
56  break;
57  }
58  }
59 
60  if (0 == d_length) {
61  // If we still have 0 as the pattern length, return.
62  return;
63  }
64 
65  // Decode each string into a new list of boolean values, making
66  // sure each have the correct length.
67 
68  for (auto &pat : PATTERNS) {
69  if (pat.empty() || pat.find_first_not_of(VALIDCHARS) != pat.npos) {
70  // This is an intentionally disabled beacon/pattern.
71  d_patterns.emplace_back();
72  continue;
73  }
74 
75  // Make sure the pattern is the correct length.
76  if (pat.size() != d_length) {
77  throw std::runtime_error("Got a pattern of incorrect length!");
78  }
79 
80  // Make a wrapped pattern, which is the original pattern plus
81  // a second copy of the pattern that has all but the last
82  // character in it. This will enable use to use the string
83  // find() routine to see if any shift of the pattern is a
84  // match.
85  auto wrapped = pat + pat;
86  wrapped.pop_back();
87  d_patterns.push_back(std::move(wrapped));
88  }
89  }
90 
91  int OsvrHdkLedIdentifier::getId(int currentId,
92  BrightnessList &brightnesses,
93  bool &lastBright, bool blobsKeepId) const {
94  // If we don't have at least the required number of frames of data, we
95  // don't know anything.
96  if (brightnesses.size() < d_length) {
97  return Led::SENTINEL_NO_IDENTIFIER_OBJECT_OR_INSUFFICIENT_DATA;
98  }
99 
100  // We only care about the d_length most-recent levels.
101  truncateBrightnessListTo(brightnesses, d_length);
102 
103  // Compute the minimum and maximum brightness values. If
104  // they are too close to each other, we have a light rather
105  // than an LED. If not, compute a threshold to separate the
106  // 0's and 1's.
107  Brightness minVal, maxVal;
108  std::tie(minVal, maxVal) = findMinMaxBrightness(brightnesses);
109  // Brightness is currently actually keypoint diameter (radius?) in
110  // pixels, and it's being under-estimated by OpenCV.
111  static const double TODO_MIN_BRIGHTNESS_DIFF = 0.3;
112  if (maxVal - minVal <= TODO_MIN_BRIGHTNESS_DIFF) {
113  return Led::SENTINEL_INSUFFICIENT_EXTREMA_DIFFERENCE;
114  }
115  const auto threshold = (minVal + maxVal) / 2;
116  // Set the `lastBright` out variable
117  lastBright = brightnesses.back() >= threshold;
118 
119  if (blobsKeepId && currentId >= 0) {
120  // Early out if we already have identified this LED.
121  return currentId;
122  }
123 
124  // Get a list of boolean values for 0's and 1's using
125  // the threshold computed above.
126  auto bits = getBitsUsingThreshold(brightnesses, threshold);
127 
128  // Search through the available patterns to see if the passed-in
129  // pattern matches any of them. If so, return that pattern. We
130  // need to check all potential rotations of the pattern, since we
131  // don't know when the code started. For the HDK, the codes are
132  // rotationally invariant. We do this by making wrapped strings
133  // and seeing if the pattern shows up anywhe in them, relying on
134  // the std::string find method to do efficiently.
135  for (size_t i = 0; i < d_patterns.size(); i++) {
136  if (d_patterns[i].empty()) {
138  continue;
139  }
140  if (d_patterns[i].find(bits) != std::string::npos) {
141  return static_cast<int>(i);
142  }
143  }
144 
145  // No pattern recognized and we should have recognized one, so return
146  // a low negative. We've used -2 so return -3.
147  return Led::SENTINEL_NO_PATTERN_RECOGNIZED_DESPITE_SUFFICIENT_DATA;
148  }
149 
150 } // End namespace vbtracker
151 } // End namespace osvr
Header file for class that tracks and identifies LEDs.
OsvrHdkLedIdentifier(const PatternStringList &PATTERNS)
Give it a list of patterns to use. There is a string for each LED, and each is encoded with '*' meani...
ZeroBasedBeaconId getId(ZeroBasedBeaconId currentId, BrightnessList &brightnesses, bool &lastBright, bool blobsKeepId) const override
Determine an ID based on a list of brightnesses This truncates the passed-in list to only as many ele...