43#include <visp3/core/vpConfig.h>
45#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO) && \
46 (((VISP_HAVE_OPENCV_VERSION < 0x050000) && defined(HAVE_OPENCV_CALIB3D) && defined(HAVE_OPENCV_FEATURES2D)) || \
47 ((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_3D) && defined(HAVE_OPENCV_FEATURES)))
49#include <visp3/core/vpException.h>
50#include <visp3/core/vpImage.h>
51#include <visp3/core/vpIoTools.h>
52#include <visp3/io/vpImageIo.h>
53#include <visp3/io/vpParseArgv.h>
54#include <visp3/vision/vpKeyPoint.h>
57#define GETOPTARGS "cdo:h"
59#ifdef ENABLE_VISP_NAMESPACE
64void usage(
const char *name,
const char *badparam,
const std::string &opath,
const std::string &user);
65bool getOptions(
int argc,
const char **argv, std::string &opath,
const std::string &user);
66bool compareKeyPoints(
const std::vector<cv::KeyPoint> &keypoints1,
const std::vector<cv::KeyPoint> &keypoints2);
67bool compareDescriptors(
const cv::Mat &descriptors1,
const cv::Mat &descriptors2);
75void usage(
const char *name,
const char *badparam,
const std::string &opath,
const std::string &user)
78Test save / load learning files for vpKeyPoint class.\n\
87 -o <output image path> %s\n\
88 Set image output path.\n\
89 From this directory, creates the \"%s\"\n\
90 subdirectory depending on the username, where \n\
91 learning files will be written.\n\
95 opath.c_str(), user.c_str());
98 fprintf(stdout,
"\nERROR: Bad parameter [%s]\n", badparam);
110bool getOptions(
int argc,
const char **argv, std::string &opath,
const std::string &user)
125 usage(argv[0],
nullptr, opath, user);
129 usage(argv[0], optarg_, opath, user);
135 if ((c == 1) || (c == -1)) {
137 usage(argv[0],
nullptr, opath, user);
138 std::cerr <<
"ERROR: " << std::endl;
139 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
154bool compareKeyPoints(
const std::vector<cv::KeyPoint> &keypoints1,
const std::vector<cv::KeyPoint> &keypoints2)
156 if (keypoints1.size() != keypoints2.size()) {
160 for (
size_t cpt = 0; cpt < keypoints1.size(); cpt++) {
161 if (!
vpMath::equal(keypoints1[cpt].angle, keypoints2[cpt].angle, std::numeric_limits<float>::epsilon())) {
162 std::cerr << std::fixed << std::setprecision(9) <<
"keypoints1[cpt].angle=" << keypoints1[cpt].angle
163 <<
" ; keypoints2[cpt].angle=" << keypoints2[cpt].angle << std::endl;
167 if (keypoints1[cpt].class_id != keypoints2[cpt].class_id) {
168 std::cerr <<
"keypoints1[cpt].class_id=" << keypoints1[cpt].class_id
169 <<
" ; keypoints2[cpt].class_id=" << keypoints2[cpt].class_id << std::endl;
173 if (keypoints1[cpt].octave != keypoints2[cpt].octave) {
174 std::cerr <<
"keypoints1[cpt].octave=" << keypoints1[cpt].octave
175 <<
" ; keypoints2[cpt].octave=" << keypoints2[cpt].octave << std::endl;
179 if (!
vpMath::equal(keypoints1[cpt].pt.x, keypoints2[cpt].pt.x, std::numeric_limits<float>::epsilon())) {
180 std::cerr << std::fixed << std::setprecision(9) <<
"keypoints1[cpt].pt.x=" << keypoints1[cpt].pt.x
181 <<
" ; keypoints2[cpt].pt.x=" << keypoints2[cpt].pt.x << std::endl;
185 if (!
vpMath::equal(keypoints1[cpt].pt.y, keypoints2[cpt].pt.y, std::numeric_limits<float>::epsilon())) {
186 std::cerr << std::fixed << std::setprecision(9) <<
"keypoints1[cpt].pt.y=" << keypoints1[cpt].pt.y
187 <<
" ; keypoints2[cpt].pt.y=" << keypoints2[cpt].pt.y << std::endl;
191 if (!
vpMath::equal(keypoints1[cpt].response, keypoints2[cpt].response, std::numeric_limits<float>::epsilon())) {
192 std::cerr << std::fixed << std::setprecision(9) <<
"keypoints1[cpt].response=" << keypoints1[cpt].response
193 <<
" ; keypoints2[cpt].response=" << keypoints2[cpt].response << std::endl;
197 if (!
vpMath::equal(keypoints1[cpt].size, keypoints2[cpt].size, std::numeric_limits<float>::epsilon())) {
198 std::cerr << std::fixed << std::setprecision(9) <<
"keypoints1[cpt].size=" << keypoints1[cpt].size
199 <<
" ; keypoints2[cpt].size=" << keypoints2[cpt].size << std::endl;
215bool compareDescriptors(
const cv::Mat &descriptors1,
const cv::Mat &descriptors2)
217 if (descriptors1.rows != descriptors2.rows || descriptors1.cols != descriptors2.cols ||
218 descriptors1.type() != descriptors2.type()) {
222 for (
int i = 0;
i < descriptors1.rows;
i++) {
223 for (
int j = 0;
j < descriptors1.cols;
j++) {
224 switch (descriptors1.type()) {
226 if (descriptors1.at<
unsigned char>(i, j) != descriptors2.at<
unsigned char>(i, j)) {
227 std::cerr <<
"descriptors1.at<unsigned char>(i,j)=" << descriptors1.at<
unsigned char>(
i,
j)
228 <<
" ; descriptors2.at<unsigned char>(i,j)=" << descriptors2.at<
unsigned char>(i, j) << std::endl;
234 if (descriptors1.at<
char>(i, j) != descriptors2.at<
char>(i, j)) {
235 std::cerr <<
"descriptors1.at<char>(i,j)=" << descriptors1.at<
char>(
i,
j)
236 <<
" ; descriptors2.at<char>(i,j)=" << descriptors2.at<
char>(i, j) << std::endl;
242 if (descriptors1.at<
unsigned short>(i, j) != descriptors2.at<
unsigned short>(i, j)) {
243 std::cerr <<
"descriptors1.at<unsigned short>(i,j)=" << descriptors1.at<
unsigned short>(
i,
j)
244 <<
" ; descriptors2.at<unsigned short>(i,j)=" << descriptors2.at<
unsigned short>(i, j) << std::endl;
250 if (descriptors1.at<
short>(i, j) != descriptors2.at<
short>(i, j)) {
251 std::cerr <<
"descriptors1.at<short>(i,j)=" << descriptors1.at<
short>(
i,
j)
252 <<
" ; descriptors2.at<short>(i,j)=" << descriptors2.at<
short>(i, j) << std::endl;
258 if (descriptors1.at<
int>(i, j) != descriptors2.at<
int>(i, j)) {
259 std::cerr <<
"descriptors1.at<int>(i,j)=" << descriptors1.at<
int>(
i,
j)
260 <<
" ; descriptors2.at<int>(i,j)=" << descriptors2.at<
int>(i, j) << std::endl;
266 if (!
vpMath::equal(descriptors1.at<
float>(i, j), descriptors2.at<
float>(i, j),
267 std::numeric_limits<float>::epsilon())) {
268 std::cerr << std::fixed << std::setprecision(9)
269 <<
"descriptors1.at<float>(i,j)=" << descriptors1.at<
float>(
i,
j)
270 <<
" ; descriptors2.at<float>(i,j)=" << descriptors2.at<
float>(i, j) << std::endl;
276 if (!
vpMath::equal(descriptors1.at<
double>(i, j), descriptors2.at<
double>(i, j),
277 std::numeric_limits<double>::epsilon())) {
278 std::cerr << std::fixed << std::setprecision(17)
279 <<
"descriptors1.at<double>(i,j)=" << descriptors1.at<
double>(
i,
j)
280 <<
" ; descriptors2.at<double>(i,j)=" << descriptors2.at<
double>(i, j) << std::endl;
295template <
typename Type>
void run_test(
const std::string &env_ipath,
const std::string &opath,
vpImage<Type> &I)
309 std::cout <<
"Detect ORB keypoints" << std::endl;
310 std::string keypointName =
"ORB";
316 std::vector<cv::KeyPoint> trainKeyPoints;
319 if (trainKeyPoints.empty() || trainDescriptors.empty() ||
static_cast<int>(trainKeyPoints.size()) != trainDescriptors.rows) {
322 "computing descriptors !");
329 std::cout <<
"Save keypoints in binary with image in: " <<
filename << std::endl;
334 std::stringstream ss;
335 ss <<
"Problem when saving file=" <<
filename;
341 std::cout <<
"Read keypoints from file: " <<
filename << std::endl;
344 std::vector<cv::KeyPoint> trainKeyPoints_read;
348 std::cout <<
"Compare keypoints" << std::endl;
349 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
351 "in binary with train images saved !");
354 std::cout <<
"Compare descriptors" << std::endl;
355 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
357 "learning file saved in "
358 "binary with train images saved !");
365 std::cout <<
"Save keypoints in binary without image in: " <<
filename << std::endl;
370 std::stringstream ss;
371 ss <<
"Problem when saving file=" <<
filename;
377 std::cout <<
"Read keypoints from file: " <<
filename << std::endl;
379 trainKeyPoints_read.clear();
383 std::cout <<
"Compare keypoints" << std::endl;
384 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
386 "binary without train images !");
389 std::cout <<
"Compare descriptors" << std::endl;
390 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
392 "learning file saved in "
393 "binary without train images !");
396#if defined(VISP_HAVE_PUGIXML)
401 std::cout <<
"Save keypoints in xml with image in: " <<
filename << std::endl;
406 std::stringstream ss;
407 ss <<
"Problem when saving file=" <<
filename;
413 std::cout <<
"Read keypoints from file: " <<
filename << std::endl;
415 trainKeyPoints_read.clear();
419 std::cout <<
"Compare keypoints" << std::endl;
420 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
422 "xml with train images saved !");
425 std::cout <<
"Compare descriptors" << std::endl;
426 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
428 "learning file saved in "
429 "xml with train images saved !");
436 std::cout <<
"Save keypoints in xml without image in: " <<
filename << std::endl;
441 std::stringstream ss;
442 ss <<
"Problem when saving file=" <<
filename;
449 trainKeyPoints_read.clear();
450 std::cout <<
"Read keypoints from file: " <<
filename << std::endl;
454 std::cout <<
"Compare keypoints" << std::endl;
455 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
457 "xml without train images saved !");
460 std::cout <<
"Compare descriptors" << std::endl;
461 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
463 "learning file saved in "
464 "xml without train images saved !");
467 std::cout <<
"Saving / loading learning files with binary descriptor are ok !" << std::endl;
471#if defined(VISP_HAVE_OPENCV) && \
472 (((VISP_HAVE_OPENCV_VERSION < 0x050000) && defined(HAVE_OPENCV_XFEATURES2D)) || \
473 ((VISP_HAVE_OPENCV_VERSION >= 0x050000) && defined(HAVE_OPENCV_FEATURES)))
475#if (VISP_HAVE_OPENCV_VERSION != 0x040504) && (VISP_HAVE_OPENCV_VERSION != 0x040505) && \
476 (VISP_HAVE_OPENCV_VERSION != 0x040600) && (VISP_HAVE_OPENCV_VERSION != 0x040700) && \
477 (VISP_HAVE_OPENCV_VERSION != 0x040900) && (VISP_HAVE_OPENCV_VERSION != 0x040A00) && \
478 (defined(__APPLE__) && defined(__MACH__))
482 std::string keypointName =
"SIFT";
483 std::cout <<
"Use " << keypointName <<
" keypoints" << std::endl;
487 std::cout <<
"Detect keypoints" << std::endl;
490 std::vector<cv::KeyPoint> trainKeyPoints;
492 std::cout <<
"Get descriptors" << std::endl;
494 if (trainKeyPoints.empty() || trainDescriptors.empty() ||
static_cast<int>(trainKeyPoints.size()) != trainDescriptors.rows) {
496 "computing descriptors (SIFT) !");
503 std::cout <<
"Save keypoints in binary with image in: " <<
filename << std::endl;
508 std::stringstream ss;
509 ss <<
"Problem when saving file=" <<
filename;
515 std::cout <<
"Load keypoints from: " <<
filename << std::endl;
517 std::vector<cv::KeyPoint> trainKeyPoints_read;
521 std::cout <<
"Compare keypoints" << std::endl;
522 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
524 "binary with train images saved !");
527 std::cout <<
"Compare descriptors" << std::endl;
528 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
530 "learning file saved in "
531 "binary with train images saved !");
538 std::cout <<
"Save keypoints in binary without image in: " <<
filename << std::endl;
543 std::stringstream ss;
544 ss <<
"Problem when saving file=" <<
filename;
550 std::cout <<
"Load keypoints from: " <<
filename << std::endl;
552 trainKeyPoints_read.clear();
556 std::cout <<
"Compare keypoints" << std::endl;
557 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
559 "binary without train images saved !");
562 std::cout <<
"Compare descriptors" << std::endl;
563 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
565 "learning file saved in "
566 "binary without train images saved !");
569#if defined(VISP_HAVE_PUGIXML)
578 std::stringstream ss;
579 ss <<
"Problem when saving file=" <<
filename;
586 trainKeyPoints_read.clear();
590 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
592 "xml with train images saved !");
595 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
597 "learning file saved in "
598 "xml with train images saved !");
609 std::stringstream ss;
610 ss <<
"Problem when saving file=" <<
filename;
617 trainKeyPoints_read.clear();
621 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
623 "xml without train images saved !");
626 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
628 "learning file saved in "
629 "xml without train images saved !");
632 std::cout <<
"Saving / loading learning files with floating point descriptor are ok !" << std::endl;
637 keypointName =
"ORB";
638 std::cout <<
"Use " << keypointName <<
" as keypoints" << std::endl;
643 std::cout << keypointName <<
" keypoints are detected" << std::endl;
646 keypoint_reset.
reset();
648 keypointName =
"SIFT";
649 std::cout <<
"Use " << keypointName <<
" as keypoints" << std::endl;
654 std::cout << keypointName <<
" keypoints are detected" << std::endl;
656 std::vector<cv::KeyPoint> trainKeyPoints_reset;
658 std::cout <<
"Get descriptors" << std::endl;
662 std::cout <<
"Compare keypoints" << std::endl;
663 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_reset)) {
667 std::cout <<
"Compare descriptors" << std::endl;
668 if (!compareDescriptors(trainDescriptors, trainDescriptors_reset)) {
672 std::cout <<
"vpKeyPoint::reset() is ok with trainKeyPoints and trainDescriptors !" << std::endl;
678int main(
int argc,
const char **argv)
681 std::string env_ipath;
682 std::string opt_opath;
683 std::string username;
690 if (env_ipath.empty()) {
696 opt_opath =
"C:/temp";
705 if (getOptions(argc, argv, opt_opath, username) ==
false) {
710 if (!opt_opath.empty()) {
720 std::cout <<
"-- Test on gray level images" << std::endl;
721 run_test(env_ipath, opath, I);
727 std::cout <<
"-- Test on color images" << std::endl;
728 run_test(env_ipath, opath, I);
733 std::cerr <<
e.what() << std::endl;
737 std::cout <<
"Saving / loading learning files are ok !" << std::endl;
738 std::cout <<
"testKeyPoint-7 is ok !" << std::endl;
744 std::cerr <<
"You need OpenCV library." << std::endl;
error that can be emitted by ViSP classes.
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition of the vpImage class member functions.
Class that allows keypoints 2D features detection (and descriptors extraction) and matching thanks to...
void getTrainKeyPoints(std::vector< cv::KeyPoint > &keyPoints) const
unsigned int buildReference(const vpImage< unsigned char > &I) VP_OVERRIDE
cv::Mat getTrainDescriptors() const
void setExtractor(const vpFeatureDescriptorType &extractorType)
void loadLearningData(const std::string &filename, bool binaryMode=false, bool append=false)
void saveLearningData(const std::string &filename, bool binaryMode=false, bool saveTrainingImages=true)
void setDetector(const vpFeatureDetectorType &detectorType)
static bool equal(double x, double y, double threshold=0.001)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)