Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
tutorial-rbt-realsense.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 */
31#include <iostream>
32#include <visp3/core/vpConfig.h>
33
34#ifdef ENABLE_VISP_NAMESPACE
35using namespace VISP_NAMESPACE_NAME;
36#endif
37
38#ifndef VISP_HAVE_REALSENSE2
39
40int main()
41{
42 std::cerr << "To run this tutorial, recompile ViSP with the Realsense third party library" << std::endl;
43 return EXIT_SUCCESS;
44}
45
46#else
47#include <visp3/sensor/vpRealSense2.h>
48#include <visp3/io/vpParseArgv.h>
49
50#include <visp3/ar/vpPanda3DFrameworkManager.h>
51
52#include <visp3/rbt/vpRBTracker.h>
53
54#include "render-based-tutorial-utils.h"
55
56#ifndef DOXYGEN_SHOULD_SKIP_THIS
60struct CmdArguments
61{
62 CmdArguments() : height(480), width(848), fps(60)
63 { }
64
65 void registerArguments(vpJsonArgumentParser &parser)
66 {
67 parser.addArgument("--height", height, false, "Realsense requested image height")
68 .addArgument("--width", width, false, "Realsense requested image width")
69 .addArgument("--fps", fps, false, "Realsense requested framerate");
70 }
71 unsigned int height, width, fps;
72};
73#endif
74
84void updateDepth(const vpImage<uint16_t> &depthRaw, float depthScale, float maxZDisplay, vpImage<float> &depth, vpImage<unsigned char> &IdepthDisplay)
85{
86 depth.resize(depthRaw.getHeight(), depthRaw.getWidth());
87#ifdef VISP_HAVE_OPENMP
88#pragma omp parallel for
89#endif
90 for (int i = 0; i < static_cast<int>(depthRaw.getSize()); ++i) {
91 depth.bitmap[i] = depthScale * static_cast<float>(depthRaw.bitmap[i]);
92 IdepthDisplay.bitmap[i] = depth.bitmap[i] > maxZDisplay ? 0 : static_cast<unsigned int>((depth.bitmap[i] / maxZDisplay) * 255.f);
93 }
94}
95
96int main(int argc, const char **argv)
97{
99 // Read the command line options
100 vpRBTrackerTutorial::BaseArguments baseArgs;
101 CmdArguments realsenseArgs;
102 vpRBTrackerTutorial::vpRBExperimentLogger logger;
103 vpRBTrackerTutorial::vpRBExperimentPlotter plotter;
104
105
107 "Tutorial showing the usage of the Render-Based tracker with a RealSense camera",
108 "--config", "/"
109 );
110
111 baseArgs.registerArguments(parser);
112 realsenseArgs.registerArguments(parser);
113 logger.registerArguments(parser);
114 plotter.registerArguments(parser);
115
116 parser.parse(argc, argv);
117
118 baseArgs.postProcessArguments();
119 plotter.postProcessArguments(baseArgs.display);
121
122
123 if (baseArgs.enableRenderProfiling) {
124 vpRBTrackerTutorial::enableRendererProfiling();
125 }
126
128 std::cout << "Loading tracker: " << baseArgs.trackerConfiguration << std::endl;
130 tracker.loadConfigurationFile(baseArgs.trackerConfiguration);
131 if (!baseArgs.modelPath.empty()) {
132 tracker.setModelPath(baseArgs.modelPath);
133 }
135
136
138 const unsigned int width = realsenseArgs.width, height = realsenseArgs.height;
139 const unsigned fps = realsenseArgs.fps;
140
141 vpRealSense2 realsense;
142 std::cout << "Opening realsense with settings: " << width << "x" << height << " @ " << fps << "fps" << std::endl;
143 rs2::config config;
144 config.enable_stream(RS2_STREAM_COLOR, width, height, RS2_FORMAT_RGBA8, fps);
145 config.enable_stream(RS2_STREAM_DEPTH, width, height, RS2_FORMAT_Z16, fps);
146 rs2::align align_to(RS2_STREAM_COLOR);
147 try {
148 realsense.open(config);
149 }
150 catch (const vpException &e) {
151 std::cout << "Caught an exception: " << e.what() << std::endl;
152 std::cout << "Check if the Realsense camera is connected..." << std::endl;
153 return EXIT_FAILURE;
154 }
155 const float depthScale = realsense.getDepthScale(); // used to convert uint16_t to meters
157
160 tracker.setCameraParameters(cam, height, width);
161 tracker.startTracking();
163
165 vpImage<vpRGBa> Icol(height, width); // Color image
166 vpImage<unsigned char> Id(height, width); // Grayscale image, converted from Icol
167 vpImage<uint16_t> depthRaw(height, width); // Raw depth map, in realsense format
168 vpImage<float> depth(height, width); // Depth map, in meters
169
170 // Display versions of raw image data
171 vpImage<unsigned char> IdepthDisplay(height, width);
172 vpImage<unsigned char> IProbaDisplay(height, width);
173 vpImage<unsigned char> cannyDisplay(height, width);
174 vpImage<vpRGBa> InormDisplay(height, width);
176
177 //camera warmup, colors may appear washed out in the first few frames
178 for (int i = 0; i < 10; ++i) {
179 realsense.acquire(Icol);
180 }
181 vpImageConvert::convert(Icol, Id);
182
183
184
185 std::cout << "Creating displays..." << std::endl;
186 std::vector<std::shared_ptr<vpDisplay>> displays, displaysDebug;
187
189 if (baseArgs.display) {
190 displays = vpRBTrackerTutorial::createDisplays(Id, Icol, IdepthDisplay, IProbaDisplay);
191 if (baseArgs.debugDisplay) {
192 displaysDebug = vpDisplayFactory::makeDisplayGrid(1, 2,
193 0, 0,
194 20, 20,
195 "Normals in object frame", InormDisplay,
196 "Depth canny", cannyDisplay
197 );
198 }
199 plotter.init(displays);
200 }
202
204 if (baseArgs.display && !baseArgs.hasInlineInit()) {
205 bool ready = false;
206 while (!ready) {
207 realsense.acquire((unsigned char *)Icol.bitmap, (unsigned char *)depthRaw.bitmap, nullptr, nullptr, &align_to);
208 updateDepth(depthRaw, depthScale, baseArgs.maxDepthDisplay, depth, IdepthDisplay);
209 vpImageConvert::convert(Icol, Id);
211 vpDisplay::flush(Icol); vpDisplay::flush(Id); vpDisplay::flush(IdepthDisplay);
212 if (vpDisplay::getClick(Id, false)) {
213 ready = true;
214 }
215 else {
216 vpTime::wait(1000.0 / fps);
217 }
218 }
219 }
220
221
223
226 // Manual initialization of the tracker
227 std::cout << "Starting init" << std::endl;
228 if (baseArgs.hasInlineInit()) {
229 tracker.setPose(baseArgs.cMoInit);
230 }
231 else if (baseArgs.display) {
232 tracker.initClick(Id, baseArgs.initFile, true);
233 tracker.getPose(cMo);
234 }
235 else {
236 throw vpException(vpException::notImplementedError, "Cannot initialize tracking: no initial pose provided or display to perform click initialization.");
237 }
238
239 std::cout << "Starting pose: " << vpPoseVector(cMo).t() << std::endl;
241
242 if (baseArgs.display) {
244 }
245
247 logger.startLog();
248 unsigned int iter = 1;
249 // Main tracking loop
250 double expStart = vpTime::measureTimeMs();
251 while (true) {
252 double frameStart = vpTime::measureTimeMs();
253 // Acquire images
255 realsense.acquire((unsigned char *)Icol.bitmap, (unsigned char *)depthRaw.bitmap, nullptr, nullptr, &align_to);
256 updateDepth(depthRaw, depthScale, baseArgs.maxDepthDisplay, depth, IdepthDisplay);
257 vpImageConvert::convert(Icol, Id);
260 double trackingStart = vpTime::measureTimeMs();
261 vpRBTrackingResult result = tracker.track(Id, Icol, depth);
262 double trackingEnd = vpTime::measureTimeMs();
263 tracker.getPose(cMo);
265
267 switch (result.getStoppingReason()) {
268 case vpRBTrackingStoppingReason::EXCEPTION:
269 {
270 std::cout << "Encountered an exception during tracking, pose was not updated!" << std::endl;
271 break;
272 }
273 case vpRBTrackingStoppingReason::NOT_ENOUGH_FEATURES:
274 {
275 std::cout << "There were not enough feature to perform tracking!" << std::endl;
276 break;
277 }
278 case vpRBTrackingStoppingReason::OBJECT_NOT_IN_IMAGE:
279 {
280 std::cout << "Object is not in image!" << std::endl;
281 break;
282 }
283 case vpRBTrackingStoppingReason::CONVERGENCE_CRITERION:
284 {
285 std::cout << "Convergence criterion reached:" << std::endl;
286 std::cout << "- Num iterations: " << result.getNumIterations() << std::endl;
287 std::cout << "- Convergence criterion: " << *(result.getConvergenceMetricValues().end() - 1) << std::endl;
288 break;
289 }
290 case vpRBTrackingStoppingReason::MAX_ITERS:
291 {
292 break;
293 }
294 default:
295 { }
296
297 }
298
299 const std::shared_ptr<vpRBDriftDetector> driftDetector = tracker.getDriftDetector();
300 if (driftDetector) {
301 if (driftDetector->getScore() < 0.25) {
302 std::cout << "Drift detection has low confidence score: " << driftDetector->getScore() << std::endl;
303 }
304 }
305
307
308 double displayStart = vpTime::measureTimeMs();
309
311 if (baseArgs.display) {
312 if (baseArgs.debugDisplay) {
313 const vpRBFeatureTrackerInput &lastFrame = tracker.getMostRecentFrame();
314
315 vpRBTrackerTutorial::displayCanny(lastFrame.renders.silhouetteCanny, cannyDisplay, lastFrame.renders.isSilhouette);
316 }
317
319 tracker.display(Id, Icol, IdepthDisplay);
320
321 vpDisplay::displayFrame(Icol, cMo, cam, 0.05, vpColor::none, 2);
322 vpDisplay::displayText(Id, 20, 5, "Right click to exit", vpColor::red);
323 if (driftDetector) {
324 std::stringstream ss;
325 ss << "Confidence score: " << std::setprecision(2) << driftDetector->getScore() << std::endl;
326 vpDisplay::displayText(Id, Id.getHeight() - 40, 5, ss.str(), vpColor::red);
327 }
329 if (vpDisplay::getClick(Id, button, false)) {
330 if (button == vpMouseButton::button3) {
331 break;
332 }
333 }
334 tracker.displayMask(IProbaDisplay);
335 vpDisplay::display(IProbaDisplay);
337 vpDisplay::flush(IdepthDisplay); vpDisplay::flush(IProbaDisplay);
338 }
340
341 const double displayEnd = vpTime::measureTimeMs();
342
343 const double frameEnd = vpTime::measureTimeMs();
345
346 logger.logFrame(tracker, iter, Id, Icol, IdepthDisplay, IProbaDisplay);
347 std::cout << "Iter " << iter << ": " << round(frameEnd - frameStart) << "ms" << std::endl;
348 std::cout << "- Tracking: " << round(trackingEnd - trackingStart) << "ms" << std::endl;
349 std::cout << "- Display: " << round(displayEnd - displayStart) << "ms" << std::endl;
350 if (baseArgs.verbose) {
351 std::cout << result.timer() << std::endl;
352 }
353 plotter.plot(tracker, (frameEnd - expStart) / 1000.0);
355 iter++;
356 }
358
360 logger.close();
362 return EXIT_SUCCESS;
364}
365#endif
Generic class defining intrinsic camera parameters.
@ perspectiveProjWithoutDistortion
Perspective projection without distortion model.
static const vpColor red
Definition vpColor.h:198
static const vpColor none
Definition vpColor.h:210
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void displayFrame(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, double size, const vpColor &color=vpColor::none, unsigned int thickness=1, const vpImagePoint &offset=vpImagePoint(0, 0), const std::string &frameName="", const vpColor &textColor=vpColor::black, const vpImagePoint &textOffset=vpImagePoint(15, 15))
static void flush(const vpImage< unsigned char > &I)
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
error that can be emitted by ViSP classes.
Definition vpException.h:60
@ notImplementedError
Not implemented.
Definition vpException.h:69
Implementation of an homogeneous matrix and operations on such kind of matrices.
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Definition of the vpImage class member functions.
Definition vpImage.h:131
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getSize() const
Definition vpImage.h:221
Type * bitmap
points toward the bitmap
Definition vpImage.h:135
unsigned int getHeight() const
Definition vpImage.h:181
Command line argument parsing with support for JSON files. If a JSON file is supplied,...
static vpPanda3DFrameworkManager & getInstance()
Implementation of a pose vector and operations on poses.
vpRowVector t() const
All the data related to a single tracking frame. This contains both the input data (from a real camer...
vpRBRenderData renders
camera parameters
Class implementing the Render-Based Tracker (RBT).
Definition vpRBTracker.h:87
vpRBTrackingStoppingReason getStoppingReason() const
vpRBTrackingTimings & timer()
const std::vector< double > & getConvergenceMetricValues() const
unsigned int getNumIterations() const
vpCameraParameters getCameraParameters(const rs2_stream &stream, vpCameraParameters::vpCameraParametersProjType type=vpCameraParameters::perspectiveProjWithDistortion, int index=-1) const
void acquire(vpImage< unsigned char > &grey, double *ts=nullptr)
bool open(const rs2::config &cfg=rs2::config())
float getDepthScale()
std::vector< std::shared_ptr< vpDisplay > > makeDisplayGrid(unsigned int rows, unsigned int cols, unsigned int startX, unsigned int startY, unsigned int paddingX, unsigned int paddingY, Args &... args)
Create a grid of displays, given a set of images. All the displays will be initialized in the correct...
VISP_EXPORT double measureTimeMs()
VISP_EXPORT int wait(double t0, double t)
void registerArguments(vpJsonArgumentParser &parser)
vpImage< unsigned char > isSilhouette
Image containing the orientation of the gradients.
vpImage< float > silhouetteCanny