42#include <visp3/core/vpConfig.h>
44#if defined(VISP_HAVE_MODULE_MBT) && \
45 (defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV))
47#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
51#include <visp3/core/vpFont.h>
52#include <visp3/core/vpImageDraw.h>
53#include <visp3/core/vpIoTools.h>
54#include <visp3/gui/vpDisplayD3D.h>
55#include <visp3/gui/vpDisplayGDI.h>
56#include <visp3/gui/vpDisplayGTK.h>
57#include <visp3/gui/vpDisplayOpenCV.h>
58#include <visp3/gui/vpDisplayX.h>
59#include <visp3/io/vpImageIo.h>
60#include <visp3/io/vpParseArgv.h>
61#include <visp3/mbt/vpMbGenericTracker.h>
63#define GETOPTARGS "i:dsclt:e:DmCh"
65#ifdef ENABLE_VISP_NAMESPACE
71void usage(
const char *name,
const char *badparam)
74 Regression test for vpGenericTracker.\n\
77 %s [-i <test image path>] [-c] [-d] [-s] [-h] [-l] \n\
78 [-t <tracker type>] [-e <last frame index>] [-D] [-m] [-C]\n",
83 -i <input image path> \n\
84 Set image input path.\n\
85 These images come from ViSP-images-x.y.z.tar.gz available \n\
86 on the ViSP website.\n\
87 Setting the VISP_INPUT_IMAGE_PATH environment\n\
88 variable produces the same behavior than using\n\
92 Turn off the display.\n\
95 If display is turn off, tracking results are saved in a video folder.\n\
98 Disable the mouse click. Useful to automate the \n\
99 execution of this program without human intervention.\n\
102 Set tracker type (<1 (Edge)>, <2 (KLT)>, <3 (both)>) for color sensor.\n\
105 Use the scanline for visibility tests.\n\
107 -e <last frame index>\n\
108 Specify the index of the last frame. Once reached, the tracking is stopped.\n\
114 Set a tracking mask.\n\
120 Print the help.\n\n");
123 fprintf(stdout,
"\nERROR: Bad parameter [%s]\n", badparam);
126bool getOptions(
int argc,
const char **argv, std::string &ipath,
bool &click_allowed,
bool &display,
bool &save,
127 bool &useScanline,
int &trackerType,
int &lastFrame,
bool &use_depth,
bool &use_mask,
128 bool &use_color_image)
139 click_allowed =
false;
151 trackerType = atoi(optarg_);
154 lastFrame = atoi(optarg_);
163 use_color_image =
true;
166 usage(argv[0],
nullptr);
170 usage(argv[0], optarg_);
175 if ((c == 1) || (c == -1)) {
177 usage(argv[0],
nullptr);
178 std::cerr <<
"ERROR: " << std::endl;
179 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
186template <
typename Type>
190#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
191 static_assert(std::is_same<Type, unsigned char>::value || std::is_same<Type, vpRGBa>::value,
192 "Template function supports only unsigned char and vpRGBa images!");
194#if defined(VISP_HAVE_DATASET)
195#if VISP_HAVE_DATASET_VERSION >= 0x030600
196 std::string ext(
"png");
198 std::string ext(
"pgm");
202 std::string ext(
"png");
215 std::ifstream file_depth(depth_filename.c_str(), std::ios::in | std::ios::binary);
216 if (!file_depth.is_open())
221 I_depth.resize(depth_height, depth_width);
222 pointcloud.resize(depth_height * depth_width);
225 for (
unsigned int i = 0;
i <
I_depth.getHeight();
i++) {
226 for (
unsigned int j = 0;
j <
I_depth.getWidth();
j++) {
234 pointcloud[
i *
I_depth.getWidth() +
j] = pt3d;
238 std::ifstream file_pose(pose_filename.c_str());
239 if (!file_pose.is_open()) {
243 for (
unsigned int i = 0;
i < 4;
i++) {
244 for (
unsigned int j = 0;
j < 4;
j++) {
245 file_pose >>
cMo[
i][
j];
256template <
typename Type>
257bool run(
const std::string &input_directory,
bool opt_click_allowed,
bool opt_display,
bool useScanline,
258 int trackerType_image,
int opt_lastFrame,
bool use_depth,
bool use_mask,
bool save)
260#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
261 static_assert(std::is_same<Type, unsigned char>::value || std::is_same<Type, vpRGBa>::value,
262 "Template function supports only unsigned char and vpRGBa images!");
265#if defined(VISP_HAVE_X11)
267#elif defined(VISP_HAVE_GDI)
269#elif defined(HAVE_OPENCV_HIGHGUI)
271#elif defined(VISP_HAVE_D3D9)
273#elif defined(VISP_HAVE_GTK)
279 std::vector<int> tracker_type(2);
280 tracker_type[0] = trackerType_image;
284#if defined(VISP_HAVE_PUGIXML)
285 std::string configFileCam1 = input_directory + std::string(
"/Config/chateau.xml");
286 std::string configFileCam2 = input_directory + std::string(
"/Config/chateau_depth.xml");
287 std::cout <<
"Load config file for camera 1: " << configFileCam1 << std::endl;
288 std::cout <<
"Load config file for camera 2: " << configFileCam2 << std::endl;
289 tracker.loadConfigFile(configFileCam1, configFileCam2);
294 cam_color.initPersProjWithoutDistortion(700.0, 700.0, 320.0, 240.0);
295 cam_depth.initPersProjWithoutDistortion(700.0, 700.0, 320.0, 240.0);
296 tracker.setCameraParameters(cam_color, cam_depth);
312#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
328 tracker.setDepthNormalPclPlaneEstimationMethod(2);
329 tracker.setDepthNormalPclPlaneEstimationRansacMaxIter(200);
330 tracker.setDepthNormalPclPlaneEstimationRansacThreshold(0.001);
331 tracker.setDepthNormalSamplingStep(2, 2);
333 tracker.setDepthDenseSamplingStep(4, 4);
337 tracker.setNearClippingDistance(0.01);
338 tracker.setFarClippingDistance(2.0);
342#ifdef VISP_HAVE_COIN3D
343 tracker.loadModel(input_directory +
"/Models/chateau.wrl", input_directory +
"/Models/chateau.cao");
345 tracker.loadModel(input_directory +
"/Models/chateau.cao", input_directory +
"/Models/chateau.cao");
356 tracker.loadModel(input_directory +
"/Models/cube.cao",
false, T);
358 tracker.getCameraParameters(cam_color, cam_depth);
359 tracker.setDisplayFeatures(
true);
360 tracker.setScanLineVisibilityTest(useScanline);
362 std::map<int, std::pair<double, double> > map_thresh;
364#ifdef VISP_HAVE_COIN3D
366 useScanline ? std::pair<double, double>(0.007, 6.) : std::pair<double, double>(0.008, 3.9);
367#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
369 useScanline ? std::pair<double, double>(0.007, 1.9) : std::pair<double, double>(0.007, 1.8);
371 useScanline ? std::pair<double, double>(0.005, 3.8) : std::pair<double, double>(0.007, 3.7);
374 useScanline ? std::pair<double, double>(0.003, 1.7) : std::pair<double, double>(0.002, 0.8);
375#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
377 std::pair<double, double>(0.002, 0.3);
380 useScanline ? std::pair<double, double>(0.002, 1.8) : std::pair<double, double>(0.002, 0.7);
384 useScanline ? std::pair<double, double>(0.015, 3.0) : std::pair<double, double>(0.009, 4.0);
385#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
387 useScanline ? std::pair<double, double>(0.006, 1.7) : std::pair<double, double>(0.005, 1.4);
389 useScanline ? std::pair<double, double>(0.004, 1.2) : std::pair<double, double>(0.004, 1.2);
392 useScanline ? std::pair<double, double>(0.002, 0.7) : std::pair<double, double>(0.001, 0.4);
393#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
395 std::pair<double, double>(0.002, 0.3);
398 useScanline ? std::pair<double, double>(0.001, 0.5) : std::pair<double, double>(0.001, 0.4);
405 std::vector<vpColVector> pointcloud;
407 if (!
read_data(input_directory, cpt_frame, cam_depth, I, I_depth_raw, pointcloud, cMo_truth)) {
408 std::cerr <<
"Cannot read first frame!" << std::endl;
413 const double roi_step = 7.0;
414 const double roi_step2 = 6.0;
417 for (
unsigned int i =
static_cast<unsigned int>(I.getRows() / roi_step);
418 i <
static_cast<unsigned int>(I.getRows() * roi_step2 / roi_step); i++) {
419 for (
unsigned int j =
static_cast<unsigned int>(I.getCols() / roi_step);
420 j <
static_cast<unsigned int>(I.getCols() * roi_step2 / roi_step); j++) {
436#ifdef VISP_HAVE_DISPLAY
437 display1.
init(I, 0, 0,
"Image");
438 display2.
init(I_depth,
static_cast<int>(I.getWidth()), 0,
"Depth");
444 tracker.setCameraTransformationMatrix(
"Camera2", depth_M_color);
445 tracker.initFromPose(I, cMo_truth);
448 bool click =
false, quit =
false, correct_accuracy =
true;
449 std::vector<double> vec_err_t, vec_err_tu;
450 std::vector<double> time_vec;
451 while (
read_data(input_directory, cpt_frame, cam_depth, I, I_depth_raw, pointcloud, cMo_truth) && !quit &&
452 (opt_lastFrame > 0 ?
static_cast<int>(cpt_frame) <= opt_lastFrame :
true)) {
460 convert(I, resultsColor);
461 convert(I_depth, resultsDepth);
465 std::map<std::string, const vpImage<Type> *> mapOfImages;
466 mapOfImages[
"Camera1"] = &I;
467 std::map<std::string, const std::vector<vpColVector> *> mapOfPointclouds;
468 mapOfPointclouds[
"Camera2"] = &pointcloud;
469 std::map<std::string, unsigned int> mapOfWidths, mapOfHeights;
471 mapOfWidths[
"Camera2"] = 0;
472 mapOfHeights[
"Camera2"] = 0;
475 mapOfWidths[
"Camera2"] =
I_depth.getWidth();
476 mapOfHeights[
"Camera2"] =
I_depth.getHeight();
479 tracker.track(mapOfImages, mapOfPointclouds, mapOfWidths, mapOfHeights);
482 time_vec.push_back(t);
485 tracker.display(I, I_depth, cMo, depth_M_color * cMo, cam_color, cam_depth,
vpColor::red, 3);
489 std::stringstream ss;
490 ss <<
"Frame: " << cpt_frame;
493 ss <<
"Nb features: " <<
tracker.getError().getRows();
498 std::map<std::string, std::vector<std::vector<double> > > mapOfModels;
499 std::map<std::string, unsigned int> mapOfW;
500 mapOfW[
"Camera1"] = I.getWidth();
501 mapOfW[
"Camera2"] =
I_depth.getWidth();
502 std::map<std::string, unsigned int> mapOfH;
503 mapOfH[
"Camera1"] = I.getHeight();
504 mapOfH[
"Camera2"] =
I_depth.getHeight();
505 std::map<std::string, vpHomogeneousMatrix> mapOfcMos;
506 mapOfcMos[
"Camera1"] =
cMo;
508 std::map<std::string, vpCameraParameters> mapOfCams;
511 tracker.getModelForDisplay(mapOfModels, mapOfW, mapOfH, mapOfcMos, mapOfCams);
512 for (std::map<std::string, std::vector<std::vector<double> > >::const_iterator it = mapOfModels.begin();
513 it != mapOfModels.end(); ++it) {
514 for (
size_t i = 0;
i < it->second.size();
i++) {
516 if (std::fabs(it->second[i][0]) <= std::numeric_limits<double>::epsilon()) {
526 std::map<std::string, std::vector<std::vector<double> > > mapOfFeatures;
527 tracker.getFeaturesForDisplay(mapOfFeatures);
528 for (std::map<std::string, std::vector<std::vector<double> > >::const_iterator it = mapOfFeatures.begin();
529 it != mapOfFeatures.end(); ++it) {
530 for (
size_t i = 0;
i < it->second.size();
i++) {
531 if (std::fabs(it->second[i][0]) <=
532 std::numeric_limits<double>::epsilon()) {
534 if (std::fabs(it->second[i][3]) <= std::numeric_limits<double>::epsilon()) {
537 else if (std::fabs(it->second[i][3] - 1) <=
538 std::numeric_limits<double>::epsilon()) {
541 else if (std::fabs(it->second[i][3] - 2) <=
542 std::numeric_limits<double>::epsilon()) {
545 else if (std::fabs(it->second[i][3] - 3) <=
546 std::numeric_limits<double>::epsilon()) {
549 else if (std::fabs(it->second[i][3] - 4) <=
550 std::numeric_limits<double>::epsilon()) {
554 vpImagePoint(it->second[i][1], it->second[i][2]), 3, color, 1);
556 else if (std::fabs(it->second[i][0] - 1) <=
557 std::numeric_limits<double>::epsilon()) {
566 std::ostringstream oss;
567 oss <<
"Tracking time: " <<
t <<
" ms";
575 for (
unsigned int i = 0;
i < 3;
i++) {
576 t_est[
i] = pose_est[
i];
577 t_truth[
i] = pose_truth[
i];
578 tu_est[
i] = pose_est[
i + 3];
579 tu_truth[
i] = pose_truth[
i + 3];
582 vpColVector t_err = t_truth - t_est, tu_err = tu_truth - tu_est;
583 const double t_thresh =
585 const double tu_thresh =
588 vec_err_t.push_back(t_err2);
589 vec_err_tu.push_back(tu_err2);
590 if (!use_mask && (t_err2 > t_thresh || tu_err2 > tu_thresh)) {
591 std::cerr <<
"Pose estimated exceeds the threshold (t_thresh = " << t_thresh <<
" ; tu_thresh = " << tu_thresh
592 <<
")!" << std::endl;
593 std::cout <<
"t_err: " << t_err2 <<
" ; tu_err: " << tu_err2 << std::endl;
594 correct_accuracy =
false;
600 vpImagePoint(I.getRows() * roi_step2 / roi_step, I.getCols() * roi_step2 / roi_step));
617 if (opt_display && opt_click_allowed) {
638 if (!time_vec.empty())
643 if (!vec_err_t.empty())
644 std::cout <<
"Max translation error: " << *std::max_element(vec_err_t.begin(), vec_err_t.end()) << std::endl;
646 if (!vec_err_tu.empty())
647 std::cout <<
"Max thetau error: " << *std::max_element(vec_err_tu.begin(), vec_err_tu.end()) << std::endl;
649 std::cout <<
"Test result: " << (correct_accuracy ?
"success" :
"failure") << std::endl;
650 return correct_accuracy ? EXIT_SUCCESS : EXIT_FAILURE;
654int main(
int argc,
const char *argv[])
657 std::string env_ipath;
658 std::string opt_ipath =
"";
659 bool opt_click_allowed =
true;
660 bool opt_display =
true;
661 bool opt_save =
false;
662 bool useScanline =
false;
664#if defined(__mips__) || defined(__mips) || defined(mips) || defined(__MIPS__)
666 int opt_lastFrame = 5;
668 int opt_lastFrame = -1;
670 bool use_depth =
false;
671 bool use_mask =
false;
672 bool use_color_image =
false;
679 if (!getOptions(argc, argv, opt_ipath, opt_click_allowed, opt_display, opt_save, useScanline, trackerType_image,
680 opt_lastFrame, use_depth, use_mask, use_color_image)) {
684#if ! (defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO))
685 if (trackerType_image == 2 || trackerType_image == 3) {
686 std::cout <<
"Using klt tracker is not possible without OpenCV imgproc and video modules." << std::endl;
687 std::cout <<
"Use rather command line option -t 1 to use edges." << std::endl;
691 std::cout <<
"trackerType_image: " << trackerType_image << std::endl;
692 std::cout <<
"useScanline: " << useScanline << std::endl;
693 std::cout <<
"use_depth: " << use_depth << std::endl;
694 std::cout <<
"use_mask: " << use_mask << std::endl;
695 std::cout <<
"use_color_image: " << use_color_image << std::endl;
696#ifdef VISP_HAVE_COIN3D
697 std::cout <<
"COIN3D available." << std::endl;
700#if !defined(VISP_HAVE_MODULE_KLT) || (!defined(VISP_HAVE_OPENCV) || (VISP_HAVE_OPENCV_VERSION < 0x020100))
701 if (trackerType_image & 2) {
702 std::cout <<
"KLT features cannot be used: ViSP is not built with "
703 "KLT module or OpenCV is not available.\nTest is not run."
710 if (opt_ipath.empty() && env_ipath.empty()) {
711 usage(argv[0],
nullptr);
712 std::cerr << std::endl <<
"ERROR:" << std::endl;
713 std::cerr <<
" Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
714 <<
" environment variable to specify the location of the " << std::endl
715 <<
" image path where test images are located." << std::endl
721 std::string input_directory =
724 std::cerr <<
"ViSP-images does not contain the folder: " << input_directory <<
"!" << std::endl;
728 if (use_color_image) {
729 return run<vpRGBa>(input_directory, opt_click_allowed, opt_display, useScanline, trackerType_image, opt_lastFrame,
730 use_depth, use_mask, opt_save);
733 return run<unsigned char>(input_directory, opt_click_allowed, opt_display, useScanline, trackerType_image,
734 opt_lastFrame, use_depth, use_mask, opt_save);
737 std::cout <<
"Test succeed" << std::endl;
741 std::cout <<
"Catch an exception: " <<
e << std::endl;
745#elif !(defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV))
748 std::cout <<
"Cannot run this example: install Lapack, Eigen3 or OpenCV" << std::endl;
754 std::cout <<
"Enable MBT module (VISP_HAVE_MODULE_MBT) to launch this test." << std::endl;
Generic class defining intrinsic camera parameters.
Implementation of column vector and the associated operations.
Class to define RGB colors available for display functionalities.
static const vpColor cyan
static const vpColor none
static const vpColor blue
static const vpColor purple
static const vpColor yellow
static const vpColor green
Display for windows using Direct3D 3rd party. Thus to enable this class Direct3D should be installed....
Display for windows using GDI (available on any windows 32 platform).
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
void init(vpImage< unsigned char > &I, int win_x=-1, int win_y=-1, const std::string &win_title="") VP_OVERRIDE
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 displayRectangle(const vpImage< unsigned char > &I, const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)
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.
Font drawing functions for image.
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 drawLine(vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, unsigned char color, unsigned int thickness=1)
static void drawCross(vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, unsigned char color, unsigned int thickness=1)
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
static void write(const vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition of the vpImage class member functions.
Wrapper for the KLT (Kanade-Lucas-Tomasi) feature tracker implemented in OpenCV. Thus to enable this ...
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)
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)
static double deg(double rad)
Real-time 6D object pose tracking using its CAD model.
@ ROBUST_FEATURE_ESTIMATION
Robust scheme to estimate the normal of the plane.
void setMu1(const double &mu_1)
void setRange(const unsigned int &range)
void setLikelihoodThresholdType(const vpLikelihoodThresholdType likelihood_threshold_type)
void setMaskNumber(const unsigned int &mask_number)
void setThreshold(const double &threshold)
void setSampleStep(const double &sample_step)
void setMaskSize(const unsigned int &mask_size)
void setMu2(const double &mu_2)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
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.
Defines a rectangle in the plane.
read_data(CameraParameters|None cam_depth, ImageGray I, rs.pipeline pipe)
VISP_EXPORT double measureTimeMs()