Visual Servoing Platform  version 3.6.1 under development (2024-05-15)
tutorial-mb-generic-tracker-read.cpp
1 #include <memory>
2 #include <visp3/core/vpIoTools.h>
3 #include <visp3/gui/vpDisplayX.h>
4 #include <visp3/gui/vpDisplayGDI.h>
5 #include <visp3/gui/vpDisplayOpenCV.h>
6 #include <visp3/io/vpImageIo.h>
7 #include <visp3/core/vpImageDraw.h>
8 
9 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(HAVE_OPENCV_HIGHGUI)) \
10  && (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
11 namespace
12 {
13 // https://en.cppreference.com/w/cpp/io/c/fprintf
14 std::string toString(const std::string &name, int val)
15 {
16  auto fmt = name.c_str();
17  int sz = std::snprintf(nullptr, 0, fmt, val);
18  std::vector<char> buf(sz + 1); // note +1 for null terminator
19  std::sprintf(buf.data(), fmt, val);
20  std::string str(buf.begin(), buf.end());
21 
22  return str;
23 }
24 
25 template<typename T, typename... Args>
26 std::unique_ptr<T> make_unique_compat(Args&&... args)
27 {
28 #if ((__cplusplus >= 201402L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L)))
29  return std::make_unique<T>(args...);
30 #else
31  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
32 #endif
33 }
34 }
35 #endif
36 
37 int main(int argc, char *argv[])
38 {
39 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(HAVE_OPENCV_HIGHGUI)) \
40  && (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
41  bool opencv_backend = false;
42  std::string npz_filename = "npz_tracking_teabox.npz";
43  bool print_cMo = false;
44  bool dump_infos = false;
45 
46  for (int i = 1; i < argc; i++) {
47  if (std::string(argv[i]) == "--cv-backend") {
48  opencv_backend = true;
49  }
50  else if ((std::string(argv[i]) == "--read" || std::string(argv[i]) == "-i") && i+1 < argc) {
51  npz_filename = argv[i+1];
52  }
53  else if (std::string(argv[i]) == "--print-cMo" && i+1 < argc) {
54  print_cMo = true;
55  }
56  else if (std::string(argv[i]) == "--dump" && i+1 < argc) {
57  dump_infos = true;
58  }
59  else {
60  std::cout << "Options:" << std::endl;
61  std::cout << " --cv-backend use OpenCV if available for in-memory PNG decoding" << std::endl;
62  std::cout << " --read / -i input filename" << std::endl;
63  std::cout << " --print-cMo print cMo" << std::endl;
64  std::cout << " --dump print all the data name in the file" << std::endl;
65  return EXIT_SUCCESS;
66  }
67  }
68 
69  std::cout << "Read file: " << npz_filename << std::endl;
70  std::cout << "OpenCV backend? " << opencv_backend << std::endl;
71 
72  const vpImageIo::vpImageIoBackendType backend =
74 
75  visp::cnpy::npz_t npz_data = visp::cnpy::npz_load(npz_filename);
76  if (dump_infos) {
77  std::cout << npz_filename << " file contains the following data:" << std::endl;
78  for (visp::cnpy::npz_t::const_iterator it = npz_data.begin(); it != npz_data.end(); ++it) {
79  std::cout << " " << it->first << std::endl;
80  }
81  }
82 
83  visp::cnpy::NpyArray arr_height = npz_data["height"];
84  visp::cnpy::NpyArray arr_width = npz_data["width"];
85  visp::cnpy::NpyArray arr_channel = npz_data["channel"];
86  int height = *arr_height.data<int>();
87  int width = *arr_width.data<int>();
88  int channel = *arr_channel.data<int>();
89  std::cout << "height: " << height << std::endl;
90  std::cout << "width: " << width << std::endl;
91  std::cout << "channel: " << channel << std::endl;
92  std::cout << "Color mode? " << (channel > 1) << std::endl;
93 
94  visp::cnpy::NpyArray arr_camera_name = npz_data["camera_name"];
95  // For null-terminated character handling, see:
96  // https://stackoverflow.com/a/8247804
97  // https://stackoverflow.com/a/45491652
98  std::vector<char> vec_arr_camera_name = arr_camera_name.as_vec<char>();
99  const std::string camera_name = std::string(vec_arr_camera_name.begin(), vec_arr_camera_name.end());
100  std::cout << "Camera name: " << camera_name << std::endl;
101 
102  visp::cnpy::NpyArray arr_px = npz_data["cam_px"];
103  visp::cnpy::NpyArray arr_py = npz_data["cam_py"];
104  visp::cnpy::NpyArray arr_u0 = npz_data["cam_u0"];
105  visp::cnpy::NpyArray arr_v0 = npz_data["cam_v0"];
106  vpCameraParameters cam(*arr_px.data<double>(), *arr_py.data<double>(), *arr_u0.data<double>(), *arr_v0.data<double>());
107  std::cout << "Cam: " << cam << std::endl;
108 
109  vpImage<unsigned char> I(height, width);
110  vpImage<vpRGBa> I_display(height, width);
111 
112  std::unique_ptr<vpDisplay> display;
113 #if defined(VISP_HAVE_X11)
114  display = make_unique_compat<vpDisplayX>(I_display, 100, 100, "Model-based tracker");
115 #elif defined(VISP_HAVE_GDI)
116  display = make_unique_compat<vpDisplayGDI>(I_display, 100, 100, "Model-based tracker");
117 #elif defined(HAVE_OPENCV_HIGHGUI)
118  display = make_unique_compat<vpDisplayOpenCV>(I_display, 100, 100, "Model-based tracker");
119 #endif
120 
121  visp::cnpy::NpyArray arr_nb_data = npz_data["nb_data"];
122  int nb_data = *arr_nb_data.data<int>();
123  std::cout << "Number of images: " << nb_data << std::endl;
124 
125  // Load all the images data
126  visp::cnpy::NpyArray arr_vec_img_data_size = npz_data["vec_img_data_size"];
127  int *vec_img_data_size_ptr = arr_vec_img_data_size.data<int>();
128  visp::cnpy::NpyArray arr_vec_img = npz_data["vec_img"];
129  unsigned char *vec_img_ptr = arr_vec_img.data<unsigned char>();
130  std::vector<unsigned char> vec_img;
131  size_t img_data_offset = 0;
132 
133  // Load all the poses
134  visp::cnpy::NpyArray arr_vec_poses = npz_data["vec_poses"];
135  double *vec_poses_ptr = arr_vec_poses.data<double>();
136  assert(arr_vec_poses.shape.size() == 2);
137  assert(arr_vec_poses.shape[1] == 6);
138  size_t pose_size = arr_vec_poses.shape[1];
139 
140  std::vector<double> times;
141 
142  for (int iter = 0; iter < nb_data; iter++) {
143  // std::copy(vec_img_ptr + img_data_offset, vec_img_ptr + img_data_offset + vec_img_data_size_ptr[iter],
144  // std::back_inserter(vec_img));
145  vec_img = std::vector<unsigned char>(vec_img_ptr + img_data_offset, vec_img_ptr + img_data_offset + vec_img_data_size_ptr[iter]);
146  double start = vpTime::measureTimeMs(), end = -1;
147  if (channel > 1) {
148  vpImageIo::readPNGfromMem(vec_img, I_display, backend);
149  end = vpTime::measureTimeMs();
150  }
151  else {
152  vpImageIo::readPNGfromMem(vec_img, I, backend);
153  end = vpTime::measureTimeMs();
154  vpImageConvert::convert(I, I_display);
155  }
156  times.push_back(end-start);
157  img_data_offset += vec_img_data_size_ptr[iter];
158 
159  const std::string str_model_iter_sz = toString("model_%06d", iter) + "_sz";
160  visp::cnpy::NpyArray arr_model_iter_sz = npz_data[str_model_iter_sz];
161  size_t model_sz = *arr_model_iter_sz.data<size_t>();
162 
163  for (size_t i = 0; i < model_sz; i++) {
164  char buffer[100];
165  int res = snprintf(buffer, 100, "model_%06d_%06zu", iter, i);
166  if (res > 0 && res < 100) {
167  std::string str_model_iter_data = buffer;
168  visp::cnpy::NpyArray arr_model_iter_data = npz_data[str_model_iter_data];
169 
170  if (arr_model_iter_data.shape[0] >= 5) {
171  if (std::fabs(arr_model_iter_data.data<double>()[0]) <= std::numeric_limits<double>::epsilon()) { // line feature
172  vpImageDraw::drawLine(I_display,
173  vpImagePoint(arr_model_iter_data.data<double>()[1], arr_model_iter_data.data<double>()[2]),
174  vpImagePoint(arr_model_iter_data.data<double>()[3], arr_model_iter_data.data<double>()[4]), vpColor::red, 3);
175  }
176  }
177  }
178  }
179 
180  vpHomogeneousMatrix cMo(vpTranslationVector(vec_poses_ptr[pose_size*iter], vec_poses_ptr[pose_size*iter + 1], vec_poses_ptr[pose_size*iter + 2]),
181  vpThetaUVector(vec_poses_ptr[pose_size*iter + 3], vec_poses_ptr[pose_size*iter + 4], vec_poses_ptr[pose_size*iter + 5])
182  );
183 
184  if (print_cMo) {
185  std::cout << "\ncMo:\n" << cMo << std::endl;
186  }
187 
188  vpDisplay::display(I_display);
189  vpDisplay::displayFrame(I_display, cMo, cam, 0.025, vpColor::none, 3);
190  vpDisplay::flush(I_display);
191 
192  vpTime::wait(30);
193  }
194 
195  std::cout << "Mean time for image decoding: " << vpMath::getMean(times) << " ms ; Median time: "
196  << vpMath::getMedian(times) << " ms ; Std: " << vpMath::getStdev(times) << " ms" << std::endl;
197 
198  vpDisplay::getClick(I_display, true);
199 
200 #else
201  (void)argc;
202  (void)argv;
203  std::cerr << "Error, a missing display library is needed (X11, GDI or OpenCV built with HighGUI module)." << std::endl;
204 #endif
205 
206  return EXIT_SUCCESS;
207 }
Generic class defining intrinsic camera parameters.
static const vpColor red
Definition: vpColor.h:211
static const vpColor none
Definition: vpColor.h:223
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)
Implementation of an homogeneous matrix and operations on such kind of matrices.
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
static void drawLine(vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, unsigned char color, unsigned int thickness=1)
vpImageIoBackendType
Image IO backend for only jpeg and png formats image loading and saving.
Definition: vpImageIo.h:123
@ IO_STB_IMAGE_BACKEND
Use embedded stb_image library.
Definition: vpImageIo.h:128
@ IO_OPENCV_BACKEND
Use OpenCV imgcodecs module.
Definition: vpImageIo.h:126
static void readPNGfromMem(const std::vector< unsigned char > &buffer, vpImage< unsigned char > &I, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:1405
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
static double getMedian(const std::vector< double > &v)
Definition: vpMath.cpp:323
static double getStdev(const std::vector< double > &v, bool useBesselCorrection=false)
Definition: vpMath.cpp:354
static double getMean(const std::vector< double > &v)
Definition: vpMath.cpp:303
Implementation of a rotation vector as axis-angle minimal representation.
Class that consider the case of a translation vector.
void display(vpImage< unsigned char > &I, const std::string &title)
Display a gray-scale image.
VISP_EXPORT npz_t npz_load(std::string fname)
Definition: vpIoTools.cpp:342
std::map< std::string, NpyArray > npz_t
Definition: vpIoTools.h:126
VISP_EXPORT int wait(double t0, double t)
VISP_EXPORT double measureTimeMs()
std::vector< size_t > shape
Definition: vpIoTools.h:120
std::vector< T > as_vec() const
Definition: vpIoTools.h:108