Visual Servoing Platform  version 3.4.0
perfGenericTracker.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See http://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Benchmark generic tracker.
33  *
34  *****************************************************************************/
35 
36 #include <visp3/core/vpConfig.h>
37 
38 #if defined(VISP_HAVE_CATCH2)
39 #define CATCH_CONFIG_ENABLE_BENCHMARKING
40 #define CATCH_CONFIG_RUNNER
41 #include <catch.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 namespace
53 {
54 bool runBenchmark = false;
55 
56 template <typename Type>
57 bool read_data(const std::string &input_directory, int cpt, const vpCameraParameters &cam_depth,
58  vpImage<Type> &I, vpImage<uint16_t> &I_depth,
59  std::vector<vpColVector> &pointcloud, vpHomogeneousMatrix &cMo)
60 {
61 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
62  static_assert(std::is_same<Type, unsigned char>::value || std::is_same<Type, vpRGBa>::value,
63  "Template function supports only unsigned char and vpRGBa images!");
64 #endif
65  char buffer[256];
66  sprintf(buffer, std::string(input_directory + "/Images/Image_%04d.pgm").c_str(), cpt);
67  std::string image_filename = buffer;
68 
69  sprintf(buffer, std::string(input_directory + "/Depth/Depth_%04d.bin").c_str(), cpt);
70  std::string depth_filename = buffer;
71 
72  sprintf(buffer, std::string(input_directory + "/CameraPose/Camera_%03d.txt").c_str(), cpt);
73  std::string pose_filename = buffer;
74 
75  if (!vpIoTools::checkFilename(image_filename) || !vpIoTools::checkFilename(depth_filename)
76  || !vpIoTools::checkFilename(pose_filename))
77  return false;
78 
79  vpImageIo::read(I, image_filename);
80 
81  unsigned int depth_width = 0, depth_height = 0;
82  std::ifstream file_depth(depth_filename.c_str(), std::ios::in | std::ios::binary);
83  if (!file_depth.is_open())
84  return false;
85 
86  vpIoTools::readBinaryValueLE(file_depth, depth_height);
87  vpIoTools::readBinaryValueLE(file_depth, depth_width);
88  I_depth.resize(depth_height, depth_width);
89  pointcloud.resize(depth_height*depth_width);
90 
91  const float depth_scale = 0.000030518f;
92  for (unsigned int i = 0; i < I_depth.getHeight(); i++) {
93  for (unsigned int j = 0; j < I_depth.getWidth(); j++) {
94  vpIoTools::readBinaryValueLE(file_depth, I_depth[i][j]);
95  double x = 0.0, y = 0.0, Z = I_depth[i][j] * depth_scale;
96  vpPixelMeterConversion::convertPoint(cam_depth, j, i, x, y);
97  vpColVector pt3d(4, 1.0);
98  pt3d[0] = x*Z;
99  pt3d[1] = y*Z;
100  pt3d[2] = Z;
101  pointcloud[i*I_depth.getWidth()+j] = pt3d;
102  }
103  }
104 
105  std::ifstream file_pose(pose_filename.c_str());
106  if (!file_pose.is_open()) {
107  return false;
108  }
109 
110  for (unsigned int i = 0; i < 4; i++) {
111  for (unsigned int j = 0; j < 4; j++) {
112  file_pose >> cMo[i][j];
113  }
114  }
115 
116  return true;
117 }
118 } //anonymous namespace
119 
120 TEST_CASE("Benchmark generic tracker", "[benchmark]") {
121  if (runBenchmark) {
122  std::vector<int> tracker_type(2);
123  tracker_type[0] = vpMbGenericTracker::EDGE_TRACKER;
124  tracker_type[1] = vpMbGenericTracker::DEPTH_DENSE_TRACKER;
125  vpMbGenericTracker tracker(tracker_type);
126 
127  const std::string input_directory = vpIoTools::createFilePath(vpIoTools::getViSPImagesDataPath(), "mbt-depth/Castle-simu");
128  const std::string configFileCam1 = input_directory + std::string("/Config/chateau.xml");
129  const std::string configFileCam2 = input_directory + std::string("/Config/chateau_depth.xml");
130  REQUIRE(vpIoTools::checkFilename(configFileCam1));
131  REQUIRE(vpIoTools::checkFilename(configFileCam2));
132  tracker.loadConfigFile(configFileCam1, configFileCam2);
133  REQUIRE(vpIoTools::checkFilename(input_directory + "/Models/chateau.cao"));
134  tracker.loadModel(input_directory + "/Models/chateau.cao", input_directory + "/Models/chateau.cao");
135 
137  T[0][0] = -1;
138  T[0][3] = -0.2;
139  T[1][1] = 0;
140  T[1][2] = 1;
141  T[1][3] = 0.12;
142  T[2][1] = 1;
143  T[2][2] = 0;
144  T[2][3] = -0.15;
145  tracker.loadModel(input_directory + "/Models/cube.cao", false, T);
146 
148  vpImage<uint16_t> I_depth_raw;
149  vpHomogeneousMatrix cMo_truth;
150  std::vector<vpColVector> pointcloud;
151 
152  vpCameraParameters cam_color, cam_depth;
153  tracker.getCameraParameters(cam_color, cam_depth);
154 
155  vpHomogeneousMatrix depth_M_color;
156  depth_M_color[0][3] = -0.05;
157  tracker.setCameraTransformationMatrix("Camera2", depth_M_color);
158 
159  // load all the data in memory to not take into account I/O from disk
160  std::vector<vpImage<unsigned char>> images;
161  std::vector<vpImage<uint16_t>> depth_raws;
162  std::vector<std::vector<vpColVector>> pointclouds;
163  std::vector<vpHomogeneousMatrix> cMo_truth_all;
164  // forward
165  for (int i = 1; i <= 40; i++) {
166  if (read_data(input_directory, i, cam_depth, I, I_depth_raw, pointcloud, cMo_truth)) {
167  images.push_back(I);
168  depth_raws.push_back(I_depth_raw);
169  pointclouds.push_back(pointcloud);
170  cMo_truth_all.push_back(cMo_truth);
171  }
172  }
173  // backward
174  for (int i = 40; i >= 1; i--) {
175  if (read_data(input_directory, i, cam_depth, I, I_depth_raw, pointcloud, cMo_truth)) {
176  images.push_back(I);
177  depth_raws.push_back(I_depth_raw);
178  pointclouds.push_back(pointcloud);
179  cMo_truth_all.push_back(cMo_truth);
180  }
181  }
182 
183  // Stereo MBT
184  {
185  std::vector<std::map<std::string, int>> mapOfTrackerTypes;
186  mapOfTrackerTypes.push_back({{"Camera1", vpMbGenericTracker::EDGE_TRACKER}, {"Camera2", vpMbGenericTracker::DEPTH_DENSE_TRACKER}});
187  mapOfTrackerTypes.push_back({{"Camera1", vpMbGenericTracker::EDGE_TRACKER}, {"Camera2", vpMbGenericTracker::DEPTH_DENSE_TRACKER}});
188  #if defined(VISP_HAVE_OPENCV)
189  mapOfTrackerTypes.push_back({{"Camera1", vpMbGenericTracker::KLT_TRACKER}, {"Camera2", vpMbGenericTracker::DEPTH_DENSE_TRACKER}});
190  mapOfTrackerTypes.push_back({{"Camera1", vpMbGenericTracker::EDGE_TRACKER | vpMbGenericTracker::KLT_TRACKER}, {"Camera2", vpMbGenericTracker::DEPTH_DENSE_TRACKER}});
191  mapOfTrackerTypes.push_back({{"Camera1", vpMbGenericTracker::EDGE_TRACKER | vpMbGenericTracker::KLT_TRACKER}, {"Camera2", vpMbGenericTracker::DEPTH_DENSE_TRACKER}});
192  #endif
193 
194  std::vector<std::string> benchmarkNames = {
195  "Edge MBT",
196  "Edge + Depth dense MBT",
197  #if defined(VISP_HAVE_OPENCV)
198  "KLT MBT",
199  "KLT + depth dense MBT",
200  "Edge + KLT + depth dense MBT"
201  #endif
202  };
203 
204  std::vector<bool> monoculars = {
205  true,
206  false,
207  #if defined(VISP_HAVE_OPENCV)
208  true,
209  false,
210  false
211  #endif
212  };
213 
214  for (size_t idx = 0; idx < mapOfTrackerTypes.size(); idx++) {
215  tracker.resetTracker();
216  tracker.setTrackerType(mapOfTrackerTypes[idx]);
217 
218  tracker.loadConfigFile(configFileCam1, configFileCam2);
219  tracker.loadModel(input_directory + "/Models/chateau.cao", input_directory + "/Models/chateau.cao");
220  tracker.loadModel(input_directory + "/Models/cube.cao", false, T);
221  tracker.initFromPose(images.front(), cMo_truth_all.front());
222 
223  std::map<std::string, unsigned int> mapOfWidths, mapOfHeights;
224  mapOfWidths["Camera2"] = monoculars[idx] ? 0 : I_depth_raw.getWidth();
225  mapOfHeights["Camera2"] = monoculars[idx] ? 0 : I_depth_raw.getHeight();
226 
228  #ifndef DEBUG_DISPLAY
229  BENCHMARK(benchmarkNames[idx].c_str())
230  #else
231  vpImage<unsigned char> I_depth;
232  vpImageConvert::createDepthHistogram(I_depth_raw, I_depth);
233 
234  vpDisplayX d_color(I, 0, 0, "Color image");
235  vpDisplayX d_depth(I_depth, I.getWidth(), 0, "Depth image");
236  tracker.setDisplayFeatures(true);
237  #endif
238  {
239  tracker.initFromPose(images.front(), cMo_truth_all.front());
240 
241  for (size_t i = 0; i < images.size(); i++) {
242  const vpImage<unsigned char>& I_current = images[i];
243  const std::vector<vpColVector>& pointcloud_current = pointclouds[i];
244 
245  #ifdef DEBUG_DISPLAY
246  vpImageConvert::createDepthHistogram(depth_raws[i], I_depth);
247  I = I_current;
249  vpDisplay::display(I_depth);
250  #endif
251 
252  std::map<std::string, const vpImage<unsigned char> *> mapOfImages;
253  mapOfImages["Camera1"] = &I_current;
254 
255  std::map<std::string, const std::vector<vpColVector> *> mapOfPointclouds;
256  mapOfPointclouds["Camera2"] = &pointcloud_current;
257 
258  tracker.track(mapOfImages, mapOfPointclouds, mapOfWidths, mapOfHeights);
259  cMo = tracker.getPose();
260 
261  #ifdef DEBUG_DISPLAY
262  tracker.display(I, I_depth, cMo, depth_M_color*cMo, cam_color, cam_depth, vpColor::red, 3);
263  vpDisplay::displayFrame(I, cMo, cam_color, 0.05, vpColor::none, 3);
264  vpDisplay::displayFrame(I_depth, depth_M_color*cMo, cam_depth, 0.05, vpColor::none, 3);
265  vpDisplay::displayText(I, 20, 20, benchmarkNames[idx], vpColor::red);
266  vpDisplay::displayText(I, 40, 20, std::string("Nb features: " + std::to_string(tracker.getError().getRows())), vpColor::red);
267 
268  vpDisplay::flush(I);
269  vpDisplay::flush(I_depth);
270  vpTime::wait(33);
271  #endif
272  }
273 
274  #ifndef DEBUG_DISPLAY
275  return cMo;
276  };
277  #else
278  }
279  #endif
280 
281  vpPoseVector pose_est(cMo);
282  vpPoseVector pose_truth(cMo_truth);
283  vpColVector t_err(3), tu_err(3);
284  for (unsigned int i = 0; i < 3; i++) {
285  t_err[i] = pose_est[i] - pose_truth[i];
286  tu_err[i] = pose_est[i+3] - pose_truth[i+3];
287  }
288 
289  const double max_translation_error = 0.005;
290  const double max_rotation_error = 0.03;
291  CHECK(sqrt(t_err.sumSquare()) < max_translation_error);
292  CHECK(sqrt(tu_err.sumSquare()) < max_rotation_error);
293  }
294  }
295  } //if (runBenchmark)
296 }
297 
298 int main(int argc, char *argv[])
299 {
300  Catch::Session session; // There must be exactly one instance
301 
302  // Build a new parser on top of Catch's
303  using namespace Catch::clara;
304  auto cli = session.cli() // Get Catch's composite command line parser
305  | Opt(runBenchmark) // bind variable to a new option, with a hint string
306  ["--benchmark"] // the option names it will respond to
307  ("run benchmark comparing naive code with ViSP implementation"); // description string for the help output
308 
309  // Now pass the new composite back to Catch so it uses that
310  session.cli(cli);
311 
312  // Let Catch (using Clara) parse the command line
313  session.applyCommandLine(argc, argv);
314 
315  int numFailed = session.run();
316 
317  // numFailed is clamped to 255 as some unices only use the lower 8 bits.
318  // This clamping has already been applied, so just return it here
319  // You can also do any post run clean-up here
320  return numFailed;
321 }
322 #else
323 #include <iostream>
324 
325 int main()
326 {
327  return 0;
328 }
329 #endif
VISP_EXPORT int wait(double t0, double t)
Definition: vpTime.cpp:173
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1202
unsigned int getWidth() const
Definition: vpImage.h:246
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition: vpImage.h:800
Implementation of an homogeneous matrix and operations on such kind of matrices.
static void readBinaryValueLE(std::ifstream &file, int16_t &short_value)
Definition: vpIoTools.cpp:1769
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition: vpDisplayX.h:150
static const vpColor none
Definition: vpColor.h:229
static void convertPoint(const vpCameraParameters &cam, const double &u, const double &v, double &x, double &y)
Real-time 6D object pose tracking using its CAD model.
static void flush(const vpImage< unsigned char > &I)
static const vpColor red
Definition: vpColor.h:217
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1446
static void display(const vpImage< unsigned char > &I)
Generic class defining intrinsic camera parameters.
static void read(vpImage< unsigned char > &I, const std::string &filename)
Definition: vpImageIo.cpp:244
Implementation of column vector and the associated operations.
Definition: vpColVector.h:130
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))
Implementation of a pose vector and operations on poses.
Definition: vpPoseVector.h:151
static bool checkFilename(const std::string &filename)
Definition: vpIoTools.cpp:640
unsigned int getHeight() const
Definition: vpImage.h:188
Definition of the vpImage class member functions.
Definition: vpImage.h:126
static void createDepthHistogram(const vpImage< uint16_t > &src_depth, vpImage< vpRGBa > &dest_rgba)