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 
93  BrightnessList &brightnesses,
94  bool &lastBright, bool blobsKeepId) const {
95  // If we don't have at least the required number of frames of data, we
96  // don't know anything.
97  if (brightnesses.size() < d_length) {
98  return ZeroBasedBeaconId(
99  Led::SENTINEL_NO_IDENTIFIER_OBJECT_OR_INSUFFICIENT_DATA);
100  }
101 
102  // We only care about the d_length most-recent levels.
103  truncateBrightnessListTo(brightnesses, d_length);
104 
105  // Compute the minimum and maximum brightness values. If
106  // they are too close to each other, we have a light rather
107  // than an LED. If not, compute a threshold to separate the
108  // 0's and 1's.
109  Brightness minVal, maxVal;
110  std::tie(minVal, maxVal) = findMinMaxBrightness(brightnesses);
111  // Brightness is currently actually keypoint diameter (radius?) in
112  // pixels, and it's being under-estimated by OpenCV.
113  static const double TODO_MIN_BRIGHTNESS_DIFF = 0.3;
114  if (maxVal - minVal <= TODO_MIN_BRIGHTNESS_DIFF) {
115  return ZeroBasedBeaconId(
116  Led::SENTINEL_INSUFFICIENT_EXTREMA_DIFFERENCE);
117  }
118  const auto threshold = (minVal + maxVal) / 2;
119  // Set the `lastBright` out variable
120  lastBright = brightnesses.back() >= threshold;
121 
122  if (blobsKeepId && beaconIdentified(currentId)) {
123  // Early out if we already have identified this LED.
124  return currentId;
125  }
126 
127  // Get a list of boolean values for 0's and 1's using
128  // the threshold computed above.
129  auto bits = getBitsUsingThreshold(brightnesses, threshold);
130 
131  // Search through the available patterns to see if the passed-in
132  // pattern matches any of them. If so, return that pattern. We
133  // need to check all potential rotations of the pattern, since we
134  // don't know when the code started. For the HDK, the codes are
135  // rotationally invariant. We do this by making wrapped strings
136  // and seeing if the pattern shows up anywhe in them, relying on
137  // the std::string find method to do efficiently.
138  for (size_t i = 0; i < d_patterns.size(); i++) {
139  if (d_patterns[i].empty()) {
141  continue;
142  }
143  if (d_patterns[i].find(bits) != std::string::npos) {
144  return ZeroBasedBeaconId(i);
145  }
146  }
147 
148  // No pattern recognized and we should have recognized one, so return
149  // a low negative. We've used -2 so return -3.
150  return ZeroBasedBeaconId(
151  Led::SENTINEL_NO_PATTERN_RECOGNIZED_DESPITE_SUFFICIENT_DATA);
152  }
153 
154 } // End namespace vbtracker
155 } // End namespace osvr
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...
Header file for class that tracks and identifies LEDs.
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...