4#include <visp3/core/vpConfig.h>
6#if defined(VISP_HAVE_REALSENSE2) && defined(VISP_HAVE_PUGIXML) && defined(VISP_HAVE_OPENCV) && \
7 (((VISP_HAVE_OPENCV_VERSION < 0x050000) && defined(HAVE_OPENCV_CALIB3D) && defined(HAVE_OPENCV_FEATURES2D)) || \
8 ((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_3D) && defined(HAVE_OPENCV_FEATURES)))
10#include <visp3/core/vpDisplay.h>
11#include <visp3/core/vpIoTools.h>
12#include <visp3/gui/vpDisplayFactory.h>
13#include <visp3/mbt/vpMbGenericTracker.h>
14#include <visp3/sensor/vpRealSense2.h>
15#include <visp3/vision/vpKeyPoint.h>
17#ifdef ENABLE_VISP_NAMESPACE
21#ifndef DOXYGEN_SHOULD_SKIP_THIS
30std::string depthTypeToString(
const DepthType &type)
51DepthType depthTypeFromString(
const std::string &name)
53 DepthType
type(DEPTH_COUNT);
56 while ((i <
static_cast<unsigned int>(DEPTH_COUNT)) && notFound) {
57 DepthType candidate =
static_cast<DepthType
>(
i);
67std::string getDepthTypeList(
const std::string &prefix =
"<",
const std::string &sep =
" , ",
const std::string &suffix =
">")
69 std::string list(prefix);
71 while (i <
static_cast<unsigned int>(DEPTH_COUNT - 1)) {
72 DepthType
type =
static_cast<DepthType
>(
i);
73 std::string name = depthTypeToString(type);
77 DepthType
type =
static_cast<DepthType
>(DEPTH_COUNT - 1);
78 std::string name = depthTypeToString(type);
79 list += name + suffix;
84int main(
int argc,
char *argv[])
86 std::string config_color =
"", config_depth =
"";
87 std::string model_color =
"", model_depth =
"";
88 std::string init_file =
"";
89 bool use_ogre =
false;
90 bool use_scanline =
false;
91 bool use_edges =
true;
93 DepthType use_depth = DepthType::DEPTH_UNUSED;
95 bool auto_init =
false;
96 double proj_error_threshold = 25;
97 std::string learning_data =
"learning/data-learned.bin";
98 bool display_projection_error =
false;
100 for (
int i = 1;
i < argc;
i++) {
101 if (std::string(argv[i]) ==
"--config_color" && i + 1 < argc) {
102 config_color = std::string(argv[i + 1]);
104 else if (std::string(argv[i]) ==
"--config_depth" && i + 1 < argc) {
105 config_depth = std::string(argv[i + 1]);
107 else if (std::string(argv[i]) ==
"--model_color" && i + 1 < argc) {
108 model_color = std::string(argv[i + 1]);
110 else if (std::string(argv[i]) ==
"--model_depth" && i + 1 < argc) {
111 model_depth = std::string(argv[i + 1]);
113 else if (std::string(argv[i]) ==
"--init_file" && i + 1 < argc) {
114 init_file = std::string(argv[i + 1]);
116 else if (std::string(argv[i]) ==
"--proj_error_threshold" && i + 1 < argc) {
117 proj_error_threshold = std::atof(argv[i + 1]);
119 else if (std::string(argv[i]) ==
"--use_ogre") {
122 else if (std::string(argv[i]) ==
"--use_scanline") {
125 else if (std::string(argv[i]) ==
"--use_edges" && i + 1 < argc) {
126 use_edges = (std::atoi(argv[i + 1]) == 0 ? false :
true);
128 else if (std::string(argv[i]) ==
"--use_klt" && i + 1 < argc) {
129 use_klt = (std::atoi(argv[i + 1]) == 0 ? false :
true);
131 else if (std::string(argv[i]) ==
"--use_depth" && i + 1 < argc) {
132 use_depth = depthTypeFromString(std::string(argv[i + 1]));
134 else if (std::string(argv[i]) ==
"--learn") {
137 else if (std::string(argv[i]) ==
"--learning_data" && i + 1 < argc) {
138 learning_data = argv[
i + 1];
140 else if (std::string(argv[i]) ==
"--auto_init") {
143 else if (std::string(argv[i]) ==
"--display_proj_error") {
144 display_projection_error =
true;
146 else if (std::string(argv[i]) ==
"--help" || std::string(argv[i]) ==
"-h") {
147 std::cout <<
"Usage: \n"
149 <<
" [--model_color <object.cao>] [--model_depth <object.cao>]"
150 " [--config_color <object.xml>] [--config_depth <object.xml>]"
151 " [--init_file <object.init>] [--use_ogre] [--use_scanline]"
152 " [--proj_error_threshold <threshold between 0 and 90> (default: "
153 << proj_error_threshold
155 " [--use_edges <0|1> (default: 1)] [--use_klt <0|1> (default: 1)] [--use_depth " + getDepthTypeList() +
" (default: " + depthTypeToString(use_depth) +
")]"
156 " [--learn] [--auto_init] [--learning_data <path to .bin> (default: learning/data-learned.bin)]"
157 " [--display_proj_error]"
160 std::cout <<
"\n** How to track a 4.2 cm width cube with manual initialization:\n"
161 << argv[0] <<
" --model_color model/cube/cube.cao --use_edges 1 --use_klt 1 --use_depth " + depthTypeToString(DEPTH_DENSE) << std::endl;
162 std::cout <<
"\n** How to learn the cube and create a learning database:\n"
163 << argv[0] <<
" --model_color model/cube/cube.cao --use_edges 1 --use_klt 1 --use_depth " + depthTypeToString(DEPTH_DENSE) +
" --learn"
165 std::cout <<
"\n** How to track the cube with initialization from learning database:\n"
166 << argv[0] <<
" --model_color model/cube/cube.cao --use_edges 1 --use_klt 1 --use_depth " + depthTypeToString(DEPTH_DENSE) +
" --auto_init"
173 if (model_depth.empty()) {
174 model_depth = model_color;
177 if (config_color.empty()) {
178 config_color = (parentname.empty() ?
"" : (parentname +
"/")) +
vpIoTools::getNameWE(model_color) +
".xml";
180 if (config_depth.empty()) {
181 config_depth = (parentname.empty() ?
"" : (parentname +
"/")) +
vpIoTools::getNameWE(model_color) +
"_depth.xml";
183 if (init_file.empty()) {
184 init_file = (parentname.empty() ?
"" : (parentname +
"/")) +
vpIoTools::getNameWE(model_color) +
".init";
186 std::cout <<
"Tracked features: " << std::endl;
187 std::cout <<
" Use edges : " << use_edges << std::endl;
188 std::cout <<
" Use klt : " << use_klt << std::endl;
189 std::cout <<
" Use depth : " << depthTypeToString(use_depth) << std::endl;
190 std::cout <<
"Tracker options: " << std::endl;
191 std::cout <<
" Use ogre : " << use_ogre << std::endl;
192 std::cout <<
" Use scanline: " << use_scanline << std::endl;
193 std::cout <<
" Proj. error : " << proj_error_threshold << std::endl;
194 std::cout <<
" Display proj. error: " << display_projection_error << std::endl;
195 std::cout <<
"Config files: " << std::endl;
196 std::cout <<
" Config color: "
197 <<
"\"" << config_color <<
"\"" << std::endl;
198 std::cout <<
" Config depth: "
199 <<
"\"" << config_depth <<
"\"" << std::endl;
200 std::cout <<
" Model color : "
201 <<
"\"" << model_color <<
"\"" << std::endl;
202 std::cout <<
" Model depth : "
203 <<
"\"" << model_depth <<
"\"" << std::endl;
204 std::cout <<
" Init file : "
205 <<
"\"" << init_file <<
"\"" << std::endl;
206 std::cout <<
"Learning options : " << std::endl;
207 std::cout <<
" Learn : " << learn << std::endl;
208 std::cout <<
" Auto init : " << auto_init << std::endl;
209 std::cout <<
" Learning data: " << learning_data << std::endl;
211 if ((!use_edges) && (!use_klt) && (use_depth == DEPTH_UNUSED)) {
212 std::cout <<
"You must choose at least one visual features between edge, KLT and depth." << std::endl;
216 if (config_color.empty() || config_depth.empty() || model_color.empty() || model_depth.empty() || init_file.empty()) {
217 std::cout <<
"config_color.empty() || config_depth.empty() || model_color.empty() || model_depth.empty() || "
227 config.enable_stream(RS2_STREAM_COLOR, width, height, RS2_FORMAT_RGBA8, fps);
228 config.enable_stream(RS2_STREAM_DEPTH, width, height, RS2_FORMAT_Z16, fps);
231 realsense.
open(config);
234 std::cout <<
"Catch an exception: " <<
e.what() << std::endl;
235 std::cout <<
"Check if the Realsense camera is connected..." << std::endl;
244 std::cout <<
"Sensor internal camera parameters for color camera: " <<
cam_color << std::endl;
245 std::cout <<
"Sensor internal camera parameters for depth camera: " <<
cam_depth << std::endl;
252 unsigned int _posx = 100, _posy = 50;
254#ifdef VISP_HAVE_DISPLAY
255#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
262 if (use_edges || use_klt)
263 display1->init(I_gray, _posx, _posy,
"Color stream");
264 if (use_depth != DEPTH_UNUSED)
265 display2->init(I_depth, _posx + I_gray.getWidth() + 10, _posy,
"Depth stream");
269 realsense.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap,
nullptr,
nullptr);
271 if (use_edges || use_klt) {
281 if (use_depth != DEPTH_UNUSED) {
294 std::vector<int> trackerTypes;
295 if (use_edges && use_klt)
302 if (use_depth == DEPTH_NORMAL) {
305 else if (use_depth == DEPTH_DENSE) {
310 std::map<std::string, vpHomogeneousMatrix> mapOfCameraTransformations;
311 std::map<std::string, const vpImage<unsigned char> *> mapOfImages;
312 std::map<std::string, std::string> mapOfInitFiles;
313 std::map<std::string, const std::vector<vpColVector> *> mapOfPointclouds;
314 std::map<std::string, unsigned int> mapOfWidths, mapOfHeights;
315 std::map<std::string, vpHomogeneousMatrix> mapOfCameraPoses;
317 std::vector<vpColVector> pointcloud;
321 if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
322 tracker.loadConfigFile(config_color, config_depth);
323 tracker.loadModel(model_color, model_depth);
324 std::cout <<
"Sensor internal depth_M_color: \n" <<
depth_M_color << std::endl;
326 tracker.setCameraTransformationMatrix(mapOfCameraTransformations);
327 mapOfImages[
"Camera1"] = &I_gray;
328 mapOfImages[
"Camera2"] = &
I_depth;
329 mapOfInitFiles[
"Camera1"] = init_file;
330 tracker.setCameraParameters(cam_color, cam_depth);
332 else if (use_edges || use_klt) {
333 tracker.loadConfigFile(config_color);
334 tracker.loadModel(model_color);
335 tracker.setCameraParameters(cam_color);
337 else if (use_depth != DEPTH_UNUSED) {
338 tracker.loadConfigFile(config_depth);
339 tracker.loadModel(model_depth);
340 tracker.setCameraParameters(cam_depth);
343 tracker.setDisplayFeatures(
true);
344 tracker.setOgreVisibilityTest(use_ogre);
345 tracker.setScanLineVisibilityTest(use_scanline);
346 tracker.setProjectionErrorComputation(
true);
347 tracker.setProjectionErrorDisplay(display_projection_error);
349#if ((VISP_HAVE_OPENCV_VERSION < 0x050000) && defined(HAVE_OPENCV_XFEATURES2D)) || ((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_FEATURES))
350 std::string detectorName =
"SIFT";
351 std::string extractorName =
"SIFT";
352 std::string matcherName =
"BruteForce";
353#elif ((VISP_HAVE_OPENCV_VERSION < 0x050000) && defined(HAVE_OPENCV_FEATURES2D)) || ((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_FEATURES))
354 std::string detectorName =
"FAST";
355 std::string extractorName =
"ORB";
356 std::string matcherName =
"BruteForce-Hamming";
359 if (learn || auto_init) {
363#if ((VISP_HAVE_OPENCV_VERSION < 0x050000) && defined(HAVE_OPENCV_FEATURES2D)) || ((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_FEATURES))
364 cv::Ptr<cv::ORB> orb_detector = keypoint.
getDetector(
"ORB").dynamicCast<cv::ORB>();
366 orb_detector->setNLevels(1);
373 std::cout <<
"Cannot enable auto detection. Learning file \"" << learning_data <<
"\" doesn't exist" << std::endl;
379 if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
380 tracker.initClick(mapOfImages, mapOfInitFiles,
true);
382 else if (use_edges || use_klt) {
383 tracker.initClick(I_gray, init_file,
true);
385 else if (use_depth != DEPTH_UNUSED) {
386 tracker.initClick(I_depth, init_file,
true);
393 bool run_auto_init =
false;
395 run_auto_init =
true;
397 std::vector<double> times_vec;
403 bool learn_position =
false;
409 bool tracking_failed =
false;
412 realsense.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap, &pointcloud,
nullptr,
nullptr);
414 if (use_edges || use_klt || run_auto_init) {
418 if (use_depth != DEPTH_UNUSED) {
423 if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
424 mapOfImages[
"Camera1"] = &I_gray;
425 mapOfPointclouds[
"Camera2"] = &pointcloud;
426 mapOfWidths[
"Camera2"] =
width;
427 mapOfHeights[
"Camera2"] =
height;
429 else if (use_edges || use_klt) {
430 mapOfImages[
"Camera"] = &I_gray;
432 else if (use_depth != DEPTH_UNUSED) {
433 mapOfPointclouds[
"Camera"] = &pointcloud;
434 mapOfWidths[
"Camera"] =
width;
435 mapOfHeights[
"Camera"] =
height;
440 if (keypoint.
matchPoint(I_gray, cam_color, cMo)) {
441 std::cout <<
"Auto init succeed" << std::endl;
442 if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
443 mapOfCameraPoses[
"Camera1"] =
cMo;
445 tracker.initFromPose(mapOfImages, mapOfCameraPoses);
447 else if (use_edges || use_klt) {
448 tracker.initFromPose(I_gray, cMo);
450 else if (use_depth != DEPTH_UNUSED) {
451 tracker.initFromPose(I_depth, depth_M_color * cMo);
455 if (use_edges || use_klt) {
458 if (use_depth != DEPTH_UNUSED) {
469 tracker.setDisplayFeatures(
false);
471 run_auto_init =
false;
473 if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
474 tracker.track(mapOfImages, mapOfPointclouds, mapOfWidths, mapOfHeights);
476 else if (use_edges || use_klt) {
479 else if (use_depth != DEPTH_UNUSED) {
480 tracker.track(mapOfImages, mapOfPointclouds, mapOfWidths, mapOfHeights);
484 std::cout <<
"Tracker exception: " <<
e.getStringMessage() << std::endl;
485 tracking_failed =
true;
487 std::cout <<
"Tracker needs to restart (tracking exception)" << std::endl;
488 run_auto_init =
true;
496 double proj_error = 0;
499 proj_error =
tracker.getProjectionError();
502 proj_error =
tracker.computeCurrentProjectionError(I_gray, cMo, cam_color);
505 if (auto_init && proj_error > proj_error_threshold) {
506 std::cout <<
"Tracker needs to restart (projection error detected: " << proj_error <<
")" << std::endl;
507 run_auto_init =
true;
508 tracking_failed =
true;
512 if (!tracking_failed) {
514 tracker.setDisplayFeatures(
true);
516 if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
517 tracker.display(I_gray, I_depth, cMo, depth_M_color * cMo, cam_color, cam_depth,
vpColor::red, 3);
521 else if (use_edges || use_klt) {
525 else if (use_depth != DEPTH_UNUSED) {
531 std::stringstream ss;
532 ss <<
"Nb features: " <<
tracker.getError().size();
536 std::stringstream ss;
537 ss <<
"Features: edges " <<
tracker.getNbFeaturesEdge() <<
", klt " <<
tracker.getNbFeaturesKlt()
538 <<
", depth " <<
tracker.getNbFeaturesDepthDense();
543 std::stringstream ss;
544 ss <<
"Loop time: " << loop_t <<
" ms";
547 if (use_edges || use_klt) {
563 learn_position =
true;
566 run_auto_init =
true;
570 if (use_depth != DEPTH_UNUSED) {
580 if (learn_position) {
582 std::vector<cv::KeyPoint> trainKeyPoints;
583 keypoint.
detect(I_gray, trainKeyPoints);
586 std::vector<vpPolygon> polygons;
587 std::vector<std::vector<vpPoint> > roisPt;
588 std::pair<std::vector<vpPolygon>, std::vector<std::vector<vpPoint> > > pair =
tracker.getPolygonFaces();
589 polygons = pair.first;
590 roisPt = pair.second;
593 std::vector<cv::Point3f> points3f;
597 keypoint.
buildReference(I_gray, trainKeyPoints, points3f,
true, learn_id++);
600 for (std::vector<cv::KeyPoint>::const_iterator it = trainKeyPoints.begin(); it != trainKeyPoints.end(); ++it) {
603 learn_position =
false;
604 std::cout <<
"Data learned" << std::endl;
607 times_vec.push_back(loop_t);
610 std::cout <<
"Save learning file: " << learning_data << std::endl;
615 std::cout <<
"Catch an exception: " <<
e.what() << std::endl;
618#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11) && defined(VISP_HAVE_DISPLAY)
619 if (display1 !=
nullptr) {
622 if (display2 !=
nullptr) {
627 if (!times_vec.empty()) {
635#elif defined(VISP_HAVE_REALSENSE2)
638 std::cout <<
"Install OpenCV 3rd party, configure and build ViSP again to use this example" << std::endl;
644 std::cout <<
"Install librealsense2 3rd party, configure and build ViSP again to use this example" << std::endl;
Generic class defining intrinsic camera parameters.
@ perspectiveProjWithoutDistortion
Perspective projection without distortion model.
static const vpColor none
static const vpColor yellow
Class that defines generic functionalities for display.
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 displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
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.
Implementation of an homogeneous matrix and operations on such kind of matrices.
static void createDepthHistogram(const vpImage< uint16_t > &src_depth, vpImage< vpRGBa > &dest_rgba)
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Definition of the vpImage class member functions.
Class that allows keypoints 2D features detection (and descriptors extraction) and matching thanks to...
unsigned int buildReference(const vpImage< unsigned char > &I) VP_OVERRIDE
void setExtractor(const vpFeatureDescriptorType &extractorType)
void loadLearningData(const std::string &filename, bool binaryMode=false, bool append=false)
void detect(const vpImage< unsigned char > &I, std::vector< cv::KeyPoint > &keyPoints, const vpRect &rectangle=vpRect())
static void compute3DForPointsInPolygons(const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, std::vector< cv::KeyPoint > &candidates, const std::vector< vpPolygon > &polygons, const std::vector< std::vector< vpPoint > > &roisPt, std::vector< cv::Point3f > &points, cv::Mat *descriptors=nullptr)
void setMatcher(const std::string &matcherName)
void saveLearningData(const std::string &filename, bool binaryMode=false, bool saveTrainingImages=true)
unsigned int matchPoint(const vpImage< unsigned char > &I) VP_OVERRIDE
void setDetector(const vpFeatureDetectorType &detectorType)
cv::Ptr< cv::FeatureDetector > getDetector(const vpFeatureDetectorType &type) const
static double getMedian(const std::vector< double > &v)
static double getStdev(const std::vector< double > &v, bool useBesselCorrection=false)
static double getMean(const std::vector< double > &v)
Real-time 6D object pose tracking using its CAD model.
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())
vpHomogeneousMatrix getTransformation(const rs2_stream &from, const rs2_stream &to, int from_index=-1) const
std::shared_ptr< vpDisplay > createDisplay()
Return a smart pointer vpDisplay specialization if a GUI library is available or nullptr otherwise.
vpDisplay * allocateDisplay()
Return a newly allocated vpDisplay specialization if a GUI library is available or nullptr otherwise.
VISP_EXPORT double measureTimeMs()