Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
tutorial-mb-generic-tracker-rgbd.cpp
1
2#include <iostream>
3
4#include <visp3/core/vpConfig.h>
5#include <visp3/core/vpDisplay.h>
6#include <visp3/core/vpIoTools.h>
7#include <visp3/gui/vpDisplayFactory.h>
8#include <visp3/io/vpImageIo.h>
10#include <visp3/mbt/vpMbGenericTracker.h>
12
13#if defined(VISP_HAVE_PCL) && defined(VISP_HAVE_PCL_SEGMENTATION) && defined(VISP_HAVE_PCL_FILTERS) && defined(VISP_HAVE_PCL_COMMON)
14#include <pcl/common/common.h>
15#include <pcl/point_cloud.h>
16#include <pcl/point_types.h>
17
18#ifdef ENABLE_VISP_NAMESPACE
19using namespace VISP_NAMESPACE_NAME;
20#endif
21
22namespace
23{
24typedef enum DepthType
25{
26 DEPTH_UNUSED = 0,
27 DEPTH_DENSE = 1,
28 DEPTH_NORMAL = 2,
29 DEPTH_COUNT = 3
30}DepthType;
31
32std::string depthTypeToString(const DepthType &type)
33{
34 std::string name;
35 switch (type) {
36 case DEPTH_UNUSED:
37 name = "unused";
38 break;
39 case DEPTH_DENSE:
40 name = "dense";
41 break;
42 case DEPTH_NORMAL:
43 name = "normals";
44 break;
45 case DEPTH_COUNT:
46 default:
47 name = "unknown";
48 break;
49 }
50 return name;
51}
52
53DepthType depthTypeFromString(const std::string &name)
54{
55 DepthType type(DEPTH_COUNT);
56 unsigned int i = 0;
57 bool notFound = true;
58 while ((i < static_cast<unsigned int>(DEPTH_COUNT)) && notFound) {
59 DepthType candidate = static_cast<DepthType>(i);
60 if (vpIoTools::toLowerCase(name) == depthTypeToString(candidate)) {
61 notFound = false;
62 type = candidate;
63 }
64 ++i;
65 }
66 return type;
67}
68
69std::string getDepthTypeList(const std::string &prefix = "<", const std::string &sep = " , ", const std::string &suffix = ">")
70{
71 std::string list(prefix);
72 unsigned int i = 0;
73 while (i < static_cast<unsigned int>(DEPTH_COUNT - 1)) {
74 DepthType type = static_cast<DepthType>(i);
75 std::string name = depthTypeToString(type);
76 list += name + sep;
77 ++i;
78 }
79 DepthType type = static_cast<DepthType>(DEPTH_COUNT - 1);
80 std::string name = depthTypeToString(type);
81 list += name + suffix;
82 return list;
83}
84
85struct vpRealsenseIntrinsics_t
86{
87 float ppx;
89 float ppy;
91 float fx;
93 float fy;
95 float coeffs[5];
96};
97
98void rs_deproject_pixel_to_point(float point[3], const vpRealsenseIntrinsics_t &intrin, const float pixel[2], float depth)
99{
100 float x = (pixel[0] - intrin.ppx) / intrin.fx;
101 float y = (pixel[1] - intrin.ppy) / intrin.fy;
102
103 float r2 = x * x + y * y;
104 float f = 1 + intrin.coeffs[0] * r2 + intrin.coeffs[1] * r2 * r2 + intrin.coeffs[4] * r2 * r2 * r2;
105 float ux = x * f + 2 * intrin.coeffs[2] * x * y + intrin.coeffs[3] * (r2 + 2 * x * x);
106 float uy = y * f + 2 * intrin.coeffs[3] * x * y + intrin.coeffs[2] * (r2 + 2 * y * y);
107
108 x = ux;
109 y = uy;
110
111 point[0] = depth * x;
112 point[1] = depth * y;
113 point[2] = depth;
114}
115
117bool read_data(unsigned int cpt, const std::string &input_directory, vpImage<vpRGBa> &I_color,
118 vpImage<uint16_t> &I_depth_raw, pcl::PointCloud<pcl::PointXYZ>::Ptr &pointcloud)
120{
121 // Read color
122 std::string filename_color = vpIoTools::formatString(input_directory + "/color_image_%04d.jpg", cpt);
123
124 if (!vpIoTools::checkFilename(filename_color)) {
125 std::cerr << "Cannot read: " << filename_color << std::endl;
126 return false;
127 }
128 vpImageIo::read(I_color, filename_color);
129
130 // Read raw depth
131 std::string filename_depth = vpIoTools::formatString(input_directory + "/depth_image_%04d.bin", cpt);
132
133 std::ifstream file_depth(filename_depth.c_str(), std::ios::in | std::ios::binary);
134 if (!file_depth.is_open()) {
135 return false;
136 }
137
138 unsigned int height = 0, width = 0;
139 vpIoTools::readBinaryValueLE(file_depth, height);
140 vpIoTools::readBinaryValueLE(file_depth, width);
141 I_depth_raw.resize(height, width);
142
143 uint16_t depth_value = 0;
144 for (unsigned int i = 0; i < height; i++) {
145 for (unsigned int j = 0; j < width; j++) {
146 vpIoTools::readBinaryValueLE(file_depth, depth_value);
147 I_depth_raw[i][j] = depth_value;
148 }
149 }
150
151 // Transform pointcloud
152 pointcloud->width = width;
153 pointcloud->height = height;
154 pointcloud->resize(static_cast<size_t>(width * height));
155
156 // Only for Creative SR300
157 const float depth_scale = 0.00100000005f;
158 vpRealsenseIntrinsics_t depth_intrinsic;
159 depth_intrinsic.ppx = 320.503509521484f;
160 depth_intrinsic.ppy = 235.602951049805f;
161 depth_intrinsic.fx = 383.970001220703f;
162 depth_intrinsic.fy = 383.970001220703f;
163 depth_intrinsic.coeffs[0] = 0.0f;
164 depth_intrinsic.coeffs[1] = 0.0f;
165 depth_intrinsic.coeffs[2] = 0.0f;
166 depth_intrinsic.coeffs[3] = 0.0f;
167 depth_intrinsic.coeffs[4] = 0.0f;
168
169 for (unsigned int i = 0; i < height; i++) {
170 for (unsigned int j = 0; j < width; j++) {
171 float scaled_depth = I_depth_raw[i][j] * depth_scale;
172 float point[3];
173 float pixel[2] = { static_cast<float>(j), static_cast<float>(i) };
174 rs_deproject_pixel_to_point(point, depth_intrinsic, pixel, scaled_depth);
175 pointcloud->points[static_cast<size_t>(i * width + j)].x = point[0];
176 pointcloud->points[static_cast<size_t>(i * width + j)].y = point[1];
177 pointcloud->points[static_cast<size_t>(i * width + j)].z = point[2];
178 }
179 }
180
181 return true;
182}
183} // namespace
184
185int main(int argc, char *argv[])
186{
187 std::string input_directory = "data"; // location of the data (images, depth_map, point_cloud)
188 std::string config_color = "model/cube/cube.xml", config_depth = "model/cube/cube_depth.xml";
189 std::string model_color = "model/cube/cube.cao", model_depth = "model/cube/cube.cao";
190 std::string init_file = "model/cube/cube.init";
191 unsigned int frame_cpt = 0;
192 DepthType use_depth = DEPTH_DENSE;
193
194 for (int i = 1; i < argc; i++) {
195 if (std::string(argv[i]) == "--input_directory" && i + 1 < argc) {
196 input_directory = std::string(argv[i + 1]);
197 }
198 else if (std::string(argv[i]) == "--config_color" && i + 1 < argc) {
199 config_color = std::string(argv[i + 1]);
200 }
201 else if (std::string(argv[i]) == "--config_depth" && i + 1 < argc) {
202 config_depth = std::string(argv[i + 1]);
203 }
204 else if (std::string(argv[i]) == "--model_color" && i + 1 < argc) {
205 model_color = std::string(argv[i + 1]);
206 }
207 else if (std::string(argv[i]) == "--model_depth" && i + 1 < argc) {
208 model_depth = std::string(argv[i + 1]);
209 }
210 else if (std::string(argv[i]) == "--init_file" && i + 1 < argc) {
211 init_file = std::string(argv[i + 1]);
212 }
213 else if (std::string(argv[i]) == "--use_depth" && i + 1 < argc) {
214 use_depth = depthTypeFromString(std::string(argv[i + 1]));
215 }
216 else if (std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") {
217 std::cout << "Usage: \n"
218 << argv[0]
219 << " --input_directory <data directory> --config_color <object.xml> --config_depth <object.xml>"
220 " --model_color <object.cao> --model_depth <object.cao> --init_file <object.init> --use_depth " << getDepthTypeList()
221 << std::endl;
222 std::cout
223 << "\nExample:\n"
224 << argv[0]
225 << " --config_color model/cube/cube.xml --config_depth model/cube/cube.xml"
226 " --model_color model/cube/cube.cao --model_depth model/cube/cube.cao --init_file model/cube/cube.init --use_depth "<< depthTypeToString(use_depth) <<"\n"
227 << std::endl;
228 return EXIT_SUCCESS;
229 }
230 }
231
232 std::cout << "Tracked features: " << std::endl;
233#if defined(VISP_HAVE_OPENCV)
234 std::cout << " Use edges : 1" << std::endl;
235#if defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
236 std::cout << " Use klt : 1" << std::endl;
237#else
238 std::cout << " Use klt : 0" << std::endl;
239#endif
240 std::cout << " Use depth : " << depthTypeToString(use_depth) << std::endl;
241#else
242 std::cout << " Use edges : 1" << std::endl;
243 std::cout << " Use klt : 0" << std::endl;
244 std::cout << " Use depth : 0" << std::endl;
245#endif
246 std::cout << "Config files: " << std::endl;
247 std::cout << " Input directory: "
248 << "\"" << input_directory << "\"" << std::endl;
249 std::cout << " Config color: "
250 << "\"" << config_color << "\"" << std::endl;
251 std::cout << " Config depth: "
252 << "\"" << config_depth << "\"" << std::endl;
253 std::cout << " Model color : "
254 << "\"" << model_color << "\"" << std::endl;
255 std::cout << " Model depth : "
256 << "\"" << model_depth << "\"" << std::endl;
257 std::cout << " Init file : "
258 << "\"" << init_file << "\"" << std::endl;
259
260 vpImage<vpRGBa> I_color;
264 vpImage<uint16_t> I_depth_raw;
266 pcl::PointCloud<pcl::PointXYZ>::Ptr pointcloud(new pcl::PointCloud<pcl::PointXYZ>());
269
270 read_data(frame_cpt, input_directory, I_color, I_depth_raw, pointcloud);
271 vpImageConvert::convert(I_color, I_gray);
272 vpImageConvert::createDepthHistogram(I_depth_raw, I_depth);
273
274#if defined(VISP_HAVE_DISPLAY)
275#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
276 std::shared_ptr<vpDisplay> display1 = vpDisplayFactory::createDisplay();
277 std::shared_ptr<vpDisplay> display2 = vpDisplayFactory::createDisplay();
278#else
281#endif
282 unsigned int _posx = 100, _posy = 50, _posdx = 10;
283 display1->init(I_gray, _posx, _posy, "Color stream");
284 display2->init(I_depth, _posx + I_gray.getWidth() + _posdx, _posy, "Depth stream");
285#endif
286
287 vpDisplay::display(I_gray);
288 vpDisplay::display(I_depth);
289 vpDisplay::flush(I_gray);
290 vpDisplay::flush(I_depth);
291
293 std::vector<int> trackerTypes;
294#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
296#else
297 trackerTypes.push_back(vpMbGenericTracker::EDGE_TRACKER);
298#endif
299 if (use_depth == DEPTH_DENSE) {
300 trackerTypes.push_back(vpMbGenericTracker::DEPTH_DENSE_TRACKER);
301 }
302 else if (use_depth == DEPTH_NORMAL) {
303 trackerTypes.push_back(vpMbGenericTracker::DEPTH_NORMAL_TRACKER);
304 }
305 vpMbGenericTracker tracker(trackerTypes);
307#if defined(VISP_HAVE_PUGIXML)
309 tracker.loadConfigFile(config_color, config_depth);
311#else
312 {
314 cam_color.initPersProjWithoutDistortion(614.9, 614.9, 320.2, 241.5);
315 cam_depth.initPersProjWithoutDistortion(384.0, 384.0, 320.5, 235.6);
316 tracker.setCameraParameters(cam_color, cam_depth);
317 }
318
319 // Edge
320 vpMe me;
321 me.setMaskSize(5);
322 me.setMaskNumber(180);
323 me.setRange(7);
325 me.setThreshold(10);
326 me.setMu1(0.5);
327 me.setMu2(0.5);
328 me.setSampleStep(4);
329 tracker.setMovingEdge(me);
330
331 // Klt
332#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
333 vpKltOpencv klt;
334 tracker.setKltMaskBorder(5);
335 klt.setMaxFeatures(300);
336 klt.setWindowSize(5);
337 klt.setQuality(0.01);
338 klt.setMinDistance(5);
339 klt.setHarrisFreeParameter(0.01);
340 klt.setBlockSize(3);
341 klt.setPyramidLevels(3);
342
343 tracker.setKltOpencv(klt);
344#endif
345
346 // Depth
347 tracker.setDepthNormalFeatureEstimationMethod(vpMbtFaceDepthNormal::ROBUST_FEATURE_ESTIMATION);
348 tracker.setDepthNormalPclPlaneEstimationMethod(2);
349 tracker.setDepthNormalPclPlaneEstimationRansacMaxIter(200);
350 tracker.setDepthNormalPclPlaneEstimationRansacThreshold(0.001);
351 tracker.setDepthNormalSamplingStep(2, 2);
352
353 tracker.setDepthDenseSamplingStep(4, 4);
354
355 tracker.setAngleAppear(vpMath::rad(80.0));
356 tracker.setAngleDisappear(vpMath::rad(85.0));
357 tracker.setNearClippingDistance(0.001);
358 tracker.setFarClippingDistance(5.0);
359 tracker.setClipping(tracker.getClipping() | vpMbtPolygon::FOV_CLIPPING);
360#endif
362 tracker.loadModel(model_color, model_depth);
364
365 tracker.getCameraParameters(cam_color, cam_depth);
366
367 std::cout << "Camera parameters for color camera (from XML file): " << cam_color << std::endl;
368 std::cout << "Camera parameters for depth camera (from XML file): " << cam_depth << std::endl;
369
371 tracker.setDisplayFeatures(true);
373
376 {
377 std::ifstream file((std::string(input_directory + "/depth_M_color.txt")).c_str());
378 depth_M_color.load(file);
379 file.close();
380 }
381 std::map<std::string, vpHomogeneousMatrix> mapOfCameraTransformations;
382 mapOfCameraTransformations["Camera1"] = vpHomogeneousMatrix();
383 mapOfCameraTransformations["Camera2"] = depth_M_color;
384 tracker.setCameraTransformationMatrix(mapOfCameraTransformations);
386 std::cout << "depth_M_color: \n" << depth_M_color << std::endl;
387
389 std::map<std::string, const vpImage<unsigned char> *> mapOfImages;
390 mapOfImages["Camera1"] = &I_gray;
391 mapOfImages["Camera2"] = &I_depth;
393
395 std::map<std::string, std::string> mapOfInitFiles;
396 mapOfInitFiles["Camera1"] = init_file;
397 tracker.initClick(mapOfImages, mapOfInitFiles, true);
399
400 mapOfImages.clear();
401 pcl::PointCloud<pcl::PointXYZ>::Ptr empty_pointcloud(new pcl::PointCloud<pcl::PointXYZ>);
402 std::vector<double> times_vec;
403
404 try {
405 bool quit = false;
406 while (!quit) {
407 double t = vpTime::measureTimeMs();
408 quit = !read_data(frame_cpt, input_directory, I_color, I_depth_raw, pointcloud);
409 vpImageConvert::convert(I_color, I_gray);
410 vpImageConvert::createDepthHistogram(I_depth_raw, I_depth);
411
412 vpDisplay::display(I_gray);
413 vpDisplay::display(I_depth);
414
415 mapOfImages["Camera1"] = &I_gray;
416 std::map<std::string, pcl::PointCloud<pcl::PointXYZ>::ConstPtr> mapOfPointclouds;
417 if (use_depth == DEPTH_UNUSED) {
418 mapOfPointclouds["Camera2"] = empty_pointcloud;
419 }
420 else {
421 mapOfPointclouds["Camera2"] = pointcloud;
422 }
423
425 tracker.track(mapOfImages, mapOfPointclouds);
427
429 vpHomogeneousMatrix cMo = tracker.getPose();
431
432 std::cout << "iter: " << frame_cpt << " cMo:\n" << cMo << std::endl;
433
435 tracker.display(I_gray, I_depth, cMo, depth_M_color * cMo, cam_color, cam_depth, vpColor::red, 3);
436 vpDisplay::displayFrame(I_gray, cMo, cam_color, 0.05, vpColor::none, 3);
437 vpDisplay::displayFrame(I_depth, depth_M_color * cMo, cam_depth, 0.05, vpColor::none, 3);
439
441 times_vec.push_back(t);
442
443 std::stringstream ss;
444 ss << "Computation time: " << t << " ms";
445 vpDisplay::displayText(I_gray, 20, 20, ss.str(), vpColor::red);
446 {
447 std::stringstream ss;
448 ss << "Nb features: " << tracker.getError().size();
449 vpDisplay::displayText(I_gray, I_gray.getHeight() - 50, 20, ss.str(), vpColor::red);
450 }
451 {
452 std::stringstream ss;
453 ss << "Features: edges " << tracker.getNbFeaturesEdge() << ", klt " << tracker.getNbFeaturesKlt() << ", depth "
454 << tracker.getNbFeaturesDepthDense();
455 vpDisplay::displayText(I_gray, I_gray.getHeight() - 30, 20, ss.str(), vpColor::red);
456 }
457
458 vpDisplay::flush(I_gray);
459 vpDisplay::flush(I_depth);
460
462 if (vpDisplay::getClick(I_gray, button, false)) {
463 quit = true;
464 }
465
466 frame_cpt++;
467 }
468 }
469 catch (const vpException &e) {
470 std::cout << "Catch exception: " << e.getStringMessage() << std::endl;
471 }
472
473#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11) && defined(VISP_HAVE_DISPLAY)
474 if (display1 != nullptr) {
475 delete display1;
476 }
477 if (display2 != nullptr) {
478 delete display2;
479 }
480#endif
481
482 std::cout << "\nProcessing time, Mean: " << vpMath::getMean(times_vec)
483 << " ms ; Median: " << vpMath::getMedian(times_vec) << " ; Std: " << vpMath::getStdev(times_vec) << " ms"
484 << std::endl;
485
486 vpDisplay::displayText(I_gray, 60, 20, "Click to quit", vpColor::red);
487 vpDisplay::flush(I_gray);
488 vpDisplay::getClick(I_gray);
489
490 return EXIT_SUCCESS;
491}
492#else
493int main()
494{
495 std::cout << "To run this tutorial, ViSP should be build with PCL library."
496 " Install libpcl, configure and build again ViSP..."
497 << std::endl;
498 return EXIT_SUCCESS;
499}
500#endif
Generic class defining intrinsic camera parameters.
static const vpColor red
Definition vpColor.h:198
static const vpColor none
Definition vpColor.h:210
Class that defines generic functionalities for display.
Definition vpDisplay.h:171
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
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)
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition of the vpImage class member functions.
Definition vpImage.h:131
unsigned int getWidth() const
Definition vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition vpImage.h:544
unsigned int getHeight() const
Definition vpImage.h:181
static std::string toLowerCase(const std::string &input)
Return a lower-case version of the string input . Numbers and special characters stay the same.
static bool checkFilename(const std::string &filename)
static void readBinaryValueLE(std::ifstream &file, int16_t &short_value)
static std::string formatString(const std::string &name, unsigned int val)
Wrapper for the KLT (Kanade-Lucas-Tomasi) feature tracker implemented in OpenCV. Thus to enable this ...
Definition vpKltOpencv.h:83
void setBlockSize(int blockSize)
void setQuality(double qualityLevel)
void setHarrisFreeParameter(double harris_k)
void setMaxFeatures(int maxCount)
void setMinDistance(double minDistance)
void setWindowSize(int winSize)
void setPyramidLevels(int pyrMaxLevel)
static double rad(double deg)
Definition vpMath.h:129
static double getMedian(const std::vector< double > &v)
Definition vpMath.cpp:343
static double getStdev(const std::vector< double > &v, bool useBesselCorrection=false)
Definition vpMath.cpp:374
static double getMean(const std::vector< double > &v)
Definition vpMath.cpp:323
Real-time 6D object pose tracking using its CAD model.
@ ROBUST_FEATURE_ESTIMATION
Robust scheme to estimate the normal of the plane.
Definition vpMe.h:143
void setMu1(const double &mu_1)
Definition vpMe.h:408
void setRange(const unsigned int &range)
Definition vpMe.h:438
void setLikelihoodThresholdType(const vpLikelihoodThresholdType likelihood_threshold_type)
Definition vpMe.h:531
void setMaskNumber(const unsigned int &mask_number)
Definition vpMe.cpp:555
void setThreshold(const double &threshold)
Definition vpMe.h:489
void setSampleStep(const double &sample_step)
Definition vpMe.h:445
void setMaskSize(const unsigned int &mask_size)
Definition vpMe.cpp:563
void setMu2(const double &mu_2)
Definition vpMe.h:415
@ NORMALIZED_THRESHOLD
Definition vpMe.h:154
read_data(CameraParameters|None cam_depth, ImageGray I, rs.pipeline pipe)
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()