Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
perfGenericTracker.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 *
30 * Description:
31 * Benchmark generic tracker.
32 */
33
37#include <visp3/core/vpConfig.h>
38
39#if defined(VISP_HAVE_CATCH2)
40
41#include <catch_amalgamated.hpp>
42
43#include <visp3/core/vpIoTools.h>
44#include <visp3/io/vpImageIo.h>
45#include <visp3/mbt/vpMbGenericTracker.h>
46
47// #define DEBUG_DISPLAY // uncomment to check that the tracking is correct
48#ifdef DEBUG_DISPLAY
49#include <visp3/gui/vpDisplayX.h>
50#endif
51
52#ifdef ENABLE_VISP_NAMESPACE
53using namespace VISP_NAMESPACE_NAME;
54#endif
55
56namespace
57{
58bool runBenchmark = false;
59
60template <typename Type>
61bool read_data(const std::string &input_directory, int cpt, const vpCameraParameters &cam_depth, vpImage<Type> &I,
62 vpImage<uint16_t> &I_depth, std::vector<vpColVector> &pointcloud, vpHomogeneousMatrix &cMo)
63{
64 static_assert(std::is_same<Type, unsigned char>::value || std::is_same<Type, vpRGBa>::value,
65 "Template function supports only unsigned char and vpRGBa images!");
66#if defined(VISP_HAVE_DATASET)
67#if VISP_HAVE_DATASET_VERSION >= 0x030600
68 std::string ext("png");
69#else
70 std::string ext("pgm");
71#endif
72#else
73 // We suppose that the user will download a recent dataset
74 std::string ext("png");
75#endif
76 std::string image_filename = vpIoTools::formatString(input_directory + "/Images/Image_%04d." + ext, cpt);
77 std::string depth_filename = vpIoTools::formatString(input_directory + "/Depth/Depth_%04d.bin", cpt);
78 std::string pose_filename = vpIoTools::formatString(input_directory + "/CameraPose/Camera_%03d.txt", cpt);
79
80 if (!vpIoTools::checkFilename(image_filename) || !vpIoTools::checkFilename(depth_filename) ||
81 !vpIoTools::checkFilename(pose_filename))
82 return false;
83
84 vpImageIo::read(I, image_filename);
85
86 unsigned int depth_width = 0, depth_height = 0;
87 std::ifstream file_depth(depth_filename.c_str(), std::ios::in | std::ios::binary);
88 if (!file_depth.is_open())
89 return false;
90
91 vpIoTools::readBinaryValueLE(file_depth, depth_height);
92 vpIoTools::readBinaryValueLE(file_depth, depth_width);
93 I_depth.resize(depth_height, depth_width);
94 pointcloud.resize(depth_height * depth_width);
95
96 const float depth_scale = 0.000030518f;
97 for (unsigned int i = 0; i < I_depth.getHeight(); i++) {
98 for (unsigned int j = 0; j < I_depth.getWidth(); j++) {
99 vpIoTools::readBinaryValueLE(file_depth, I_depth[i][j]);
100 double x = 0.0, y = 0.0, Z = I_depth[i][j] * depth_scale;
101 vpPixelMeterConversion::convertPoint(cam_depth, j, i, x, y);
102 vpColVector pt3d(4, 1.0);
103 pt3d[0] = x * Z;
104 pt3d[1] = y * Z;
105 pt3d[2] = Z;
106 pointcloud[i * I_depth.getWidth() + j] = pt3d;
107 }
108 }
109
110 std::ifstream file_pose(pose_filename.c_str());
111 if (!file_pose.is_open()) {
112 return false;
113 }
114
115 for (unsigned int i = 0; i < 4; i++) {
116 for (unsigned int j = 0; j < 4; j++) {
117 file_pose >> cMo[i][j];
118 }
119 }
120
121 return true;
122}
123} // anonymous namespace
124
125TEST_CASE("Benchmark generic tracker", "[benchmark]")
126{
127 if (runBenchmark) {
128 std::vector<int> tracker_type(2);
129 tracker_type[0] = vpMbGenericTracker::EDGE_TRACKER;
131 vpMbGenericTracker tracker(tracker_type);
132
133 const std::string input_directory =
135
136 const bool verbose = false;
137#if defined(VISP_HAVE_PUGIXML)
138 const std::string configFileCam1 = input_directory + std::string("/Config/chateau.xml");
139 const std::string configFileCam2 = input_directory + std::string("/Config/chateau_depth.xml");
140 REQUIRE(vpIoTools::checkFilename(configFileCam1));
141 REQUIRE(vpIoTools::checkFilename(configFileCam2));
142 tracker.loadConfigFile(configFileCam1, configFileCam2, verbose);
143#else
144 {
146 cam_color.initPersProjWithoutDistortion(700.0, 700.0, 320.0, 240.0);
147 cam_depth.initPersProjWithoutDistortion(700.0, 700.0, 320.0, 240.0);
148 tracker.setCameraParameters(cam_color, cam_depth);
149 }
150
151 // Edge
152 vpMe me;
153 me.setMaskSize(5);
154 me.setMaskNumber(180);
155 me.setRange(8);
157 me.setThreshold(5);
158 me.setMu1(0.5);
159 me.setMu2(0.5);
160 me.setSampleStep(5);
161 tracker.setMovingEdge(me);
162
163 // Klt
164#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
165 vpKltOpencv klt;
166 tracker.setKltMaskBorder(5);
167 klt.setMaxFeatures(10000);
168 klt.setWindowSize(5);
169 klt.setQuality(0.01);
170 klt.setMinDistance(5);
171 klt.setHarrisFreeParameter(0.02);
172 klt.setBlockSize(3);
173 klt.setPyramidLevels(3);
174
175 tracker.setKltOpencv(klt);
176#endif
177
178 // Depth
179 tracker.setDepthNormalFeatureEstimationMethod(vpMbtFaceDepthNormal::ROBUST_FEATURE_ESTIMATION);
180 tracker.setDepthNormalPclPlaneEstimationMethod(2);
181 tracker.setDepthNormalPclPlaneEstimationRansacMaxIter(200);
182 tracker.setDepthNormalPclPlaneEstimationRansacThreshold(0.001);
183 tracker.setDepthNormalSamplingStep(2, 2);
184
185 tracker.setDepthDenseSamplingStep(4, 4);
186
187 tracker.setAngleAppear(vpMath::rad(85.0));
188 tracker.setAngleDisappear(vpMath::rad(89.0));
189 tracker.setNearClippingDistance(0.01);
190 tracker.setFarClippingDistance(2.0);
191 tracker.setClipping(tracker.getClipping() | vpMbtPolygon::FOV_CLIPPING);
192#endif
193
194 REQUIRE(vpIoTools::checkFilename(input_directory + "/Models/chateau.cao"));
195 tracker.loadModel(input_directory + "/Models/chateau.cao", input_directory + "/Models/chateau.cao", verbose);
196
198 T[0][0] = -1;
199 T[0][3] = -0.2;
200 T[1][1] = 0;
201 T[1][2] = 1;
202 T[1][3] = 0.12;
203 T[2][1] = 1;
204 T[2][2] = 0;
205 T[2][3] = -0.15;
206 tracker.loadModel(input_directory + "/Models/cube.cao", verbose, T);
207
209 vpImage<uint16_t> I_depth_raw;
210 vpHomogeneousMatrix cMo_truth;
211 std::vector<vpColVector> pointcloud;
212
214 tracker.getCameraParameters(cam_color, cam_depth);
215
217 depth_M_color[0][3] = -0.05;
218 tracker.setCameraTransformationMatrix("Camera2", depth_M_color);
219
220 // load all the data in memory to not take into account I/O from disk
221 std::vector<vpImage<unsigned char> > images;
222 std::vector<vpImage<uint16_t> > depth_raws;
223 std::vector<std::vector<vpColVector> > pointclouds;
224 std::vector<vpHomogeneousMatrix> cMo_truth_all;
225 // forward
226 for (int i = 1; i <= 40; i++) {
227 if (read_data(input_directory, i, cam_depth, I, I_depth_raw, pointcloud, cMo_truth)) {
228 images.push_back(I);
229 depth_raws.push_back(I_depth_raw);
230 pointclouds.push_back(pointcloud);
231 cMo_truth_all.push_back(cMo_truth);
232 }
233 }
234 // backward
235 for (int i = 40; i >= 1; i--) {
236 if (read_data(input_directory, i, cam_depth, I, I_depth_raw, pointcloud, cMo_truth)) {
237 images.push_back(I);
238 depth_raws.push_back(I_depth_raw);
239 pointclouds.push_back(pointcloud);
240 cMo_truth_all.push_back(cMo_truth);
241 }
242 }
243
244 // Stereo MBT
245 {
246 std::vector<std::map<std::string, int> > mapOfTrackerTypes;
247 mapOfTrackerTypes.push_back(
249 mapOfTrackerTypes.push_back(
251#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
252 mapOfTrackerTypes.push_back(
254 mapOfTrackerTypes.push_back({ {"Camera1", vpMbGenericTracker::EDGE_TRACKER | vpMbGenericTracker::KLT_TRACKER},
256 mapOfTrackerTypes.push_back({ {"Camera1", vpMbGenericTracker::EDGE_TRACKER | vpMbGenericTracker::KLT_TRACKER},
258#endif
259
260 std::vector<std::string> benchmarkNames = {
261 "Edge MBT",
262 "Edge + Depth dense MBT",
263#if defined(VISP_HAVE_OPENCV)
264 "KLT MBT",
265 "KLT + depth dense MBT",
266 "Edge + KLT + depth dense MBT"
267#endif
268 };
269
270 std::vector<bool> monoculars = {
271 true,
272 false,
273#if defined(VISP_HAVE_OPENCV)
274 true,
275 false,
276 false
277#endif
278 };
279
280 for (size_t idx = 0; idx < mapOfTrackerTypes.size(); idx++) {
281 tracker.resetTracker();
282 tracker.setTrackerType(mapOfTrackerTypes[idx]);
283
284 const bool verbose = false;
285#if defined(VISP_HAVE_PUGIXML)
286 tracker.loadConfigFile(configFileCam1, configFileCam2, verbose);
287#else
288 {
290 cam_color.initPersProjWithoutDistortion(700.0, 700.0, 320.0, 240.0);
291 cam_depth.initPersProjWithoutDistortion(700.0, 700.0, 320.0, 240.0);
292 tracker.setCameraParameters(cam_color, cam_depth);
293 }
294
295 // Edge
296 vpMe me;
297 me.setMaskSize(5);
298 me.setMaskNumber(180);
299 me.setRange(8);
301 me.setThreshold(5);
302 me.setMu1(0.5);
303 me.setMu2(0.5);
304 me.setSampleStep(5);
305 tracker.setMovingEdge(me);
306
307 // Klt
308#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
309 vpKltOpencv klt;
310 tracker.setKltMaskBorder(5);
311 klt.setMaxFeatures(10000);
312 klt.setWindowSize(5);
313 klt.setQuality(0.01);
314 klt.setMinDistance(5);
315 klt.setHarrisFreeParameter(0.02);
316 klt.setBlockSize(3);
317 klt.setPyramidLevels(3);
318
319 tracker.setKltOpencv(klt);
320#endif
321
322 // Depth
323 tracker.setDepthNormalFeatureEstimationMethod(vpMbtFaceDepthNormal::ROBUST_FEATURE_ESTIMATION);
324 tracker.setDepthNormalPclPlaneEstimationMethod(2);
325 tracker.setDepthNormalPclPlaneEstimationRansacMaxIter(200);
326 tracker.setDepthNormalPclPlaneEstimationRansacThreshold(0.001);
327 tracker.setDepthNormalSamplingStep(2, 2);
328
329 tracker.setDepthDenseSamplingStep(4, 4);
330
331 tracker.setAngleAppear(vpMath::rad(85.0));
332 tracker.setAngleDisappear(vpMath::rad(89.0));
333 tracker.setNearClippingDistance(0.01);
334 tracker.setFarClippingDistance(2.0);
335 tracker.setClipping(tracker.getClipping() | vpMbtPolygon::FOV_CLIPPING);
336#endif
337 tracker.loadModel(input_directory + "/Models/chateau.cao", input_directory + "/Models/chateau.cao", verbose);
338 tracker.loadModel(input_directory + "/Models/cube.cao", verbose, T);
339 tracker.initFromPose(images.front(), cMo_truth_all.front());
340
341 std::map<std::string, unsigned int> mapOfWidths, mapOfHeights;
342 mapOfWidths["Camera2"] = monoculars[idx] ? 0 : I_depth_raw.getWidth();
343 mapOfHeights["Camera2"] = monoculars[idx] ? 0 : I_depth_raw.getHeight();
344
346#ifndef DEBUG_DISPLAY
347 BENCHMARK(benchmarkNames[idx].c_str())
348#else
350 vpImageConvert::createDepthHistogram(I_depth_raw, I_depth);
351
352 vpDisplayX d_color(I, 0, 0, "Color image");
353 vpDisplayX d_depth(I_depth, I.getWidth(), 0, "Depth image");
354 tracker.setDisplayFeatures(true);
355#endif
356 {
357 tracker.initFromPose(images.front(), cMo_truth_all.front());
358
359 for (size_t i = 0; i < images.size(); i++) {
360 const vpImage<unsigned char> &I_current = images[i];
361 const std::vector<vpColVector> &pointcloud_current = pointclouds[i];
362
363#ifdef DEBUG_DISPLAY
364 vpImageConvert::createDepthHistogram(depth_raws[i], I_depth);
365 I = I_current;
367 vpDisplay::display(I_depth);
368#endif
369
370 std::map<std::string, const vpImage<unsigned char> *> mapOfImages;
371 mapOfImages["Camera1"] = &I_current;
372
373 std::map<std::string, const std::vector<vpColVector> *> mapOfPointclouds;
374 mapOfPointclouds["Camera2"] = &pointcloud_current;
375
376 tracker.track(mapOfImages, mapOfPointclouds, mapOfWidths, mapOfHeights);
377 cMo = tracker.getPose();
378
379#ifdef DEBUG_DISPLAY
380 tracker.display(I, I_depth, cMo, depth_M_color * cMo, cam_color, cam_depth, vpColor::red, 3);
381 vpDisplay::displayFrame(I, cMo, cam_color, 0.05, vpColor::none, 3);
382 vpDisplay::displayFrame(I_depth, depth_M_color * cMo, cam_depth, 0.05, vpColor::none, 3);
383 vpDisplay::displayText(I, 20, 20, benchmarkNames[idx], vpColor::red);
385 I, 40, 20, std::string("Nb features: " + std::to_string(tracker.getError().getRows())), vpColor::red);
386
388 vpDisplay::flush(I_depth);
389 vpTime::wait(33);
390#endif
391 }
392
393#ifndef DEBUG_DISPLAY
394 return cMo;
395 };
396#else
397 }
398#endif
399
400 vpPoseVector pose_est(cMo);
401 vpPoseVector pose_truth(cMo_truth);
402 vpColVector t_err(3), tu_err(3);
403 for (unsigned int i = 0; i < 3; i++) {
404 t_err[i] = pose_est[i] - pose_truth[i];
405 tu_err[i] = pose_est[i + 3] - pose_truth[i + 3];
406 }
407
408 const double max_translation_error = 0.006;
409 const double max_rotation_error = 0.03;
410 CHECK(sqrt(t_err.sumSquare()) < max_translation_error);
411 CHECK(sqrt(tu_err.sumSquare()) < max_rotation_error);
412 }
413 }
414} // if (runBenchmark)
415}
416
417int main(int argc, char *argv[])
418{
419 Catch::Session session;
420
421 auto cli = session.cli() // Get Catch's composite command line parser
422 | Catch::Clara::Opt(runBenchmark) // bind variable to a new option, with a hint string
423 ["--benchmark"] // the option names it will respond to
424 ("run benchmark comparing naive code with ViSP implementation"); // description string for the help output
425
426 // Now pass the new composite back to Catch so it uses that
427 session.cli(cli);
428 session.applyCommandLine(argc, argv);
429 int numFailed = session.run();
430 return numFailed;
431}
432
433#else
434#include <iostream>
435
436int main() { return EXIT_SUCCESS; }
437#endif
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
static const vpColor red
Definition vpColor.h:198
static const vpColor none
Definition vpColor.h:210
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition vpDisplayX.h:135
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)
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 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
unsigned int getHeight() const
Definition vpImage.h:181
static std::string getViSPImagesDataPath()
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)
static std::string createFilePath(const std::string &parent, const std::string &child)
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
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
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
Implementation of a pose vector and operations on poses.
read_data(CameraParameters|None cam_depth, ImageGray I, rs.pipeline pipe)
VISP_EXPORT int wait(double t0, double t)