41 #include <opencv2/highgui/highgui.hpp>
42 #include <opencv2/imgproc/imgproc.hpp>
43 #include <json/reader.h>
44 #include <json/value.h>
49 #include <unordered_set>
58 : m_prefix(prefix), m_os(&os) {}
59 template <
typename T> std::ostream &operator<<(T val) {
60 return (*m_os) << m_prefix << val;
71 out(
"[OSVR Video Tracker Calibration] ", std::cout);
73 err(
"[OSVR Video Tracker Calibration] ", std::cerr);
77 static const std::string windowNameAndInstructions(
78 "OSVR Video Tracker Pre-Calibration | q or esc to quit without saving");
80 static int withAnError() {
82 err <<
"Press enter to exit." << endl;
86 static Json::Value findVideoTrackerParams(Json::Value
const &drivers) {
87 if (!drivers.isArray()) {
88 return Json::Value(Json::nullValue);
90 for (
auto const &entry : drivers) {
91 if (entry[
"plugin"] ==
"com_osvr_VideoBasedHMDTracker" &&
92 entry[
"driver"] ==
"VideoBasedHMDTracker") {
93 return entry[
"params"];
96 return Json::Value(Json::nullValue);
103 : m_src(std::move(src)), m_params(params), m_vbtracker(params),
104 m_distanceBetweenPanels(computeDistanceBetweenPanels(params)) {
105 m_firstNotch = m_params.initialBeaconError * 0.9;
106 m_secondNotch = m_params.initialBeaconError * 0.8;
107 cv::namedWindow(windowNameAndInstructions);
114 vbtracker().getFirstEstimator().permitKalmanMode(
false);
118 out <<
"Bring the HMD into view and fairly close to the camera."
120 double zDistance = 1000.;
121 while (zDistance > 0.3 && !m_quit) {
129 if (timeToUpdateDisplay()) {
130 m_frame.copyTo(m_display);
133 "Bring the HMD into view and close to the camera.",
134 cv::Point(30, 30), cv::FONT_HERSHEY_SIMPLEX, 0.4,
146 vbtracker().getFirstEstimator().permitKalmanMode(
true);
148 out <<
"OK - you'll now want to move the HMD slowly around the view of "
149 "the camera, and rotate it so that all sides can be seen."
151 out <<
"Press 's' to save your calibration when you're done." << endl;
152 m_frame.copyTo(m_display);
158 static const int MAX_BEACONS_TO_SHOW = 34;
161 bool gotDebugData =
false;
162 tryGrabAndProcessFrame(
169 if (timeToUpdateDisplay() && gotDebugData) {
170 m_frame.copyTo(m_display);
176 vbtracker().getFirstEstimator().getBeaconDebugData();
177 auto nBeacons = debugData.size();
178 auto nBeaconsActive =
size_t{0};
179 auto nBeaconsIdentified =
size_t{0};
180 for (decltype(nBeacons) i = 0; i < nBeacons; ++i) {
181 if (debugData[i].measurement.x != 0) {
182 nBeaconsIdentified++;
184 if (debugData[i].variance == 0) {
189 cv::line(m_display, debugData[i].measurement, debugData[i].measurement + debugData[i].residual,
cv::Scalar(0, 255, 0), 2);
192 m_display, debugData[i].measurement,
193 static_cast<int>(cv::norm(debugData[i].residual)),
198 cv::putText(m_display,
199 std::to_string(nBeaconsActive) +
200 " beacons active of " +
201 std::to_string(nBeaconsIdentified) +
202 " identified this frame",
203 cv::Point(30, 30), cv::FONT_HERSHEY_SIMPLEX,
206 cv::putText(m_display,
"Green labels indicate beacons with "
207 "enough calibration data. S to save "
209 cv::Point(30, 50), cv::FONT_HERSHEY_SIMPLEX,
212 auto numGreen = std::size_t{0};
213 auto numYellow = std::size_t{0};
214 auto numUnimproved = std::size_t{0};
218 std::vector<cv::Point2f> reprojections;
219 vbtracker().getFirstEstimator().ProjectBeaconsToImage(
221 const auto nBeacons = reprojections.size();
222 m_nBeacons = nBeacons;
223 const auto beaconsToDisplay =
224 std::min(static_cast<std::size_t>(MAX_BEACONS_TO_SHOW),
226 for (std::size_t i = 0; i < beaconsToDisplay; ++i) {
227 Eigen::Vector3d autocalibVariance =
230 .getBeaconAutocalibVariance(i);
232 if ((autocalibVariance.array() <
233 Eigen::Array3d::Constant(m_secondNotch))
238 }
else if ((autocalibVariance.array() <
239 Eigen::Array3d::Constant(m_firstNotch))
248 cv::putText(m_display, std::to_string(i + 1),
249 reprojections[i] + cv::Point2f(1, 1),
250 cv::FONT_HERSHEY_SIMPLEX, 0.45, color);
256 static const auto PROGRESS_HEIGHT = 5;
257 drawTwoStepProgressBar(
259 cv::Point(0, m_display.rows - PROGRESS_HEIGHT),
260 cv::Size(m_display.cols, PROGRESS_HEIGHT), numGreen,
261 numYellow, numUnimproved);
264 auto key = updateDisplay();
265 if (
's' == key ||
'S' == key) {
272 int beaconsToOutput =
273 std::min(MAX_BEACONS_TO_SHOW, static_cast<int>(m_nBeacons));
274 for (
int i = 0; i < beaconsToOutput; ++i) {
275 std::cout <<
"Beacon " << i + 1 <<
" autocalib variance ratio: "
278 .getBeaconAutocalibVariance(i)
280 m_params.initialBeaconError
286 Json::Value calib(Json::arrayValue);
287 out <<
"Saving your calibration data..." << endl;
288 auto &estimator = vbtracker().getFirstEstimator();
289 auto numBeaconsFromAutocalib =
290 std::min(m_nBeacons, getNumHDKFrontPanelBeacons());
292 for (std::size_t i = 0; i < numBeaconsFromAutocalib; ++i) {
294 estimator.getBeaconAutocalibPosition(i)));
296 if (m_nBeacons > numBeaconsFromAutocalib) {
300 Point3Vector locations;
301 addRearPanelBeaconLocations(m_distanceBetweenPanels, locations);
302 for (
auto const &beacon : locations) {
303 Json::Value val(Json::arrayValue);
304 val.append(beacon.x);
305 val.append(beacon.y);
306 val.append(beacon.z);
314 std::ofstream outfile(m_params.calibrationFile);
319 out <<
"Done! Press enter to exit." << endl;
326 if (!m_src->grab()) {
327 err <<
"Failed to grab!" << endl;
331 m_src->retrieve(m_frame, m_imageGray);
333 m_vbtracker.processImage(m_frame, m_imageGray, m_timestamp,
334 std::forward<F>(functor));
335 m_frameStride = (m_frameStride + 1) % 11;
345 cv::imshow(windowNameAndInstructions, m_display);
346 auto key =
static_cast<char>(cv::waitKey(1));
347 if (
'q' == key ||
'Q' == key || 27 == key) {
353 void closeWindow() { cv::destroyWindow(windowNameAndInstructions); }
356 ImageSourcePtr m_src;
358 const float m_distanceBetweenPanels;
360 double m_secondNotch;
367 std::size_t m_frameStride = 0;
368 std::size_t m_nBeacons = 0;
373 int main(
int argc,
char *argv[]) {
378 std::string configName(osvr::server::getDefaultConfigFilename());
380 configName = argv[1];
382 out <<
"Using default config file - pass a filename on the command "
383 "line to use a different one."
389 out <<
"Using config file '" << configName <<
"'" << endl;
390 std::ifstream configFile(configName);
391 if (!configFile.good()) {
392 err <<
"Could not open config file!" << endl;
393 err <<
"Searched in the current directory; file may be "
394 "misspelled, missing, or in a different directory."
396 return withAnError();
399 if (!reader.parse(configFile, root)) {
400 err <<
"Could not parse config file as JSON!" << endl;
401 return withAnError();
404 auto trackerParams = findVideoTrackerParams(root[
"drivers"]);
405 if (trackerParams.isNull()) {
406 out <<
"Warning: No video tracker params found?" << endl;
411 params = parseConfigParams(trackerParams);
415 err <<
"calibrationFile not specified in configuration file! no clue "
418 return withAnError();
422 params.
debug =
false;
427 auto src = openHDKCameraDirectShow();
428 if (!src || !src->ok()) {
429 err <<
"Couldn't find or access the IR camera!" << endl;
430 return withAnError();
434 cv::setNumThreads(1);
440 auto camParams = getHDKCameraParameters();
445 setupSensorsIncludeRearPanel(trackerApp.vbtracker(), params,
false);
448 err <<
"WARNING: only calibrating the first sensor is currently "
451 setupSensorsWithoutRearPanel(trackerApp.vbtracker(), params,
false);
bool streamBeaconDebugInfo
uint32_t OSVR_ChannelCount
The integer type specifying a number of channels/sensors or a channel/sensor index.
Header containing wrappers for some common jsoncpp operations.
double osvrVec3GetZ(OSVR_Vec3 const *v)
Accessor for Vec3 component Z.
std::string calibrationFile
bool timeToUpdateDisplay() const
Is it time to update the display window?
void getNow(TimeValue &tv)
Set the given TimeValue to the current time.
bool tryGrabAndProcessFrame(F &&functor)
returns true if we processed a frame.
std::string jsonToStyledString(Json::Value const &val)
Turns the JSON value into a pretty-printed, human-targeted string representation. ...
int main(int argc, char *argv[])
bool extraVerbose
Extra verbose developer debugging messages.
General configuration parameters.
std::string jsonToCompactString(Json::Value const &val)
Turns the JSON value into a compact string representation.
bool debug
Whether to show the debug windows and debug messages.
A structure defining a 3D (6DOF) rigid body pose: translation and rotation.
Standardized, portable parallel to struct timeval for representing both absolute times and time inter...
Json::Value toJson(Eigen::QuaternionBase< Derived > const &quat)
Converts quaternions to JSON objects.
OSVR_Vec3 translation
Position vector.
double Scalar
Common scalar type.