#include <iostream>
#include <visp3/core/vpConfig.h>
#if defined(VISP_HAVE_OCCIPITAL_STRUCTURE) && defined(VISP_HAVE_PUGIXML) && defined(VISP_HAVE_OPENCV) && \
(((VISP_HAVE_OPENCV_VERSION < 0x050000) && (defined(HAVE_OPENCV_FEATURES2D) || defined(HAVE_OPENCV_XFEATURES2D))) || \
((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_FEATURES)))
#include <visp3/core/vpDisplay.h>
#include <visp3/core/vpIoTools.h>
#include <visp3/core/vpXmlParserCamera.h>
#include <visp3/gui/vpDisplayFactory.h>
#include <visp3/mbt/vpMbGenericTracker.h>
#include <visp3/sensor/vpOccipitalStructure.h>
#include <visp3/vision/vpKeyPoint.h>
#ifdef ENABLE_VISP_NAMESPACE
#endif
#ifndef DOXYGEN_SHOULD_SKIP_THIS
typedef enum DepthType
{
DEPTH_UNUSED = 0,
DEPTH_DENSE = 1,
DEPTH_NORMAL = 2,
DEPTH_COUNT = 3
}DepthType;
std::string depthTypeToString(const DepthType &type)
{
std::string name;
switch (type) {
case DEPTH_UNUSED:
name = "unused";
break;
case DEPTH_DENSE:
name = "dense";
break;
case DEPTH_NORMAL:
name = "normals";
break;
case DEPTH_COUNT:
default:
name = "unknown";
break;
}
return name;
}
DepthType depthTypeFromString(const std::string &name)
{
DepthType
type(DEPTH_COUNT);
bool notFound = true;
while ((i < static_cast<unsigned int>(DEPTH_COUNT)) && notFound) {
DepthType candidate =
static_cast<DepthType
>(
i);
notFound = false;
}
}
}
std::string getDepthTypeList(const std::string &prefix = "<", const std::string &sep = " , ", const std::string &suffix = ">")
{
std::string list(prefix);
while (i < static_cast<unsigned int>(DEPTH_COUNT - 1)) {
DepthType
type =
static_cast<DepthType
>(
i);
std::string name = depthTypeToString(type);
list += name + sep;
}
DepthType
type =
static_cast<DepthType
>(DEPTH_COUNT - 1);
std::string name = depthTypeToString(type);
list += name + suffix;
return list;
}
#endif
int main(int argc, char *argv[])
{
std::string config_color = "", config_depth = "";
std::string model_color = "", model_depth = "";
std::string init_file = "";
bool use_ogre = false;
bool use_scanline = false;
bool use_edges = true;
bool use_klt = true;
DepthType use_depth = DEPTH_DENSE;
bool learn = false;
bool auto_init = false;
double proj_error_threshold = 25;
std::string learning_data = "learning/data-learned.bin";
bool display_projection_error = false;
for (
int i = 1;
i < argc;
i++) {
if (std::string(argv[i]) == "--config_color" && i + 1 < argc) {
config_color = std::string(argv[i + 1]);
}
else if (std::string(argv[i]) == "--config_depth" && i + 1 < argc) {
config_depth = std::string(argv[i + 1]);
}
else if (std::string(argv[i]) == "--model_color" && i + 1 < argc) {
model_color = std::string(argv[i + 1]);
}
else if (std::string(argv[i]) == "--model_depth" && i + 1 < argc) {
model_depth = std::string(argv[i + 1]);
}
else if (std::string(argv[i]) == "--init_file" && i + 1 < argc) {
init_file = std::string(argv[i + 1]);
}
else if (std::string(argv[i]) == "--proj_error_threshold" && i + 1 < argc) {
proj_error_threshold = std::atof(argv[i + 1]);
}
else if (std::string(argv[i]) == "--use_ogre") {
use_ogre = true;
}
else if (std::string(argv[i]) == "--use_scanline") {
use_scanline = true;
}
else if (std::string(argv[i]) == "--use_edges" && i + 1 < argc) {
use_edges = (std::atoi(argv[i + 1]) == 0 ? false : true);
}
else if (std::string(argv[i]) == "--use_klt" && i + 1 < argc) {
use_klt = (std::atoi(argv[i + 1]) == 0 ? false : true);
}
else if (std::string(argv[i]) == "--use_depth" && i + 1 < argc) {
use_depth = depthTypeFromString(std::string(argv[i + 1]));
}
else if (std::string(argv[i]) == "--learn") {
learn = true;
}
else if (std::string(argv[i]) == "--learning_data" && i + 1 < argc) {
learning_data = argv[
i + 1];
}
else if (std::string(argv[i]) == "--auto_init") {
auto_init = true;
}
else if (std::string(argv[i]) == "--display_proj_error") {
display_projection_error = true;
}
else if (std::string(argv[i]) == "--help" || std::string(argv[i]) == "-h") {
std::cout << "Usage: \n"
<< argv[0]
<< " [--model_color <object.cao>] [--model_depth <object.cao>]"
" [--config_color <object.xml>] [--config_depth <object.xml>]"
" [--init_file <object.init>] [--use_ogre] [--use_scanline]"
" [--proj_error_threshold <threshold between 0 and 90> (default: "
<< proj_error_threshold
<< ")]"
" [--use_edges <0|1> (default: 1)] [--use_klt <0|1> (default: 1)] [--use_depth " + getDepthTypeList() + " (default: " + depthTypeToString(use_depth) + ")]"
" [--learn] [--auto_init] [--learning_data <path to .bin> (default: learning/data-learned.bin)]"
" [--display_proj_error]"
<< std::endl;
std::cout << "\n** How to track a 4.2 cm width cube with manual initialization:\n"
<< argv[0] << " --model_color model/cube/cube.cao --use_edges 1 --use_klt 1 --use_depth 1" << std::endl;
std::cout << "\n** How to learn the cube and create a learning database:\n"
<< argv[0] << " --model_color model/cube/cube.cao --use_edges 1 --use_klt 1 --use_depth 1 --learn"
<< std::endl;
std::cout << "\n** How to track the cube with initialization from learning database:\n"
<< argv[0] << " --model_color model/cube/cube.cao --use_edges 1 --use_klt 1 --use_depth 1 --auto_init"
<< std::endl;
return EXIT_SUCCESS;
}
}
if (model_depth.empty()) {
model_depth = model_color;
}
if (config_color.empty()) {
config_color = (parentname.empty() ?
"" : (parentname +
"/")) +
vpIoTools::getNameWE(model_color) +
".xml";
}
if (config_depth.empty()) {
config_depth = (parentname.empty() ?
"" : (parentname +
"/")) +
vpIoTools::getNameWE(model_color) +
"_depth.xml";
}
if (init_file.empty()) {
init_file = (parentname.empty() ?
"" : (parentname +
"/")) +
vpIoTools::getNameWE(model_color) +
".init";
}
std::cout << "Tracked features: " << std::endl;
std::cout << " Use edges : " << use_edges << std::endl;
std::cout << " Use klt : " << use_klt << std::endl;
std::cout << " Use depth : " << depthTypeToString(use_depth) << std::endl;
std::cout << "Tracker options: " << std::endl;
std::cout << " Use ogre : " << use_ogre << std::endl;
std::cout << " Use scanline: " << use_scanline << std::endl;
std::cout << " Proj. error : " << proj_error_threshold << std::endl;
std::cout << " Display proj. error: " << display_projection_error << std::endl;
std::cout << "Config files: " << std::endl;
std::cout << " Config color: "
<< "\"" << config_color << "\"" << std::endl;
std::cout << " Config depth: "
<< "\"" << config_depth << "\"" << std::endl;
std::cout << " Model color : "
<< "\"" << model_color << "\"" << std::endl;
std::cout << " Model depth : "
<< "\"" << model_depth << "\"" << std::endl;
std::cout << " Init file : "
<< "\"" << init_file << "\"" << std::endl;
std::cout << "Learning options : " << std::endl;
std::cout << " Learn : " << learn << std::endl;
std::cout << " Auto init : " << auto_init << std::endl;
std::cout << " Learning data: " << learning_data << std::endl;
if (!use_edges && !use_klt && (use_depth == DEPTH_UNUSED)) {
std::cout << "You must choose at least one visual features between edge, KLT and depth." << std::endl;
return EXIT_FAILURE;
}
if (config_color.empty() || config_depth.empty() || model_color.empty() || model_depth.empty() || init_file.empty()) {
std::cout << "config_color.empty() || config_depth.empty() || model_color.empty() || model_depth.empty() || "
"init_file.empty()"
<< std::endl;
return EXIT_FAILURE;
}
ST::CaptureSessionSettings settings;
settings.source = ST::CaptureSessionSourceId::StructureCore;
settings.structureCore.visibleEnabled = true;
settings.applyExpensiveCorrection = true;
try {
}
std::cout <<
"Catch an exception: " <<
e.what() << std::endl;
std::cout << "Check if the Structure Core camera is connected..." << std::endl;
return EXIT_SUCCESS;
}
std::cout <<
"Sensor internal camera parameters for color camera: " <<
cam_color << std::endl;
std::cout <<
"Sensor internal camera parameters for depth camera: " <<
cam_depth << std::endl;
unsigned int _posx = 100, _posy = 50;
#ifdef VISP_HAVE_DISPLAY
#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
#else
#endif
if (use_edges || use_klt) {
display1->init(I_gray, _posx, _posy, "Color stream");
}
if (use_depth != DEPTH_UNUSED) {
display2->init(I_depth, _posx + I_gray.getWidth() + 10, _posy, "Depth stream");
}
#endif
while (true) {
sc.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap,
nullptr,
nullptr,
nullptr);
if (use_edges || use_klt) {
break;
}
}
if (use_depth != DEPTH_UNUSED) {
break;
}
}
}
std::vector<int> trackerTypes;
if (use_edges && use_klt)
else if (use_edges)
else if (use_klt)
if (use_depth == DEPTH_DENSE) {
}
else if (use_depth == DEPTH_NORMAL) {
}
std::map<std::string, vpHomogeneousMatrix> mapOfCameraTransformations;
std::map<std::string, const vpImage<unsigned char> *> mapOfImages;
std::map<std::string, std::string> mapOfInitFiles;
std::map<std::string, const std::vector<vpColVector> *> mapOfPointclouds;
std::map<std::string, unsigned int> mapOfWidths, mapOfHeights;
std::map<std::string, vpHomogeneousMatrix> mapOfCameraPoses;
std::vector<vpColVector> pointcloud;
if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
tracker.loadConfigFile(config_color, config_depth);
tracker.loadModel(model_color, model_depth);
std::cout <<
"Sensor internal depth_M_color: \n" <<
depth_M_color << std::endl;
tracker.setCameraTransformationMatrix(mapOfCameraTransformations);
mapOfImages["Camera1"] = &I_gray;
mapOfInitFiles["Camera1"] = init_file;
tracker.setCameraParameters(cam_color, cam_depth);
}
else if (use_edges || use_klt) {
tracker.loadConfigFile(config_color);
tracker.setCameraParameters(cam_color);
}
else if (use_depth != DEPTH_UNUSED) {
tracker.loadConfigFile(config_depth);
tracker.setCameraParameters(cam_depth);
}
tracker.setOgreVisibilityTest(use_ogre);
tracker.setScanLineVisibilityTest(use_scanline);
tracker.setProjectionErrorComputation(
true);
tracker.setProjectionErrorDisplay(display_projection_error);
#if ((VISP_HAVE_OPENCV_VERSION < 0x050000) && defined(HAVE_OPENCV_XFEATURES2D)) || ((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_FEATURES))
std::string detectorName = "SIFT";
std::string extractorName = "SIFT";
std::string matcherName = "BruteForce";
#elif ((VISP_HAVE_OPENCV_VERSION < 0x050000) && defined(HAVE_OPENCV_FEATURES2D)) || ((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_FEATURES))
std::string detectorName = "FAST";
std::string extractorName = "ORB";
#endif
std::string matcherName = "BruteForce-Hamming";
if (learn || auto_init) {
#if ((VISP_HAVE_OPENCV_VERSION < 0x050000) && defined(HAVE_OPENCV_FEATURES2D)) || ((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_FEATURES))
cv::Ptr<cv::ORB> orb_detector = keypoint.
getDetector(
"ORB").dynamicCast<cv::ORB>();
if (orb_detector) {
orb_detector->setNLevels(1);
}
#endif
}
if (auto_init) {
std::cout << "Cannot enable auto detection. Learning file \"" << learning_data << "\" doesn't exist" << std::endl;
return EXIT_FAILURE;
}
}
else {
if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
tracker.initClick(mapOfImages, mapOfInitFiles,
true);
}
else if (use_edges || use_klt) {
tracker.initClick(I_gray, init_file,
true);
}
else if (use_depth != DEPTH_UNUSED) {
tracker.initClick(I_depth, init_file,
true);
}
if (learn)
}
bool run_auto_init = false;
if (auto_init) {
run_auto_init = true;
}
std::vector<double> times_vec;
try {
int learn_id = 1;
bool quit = false;
bool learn_position = false;
double loop_t = 0;
while (!quit) {
bool tracking_failed = false;
sc.
acquire((
unsigned char *)I_color.bitmap, (
unsigned char *)I_depth_raw.bitmap, &pointcloud);
if (use_edges || use_klt || run_auto_init) {
}
if (use_depth != DEPTH_UNUSED) {
}
if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
mapOfImages["Camera1"] = &I_gray;
mapOfPointclouds["Camera2"] = &pointcloud;
mapOfWidths[
"Camera2"] =
width;
mapOfHeights[
"Camera2"] =
height;
}
else if (use_edges || use_klt) {
mapOfImages["Camera"] = &I_gray;
}
else if (use_depth != DEPTH_UNUSED) {
mapOfPointclouds["Camera"] = &pointcloud;
mapOfWidths[
"Camera"] =
width;
mapOfHeights[
"Camera"] =
height;
}
if (run_auto_init) {
if (keypoint.
matchPoint(I_gray, cam_color, cMo)) {
std::cout << "Auto init succeed" << std::endl;
if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
mapOfCameraPoses[
"Camera1"] =
cMo;
tracker.initFromPose(mapOfImages, mapOfCameraPoses);
}
else if (use_edges || use_klt) {
}
else if (use_depth != DEPTH_UNUSED) {
tracker.initFromPose(I_depth, depth_M_color * cMo);
}
}
else {
if (use_edges || use_klt) {
}
if (use_depth != DEPTH_UNUSED) {
}
continue;
}
}
try {
if (run_auto_init) {
run_auto_init = false;
}
if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
tracker.track(mapOfImages, mapOfPointclouds, mapOfWidths, mapOfHeights);
}
else if (use_edges || use_klt) {
}
else if (use_depth != DEPTH_UNUSED) {
tracker.track(mapOfImages, mapOfPointclouds, mapOfWidths, mapOfHeights);
}
}
std::cout <<
"Tracker exception: " <<
e.getStringMessage() << std::endl;
tracking_failed = true;
if (auto_init) {
std::cout << "Tracker needs to restart (tracking exception)" << std::endl;
run_auto_init = true;
}
}
double proj_error = 0;
proj_error =
tracker.getProjectionError();
}
else {
proj_error =
tracker.computeCurrentProjectionError(I_gray, cMo, cam_color);
}
if (auto_init && proj_error > proj_error_threshold) {
std::cout << "Tracker needs to restart (projection error detected: " << proj_error << ")" << std::endl;
run_auto_init = true;
tracking_failed = true;
}
if (!tracking_failed) {
if ((use_edges || use_klt) && (use_depth != DEPTH_UNUSED)) {
tracker.display(I_gray, I_depth, cMo, depth_M_color * cMo, cam_color, cam_depth,
vpColor::red, 3);
}
else if (use_edges || use_klt) {
}
else if (use_depth != DEPTH_UNUSED) {
}
{
std::stringstream ss;
ss <<
"Nb features: " <<
tracker.getError().size();
}
{
std::stringstream ss;
ss <<
"Features: edges " <<
tracker.getNbFeaturesEdge() <<
", klt " <<
tracker.getNbFeaturesKlt()
<<
", depth " <<
tracker.getNbFeaturesDepthDense();
}
}
std::stringstream ss;
ss << "Loop time: " << loop_t << " ms";
if (use_edges || use_klt) {
if (learn)
else if (auto_init)
else
quit = true;
}
learn_position = true;
}
run_auto_init = true;
}
}
}
if (use_depth != DEPTH_UNUSED) {
quit = true;
}
}
if (learn_position) {
std::vector<cv::KeyPoint> trainKeyPoints;
keypoint.
detect(I_gray, trainKeyPoints);
std::vector<vpPolygon> polygons;
std::vector<std::vector<vpPoint> > roisPt;
std::pair<std::vector<vpPolygon>, std::vector<std::vector<vpPoint> > > pair =
tracker.getPolygonFaces();
polygons = pair.first;
roisPt = pair.second;
std::vector<cv::Point3f> points3f;
keypoint.
buildReference(I_gray, trainKeyPoints, points3f,
true, learn_id++);
for (std::vector<cv::KeyPoint>::const_iterator it = trainKeyPoints.begin(); it != trainKeyPoints.end(); ++it) {
}
learn_position = false;
std::cout << "Data learned" << std::endl;
}
times_vec.push_back(loop_t);
}
if (learn) {
std::cout << "Save learning file: " << learning_data << std::endl;
}
}
std::cout <<
"Catch an exception: " <<
e.what() << std::endl;
}
#if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_11) && defined(VISP_HAVE_DISPLAY)
if (display1 != nullptr) {
delete display1;
}
if (display2 != nullptr) {
delete display2;
}
#endif
if (!times_vec.empty()) {
<< std::endl;
}
return EXIT_SUCCESS;
}
#elif defined(VISP_HAVE_OCCIPITAL_STRUCTURE)
int main()
{
std::cout << "Install OpenCV 3rd party, configure and build ViSP again to use this example" << std::endl;
return EXIT_SUCCESS;
}
#else
int main()
{
std::cout << "Install libStructure 3rd party, configure and build ViSP again to use this example" << std::endl;
return EXIT_SUCCESS;
}
#endif
Generic class defining intrinsic camera parameters.
static const vpColor none
static const vpColor yellow
Class that defines generic functionalities for display.
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 displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
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)
error that can be emitted by ViSP classes.
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpHomogeneousMatrix inverse() const
static void createDepthHistogram(const vpImage< uint16_t > &src_depth, vpImage< vpRGBa > &dest_rgba)
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Definition of the vpImage class member functions.
Class that allows keypoints 2D features detection (and descriptors extraction) and matching thanks to...
unsigned int buildReference(const vpImage< unsigned char > &I) VP_OVERRIDE
void setExtractor(const vpFeatureDescriptorType &extractorType)
void loadLearningData(const std::string &filename, bool binaryMode=false, bool append=false)
void detect(const vpImage< unsigned char > &I, std::vector< cv::KeyPoint > &keyPoints, const vpRect &rectangle=vpRect())
static void compute3DForPointsInPolygons(const vpHomogeneousMatrix &cMo, const vpCameraParameters &cam, std::vector< cv::KeyPoint > &candidates, const std::vector< vpPolygon > &polygons, const std::vector< std::vector< vpPoint > > &roisPt, std::vector< cv::Point3f > &points, cv::Mat *descriptors=nullptr)
void setMatcher(const std::string &matcherName)
void saveLearningData(const std::string &filename, bool binaryMode=false, bool saveTrainingImages=true)
unsigned int matchPoint(const vpImage< unsigned char > &I) VP_OVERRIDE
void setDetector(const vpFeatureDetectorType &detectorType)
cv::Ptr< cv::FeatureDetector > getDetector(const vpFeatureDetectorType &type) const
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)
Real-time 6D object pose tracking using its CAD model.
unsigned int getHeight(vpOccipitalStructureStream stream_type)
vpCameraParameters getCameraParameters(const vpOccipitalStructureStream stream_type, vpCameraParameters::vpCameraParametersProjType type=vpCameraParameters::perspectiveProjWithoutDistortion)
void acquire(vpImage< unsigned char > &gray, bool undistorted=false, double *ts=nullptr)
unsigned int getWidth(vpOccipitalStructureStream stream_type)
vpHomogeneousMatrix getTransform(const vpOccipitalStructureStream from, const vpOccipitalStructureStream to)
bool open(const ST::CaptureSessionSettings &settings)
std::shared_ptr< vpDisplay > createDisplay()
Return a smart pointer vpDisplay specialization if a GUI library is available or nullptr otherwise.
vpDisplay * allocateDisplay()
Return a newly allocated vpDisplay specialization if a GUI library is available or nullptr otherwise.
VISP_EXPORT double measureTimeMs()