Regression test for depth MBT.
#include <cstdlib>
#include <iostream>
#include <visp3/core/vpConfig.h>
#if defined(VISP_HAVE_MODULE_MBT) && (defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV))
#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
#include <type_traits>
#endif
#include <visp3/core/vpIoTools.h>
#include <visp3/gui/vpDisplayD3D.h>
#include <visp3/gui/vpDisplayGDI.h>
#include <visp3/gui/vpDisplayGTK.h>
#include <visp3/gui/vpDisplayOpenCV.h>
#include <visp3/gui/vpDisplayX.h>
#include <visp3/io/vpImageIo.h>
#include <visp3/io/vpParseArgv.h>
#include <visp3/mbt/vpMbGenericTracker.h>
#define GETOPTARGS "i:dcle:mCh"
#ifdef ENABLE_VISP_NAMESPACE
#endif
namespace
{
void usage(const char *name, const char *badparam)
{
fprintf(stdout, "\n\
Regression test for vpGenericTracker and depth.\n\
\n\
SYNOPSIS\n\
%s [-i <test image path>] [-c] [-d] [-h] [-l] \n\
[-e <last frame index>] [-m] [-C]\n",
name);
fprintf(stdout, "\n\
OPTIONS: \n\
-i <input image path> \n\
Set image input path.\n\
These images come from ViSP-images-x.y.z.tar.gz available \n\
on the ViSP website.\n\
Setting the VISP_INPUT_IMAGE_PATH environment\n\
variable produces the same behavior than using\n\
this option.\n\
\n\
-d \n\
Turn off the display.\n\
\n\
-c\n\
Disable the mouse click. Useful to automate the \n\
execution of this program without human intervention.\n\
\n\
-l\n\
Use the scanline for visibility tests.\n\
\n\
-e <last frame index>\n\
Specify the index of the last frame. Once reached, the tracking is stopped.\n\
\n\
-m \n\
Set a tracking mask.\n\
\n\
-C \n\
Use color images.\n\
\n\
-h \n\
Print the help.\n\n");
if (badparam)
fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
}
bool getOptions(int argc, const char **argv, std::string &ipath, bool &click_allowed, bool &display, bool &useScanline,
int &lastFrame, bool &use_mask, bool &use_color_image)
{
const char *optarg_;
int c;
switch (c) {
case 'i':
ipath = optarg_;
break;
case 'c':
click_allowed = false;
break;
case 'd':
display = false;
break;
case 'l':
useScanline = true;
break;
case 'e':
lastFrame = atoi(optarg_);
break;
case 'm':
use_mask = true;
break;
case 'C':
use_color_image = true;
break;
case 'h':
usage(argv[0], nullptr);
return false;
break;
default:
usage(argv[0], optarg_);
return false;
break;
}
}
if ((c == 1) || (c == -1)) {
usage(argv[0], nullptr);
std::cerr << "ERROR: " << std::endl;
std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
return false;
}
return true;
}
template <typename Type>
{
#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
static_assert(std::is_same<Type, unsigned char>::value || std::is_same<Type, vpRGBa>::value,
"Template function supports only unsigned char and vpRGBa images!");
#endif
#if VISP_HAVE_DATASET_VERSION >= 0x030600
std::string ext("png");
#else
std::string ext("pgm");
#endif
char buffer[FILENAME_MAX];
snprintf(buffer, FILENAME_MAX, std::string(input_directory + "/Images/Image_%04d." + ext).c_str(), cpt);
std::string image_filename = buffer;
snprintf(buffer, FILENAME_MAX, std::string(input_directory + "/Depth/Depth_%04d.bin").c_str(), cpt);
std::string depth_filename = buffer;
snprintf(buffer, FILENAME_MAX, std::string(input_directory + "/CameraPose/Camera_%03d.txt").c_str(), cpt);
std::string pose_filename = buffer;
return false;
unsigned int depth_width = 0, depth_height = 0;
std::ifstream file_depth(depth_filename.c_str(), std::ios::in | std::ios::binary);
if (!file_depth.is_open())
return false;
I_depth.
resize(depth_height, depth_width);
pointcloud.resize(depth_height * depth_width);
const float depth_scale = 0.000030518f;
for (
unsigned int i = 0; i < I_depth.
getHeight(); i++) {
for (
unsigned int j = 0; j < I_depth.
getWidth(); j++) {
double x = 0.0, y = 0.0, Z = I_depth[i][j] * depth_scale;
pt3d[0] = x * Z;
pt3d[1] = y * Z;
pt3d[2] = Z;
pointcloud[i * I_depth.
getWidth() + j] = pt3d;
}
}
std::ifstream file_pose(pose_filename.c_str());
if (!file_pose.is_open()) {
return false;
}
for (unsigned int i = 0; i < 4; i++) {
for (unsigned int j = 0; j < 4; j++) {
file_pose >> cMo[i][j];
}
}
return true;
}
template <typename Type>
bool run(
vpImage<Type> &I,
const std::string &input_directory,
bool opt_click_allowed,
bool opt_display,
bool useScanline, int opt_lastFrame, bool use_mask)
{
#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
static_assert(std::is_same<Type, unsigned char>::value || std::is_same<Type, vpRGBa>::value,
"Template function supports only unsigned char and vpRGBa images!");
#endif
#if defined(VISP_HAVE_X11)
vpDisplayX display1, display2;
#elif defined(VISP_HAVE_GDI)
#elif defined(HAVE_OPENCV_HIGHGUI)
#elif defined(VISP_HAVE_D3D9)
#elif defined(VISP_HAVE_GTK)
#else
opt_display = false;
#endif
std::vector<int> tracker_type;
#if defined(VISP_HAVE_PUGIXML)
tracker.
loadConfigFile(input_directory +
"/Config/chateau_depth.xml");
#else
{
}
#if defined(VISP_HAVE_MODULE_KLT) && defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
tracker.setKltMaskBorder(5);
#endif
#endif
tracker.
loadModel(input_directory +
"/Models/chateau.cao");
T[0][0] = -1;
T[0][3] = -0.2;
T[1][1] = 0;
T[1][2] = 1;
T[1][3] = 0.12;
T[2][1] = 1;
T[2][2] = 0;
T[2][3] = -0.15;
tracker.
loadModel(input_directory +
"/Models/cube.cao",
false, T);
std::vector<vpColVector> pointcloud;
int cpt_frame = 1;
if (!read_data(input_directory, cpt_frame, cam_depth, I, I_depth_raw, pointcloud, cMo_truth)) {
std::cerr << "Cannot read first frame!" << std::endl;
return EXIT_FAILURE;
}
const double roi_step = 7.0;
const double roi_step2 = 6.0;
if (use_mask) {
mask = false;
for (
unsigned int i = (
unsigned int)(I.
getRows() / roi_step);
i < (
unsigned int)(I.
getRows() * roi_step2 / roi_step); i++) {
for (
unsigned int j = (
unsigned int)(I.
getCols() / roi_step);
j < (
unsigned int)(I.
getCols() * roi_step2 / roi_step); j++) {
mask[i][j] = true;
}
}
}
if (opt_display) {
#ifdef VISP_HAVE_DISPLAY
display1.init(I, 0, 0, "Image");
display2.init(I_depth, (
int)I.
getWidth(), 0,
"Depth");
#endif
}
depth_M_color[0][3] = -0.05;
bool click = false, quit = false, correct_accuracy = true;
std::vector<double> vec_err_t, vec_err_tu;
std::vector<double> time_vec;
while (read_data(input_directory, cpt_frame, cam_depth, I, I_depth_raw, pointcloud, cMo_truth) && !quit &&
(opt_lastFrame > 0 ? (int)cpt_frame <= opt_lastFrame : true)) {
if (opt_display) {
}
std::map<std::string, const vpImage<Type> *> mapOfImages;
std::map<std::string, const std::vector<vpColVector> *> mapOfPointclouds;
mapOfPointclouds["Camera"] = &pointcloud;
std::map<std::string, unsigned int> mapOfWidths, mapOfHeights;
mapOfWidths[
"Camera"] = I_depth.
getWidth();
mapOfHeights[
"Camera"] = I_depth.
getHeight();
tracker.
track(mapOfImages, mapOfPointclouds, mapOfWidths, mapOfHeights);
time_vec.push_back(t);
if (opt_display) {
std::stringstream ss;
ss << "Frame: " << cpt_frame;
ss.str("");
}
for (unsigned int i = 0; i < 3; i++) {
t_est[i] = pose_est[i];
t_truth[i] = pose_truth[i];
tu_est[i] = pose_est[i + 3];
tu_truth[i] = pose_truth[i + 3];
}
vpColVector t_err = t_truth - t_est, tu_err = tu_truth - tu_est;
vec_err_t.push_back(t_err2);
vec_err_tu.push_back(tu_err2);
const double t_thresh = useScanline ? 0.003 : 0.002;
const double tu_thresh = useScanline ? 0.5 : 0.4;
if (!use_mask && (t_err2 > t_thresh || tu_err2 > tu_thresh)) {
std::cerr << "Pose estimated exceeds the threshold (t_thresh = " << t_thresh << ", tu_thresh = " << tu_thresh
<< ")!" << std::endl;
std::cout << "t_err: " << t_err2 << " ; tu_err: " << tu_err2 << std::endl;
correct_accuracy = false;
}
if (opt_display) {
if (use_mask) {
}
}
if (opt_display && opt_click_allowed) {
switch (button) {
quit = !click;
break;
click = !click;
break;
default:
break;
}
}
}
cpt_frame++;
}
if (!time_vec.empty())
<< std::endl;
if (!vec_err_t.empty())
std::cout << "Max translation error: " << *std::max_element(vec_err_t.begin(), vec_err_t.end()) << std::endl;
if (!vec_err_tu.empty())
std::cout << "Max thetau error: " << *std::max_element(vec_err_tu.begin(), vec_err_tu.end()) << std::endl;
return correct_accuracy ? EXIT_SUCCESS : EXIT_FAILURE;
}
}
int main(int argc, const char *argv[])
{
try {
std::string env_ipath;
std::string opt_ipath = "";
bool opt_click_allowed = true;
bool opt_display = true;
bool useScanline = false;
#if defined(__mips__) || defined(__mips) || defined(mips) || defined(__MIPS__)
int opt_lastFrame = 5;
#else
int opt_lastFrame = -1;
#endif
bool use_mask = false;
bool use_color_image = false;
if (!getOptions(argc, argv, opt_ipath, opt_click_allowed, opt_display, useScanline, opt_lastFrame, use_mask,
use_color_image)) {
return EXIT_FAILURE;
}
std::cout << "useScanline: " << useScanline << std::endl;
std::cout << "use_mask: " << use_mask << std::endl;
std::cout << "use_color_image: " << use_color_image << std::endl;
if (opt_ipath.empty() && env_ipath.empty()) {
usage(argv[0], nullptr);
std::cerr << std::endl << "ERROR:" << std::endl;
std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
<< " environment variable to specify the location of the " << std::endl
<< " image path where test images are located." << std::endl
<< std::endl;
return EXIT_FAILURE;
}
std::string input_directory =
std::cerr << "ViSP-images does not contain the folder: " << input_directory << "!" << std::endl;
return EXIT_SUCCESS;
}
if (use_color_image) {
return run(I_color, input_directory, opt_click_allowed, opt_display, useScanline, opt_lastFrame, use_mask);
}
else {
return run(I_gray, input_directory, opt_click_allowed, opt_display, useScanline, opt_lastFrame, use_mask);
}
}
std::cout << "Catch an exception: " << e << std::endl;
return EXIT_FAILURE;
}
}
#elif !(defined(VISP_HAVE_LAPACK) || defined(VISP_HAVE_EIGEN3) || defined(VISP_HAVE_OPENCV))
int main()
{
std::cout << "Cannot run this example: install Lapack, Eigen3 or OpenCV" << std::endl;
return EXIT_SUCCESS;
}
#else
int main()
{
std::cout << "Enable MBT module (VISP_HAVE_MODULE_MBT) to launch this test." << std::endl;
return EXIT_SUCCESS;
}
#endif
unsigned int getRows() const
Generic class defining intrinsic camera parameters.
void initPersProjWithoutDistortion(double px, double py, double u0, double v0)
Implementation of column vector and the associated operations.
static const vpColor none
static const vpColor yellow
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...
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.
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)
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.
unsigned int getWidth() const
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
unsigned int getCols() const
unsigned int getHeight() const
unsigned int getRows() const
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.
virtual void setCameraParameters(const vpCameraParameters &camera) VP_OVERRIDE
virtual void setDisplayFeatures(bool displayF) VP_OVERRIDE
virtual vpColVector getError() const VP_OVERRIDE
virtual void getCameraParameters(vpCameraParameters &camera) const VP_OVERRIDE
virtual void initFromPose(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo) VP_OVERRIDE
virtual void setDepthNormalSamplingStep(unsigned int stepX, unsigned int stepY)
virtual void getPose(vpHomogeneousMatrix &cMo) const VP_OVERRIDE
virtual void setDepthNormalPclPlaneEstimationMethod(int method)
virtual void setDepthNormalPclPlaneEstimationRansacMaxIter(int maxIter)
virtual void setDepthNormalPclPlaneEstimationRansacThreshold(double threshold)
virtual void setAngleDisappear(const double &a) VP_OVERRIDE
virtual void setDepthDenseSamplingStep(unsigned int stepX, unsigned int stepY)
virtual void track(const vpImage< unsigned char > &I) VP_OVERRIDE
virtual void loadModel(const std::string &modelFile, bool verbose=false, const vpHomogeneousMatrix &T=vpHomogeneousMatrix()) VP_OVERRIDE
virtual void setMask(const vpImage< bool > &mask) VP_OVERRIDE
virtual void getClipping(unsigned int &clippingFlag1, unsigned int &clippingFlag2) const
virtual void setClipping(const unsigned int &flags) VP_OVERRIDE
virtual void setScanLineVisibilityTest(const bool &v) VP_OVERRIDE
virtual void setNearClippingDistance(const double &dist) VP_OVERRIDE
virtual void setDepthNormalFeatureEstimationMethod(const vpMbtFaceDepthNormal::vpFeatureEstimationType &method)
virtual void display(const vpImage< unsigned char > &I, const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, const vpColor &col, unsigned int thickness=1, bool displayFullModel=false) VP_OVERRIDE
virtual void loadConfigFile(const std::string &configFile, bool verbose=true) VP_OVERRIDE
virtual void setAngleAppear(const double &a) VP_OVERRIDE
virtual void setFarClippingDistance(const double &dist) VP_OVERRIDE
@ ROBUST_FEATURE_ESTIMATION
Robust scheme to estimate the normal of the plane.
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.
VISP_EXPORT double measureTimeMs()