43 #include <visp3/core/vpConfig.h>
45 #if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_FEATURES2D) && defined(HAVE_OPENCV_VIDEO)
47 #include <visp3/core/vpException.h>
48 #include <visp3/core/vpImage.h>
49 #include <visp3/core/vpIoTools.h>
50 #include <visp3/io/vpImageIo.h>
51 #include <visp3/io/vpParseArgv.h>
52 #include <visp3/vision/vpKeyPoint.h>
55 #define GETOPTARGS "cdo:h"
57 #ifdef ENABLE_VISP_NAMESPACE
69 void usage(
const char *name,
const char *badparam,
const std::string &opath,
const std::string &user)
72 Test save / load learning files for vpKeyPoint class.\n\
81 -o <output image path> %s\n\
82 Set image output path.\n\
83 From this directory, creates the \"%s\"\n\
84 subdirectory depending on the username, where \n\
85 learning files will be written.\n\
89 opath.c_str(), user.c_str());
92 fprintf(stdout,
"\nERROR: Bad parameter [%s]\n", badparam);
106 bool getOptions(
int argc,
const char **argv, std::string &opath,
const std::string &user)
121 usage(argv[0],
nullptr, opath, user);
126 usage(argv[0], optarg_, opath, user);
134 if ((c == 1) || (c == -1)) {
136 usage(argv[0],
nullptr, opath, user);
137 std::cerr <<
"ERROR: " << std::endl;
138 std::cerr <<
" Bad argument " << optarg_ << std::endl << std::endl;
153 bool compareKeyPoints(
const std::vector<cv::KeyPoint> &keypoints1,
const std::vector<cv::KeyPoint> &keypoints2)
155 if (keypoints1.size() != keypoints2.size()) {
159 for (
size_t cpt = 0; cpt < keypoints1.size(); cpt++) {
160 if (!
vpMath::equal(keypoints1[cpt].angle, keypoints2[cpt].angle, std::numeric_limits<float>::epsilon())) {
161 std::cerr << std::fixed << std::setprecision(9) <<
"keypoints1[cpt].angle=" << keypoints1[cpt].angle
162 <<
" ; keypoints2[cpt].angle=" << keypoints2[cpt].angle << std::endl;
166 if (keypoints1[cpt].class_id != keypoints2[cpt].class_id) {
167 std::cerr <<
"keypoints1[cpt].class_id=" << keypoints1[cpt].class_id
168 <<
" ; keypoints2[cpt].class_id=" << keypoints2[cpt].class_id << std::endl;
172 if (keypoints1[cpt].octave != keypoints2[cpt].octave) {
173 std::cerr <<
"keypoints1[cpt].octave=" << keypoints1[cpt].octave
174 <<
" ; keypoints2[cpt].octave=" << keypoints2[cpt].octave << std::endl;
178 if (!
vpMath::equal(keypoints1[cpt].pt.x, keypoints2[cpt].pt.x, std::numeric_limits<float>::epsilon())) {
179 std::cerr << std::fixed << std::setprecision(9) <<
"keypoints1[cpt].pt.x=" << keypoints1[cpt].pt.x
180 <<
" ; keypoints2[cpt].pt.x=" << keypoints2[cpt].pt.x << std::endl;
184 if (!
vpMath::equal(keypoints1[cpt].pt.y, keypoints2[cpt].pt.y, std::numeric_limits<float>::epsilon())) {
185 std::cerr << std::fixed << std::setprecision(9) <<
"keypoints1[cpt].pt.y=" << keypoints1[cpt].pt.y
186 <<
" ; keypoints2[cpt].pt.y=" << keypoints2[cpt].pt.y << std::endl;
190 if (!
vpMath::equal(keypoints1[cpt].response, keypoints2[cpt].response, std::numeric_limits<float>::epsilon())) {
191 std::cerr << std::fixed << std::setprecision(9) <<
"keypoints1[cpt].response=" << keypoints1[cpt].response
192 <<
" ; keypoints2[cpt].response=" << keypoints2[cpt].response << std::endl;
196 if (!
vpMath::equal(keypoints1[cpt].size, keypoints2[cpt].size, std::numeric_limits<float>::epsilon())) {
197 std::cerr << std::fixed << std::setprecision(9) <<
"keypoints1[cpt].size=" << keypoints1[cpt].size
198 <<
" ; keypoints2[cpt].size=" << keypoints2[cpt].size << std::endl;
214 bool compareDescriptors(
const cv::Mat &descriptors1,
const cv::Mat &descriptors2)
216 if (descriptors1.rows != descriptors2.rows || descriptors1.cols != descriptors2.cols ||
217 descriptors1.type() != descriptors2.type()) {
221 for (
int i = 0; i < descriptors1.rows; i++) {
222 for (
int j = 0; j < descriptors1.cols; j++) {
223 switch (descriptors1.type()) {
225 if (descriptors1.at<
unsigned char>(i, j) != descriptors2.at<
unsigned char>(i, j)) {
226 std::cerr <<
"descriptors1.at<unsigned char>(i,j)=" << descriptors1.at<
unsigned char>(i, j)
227 <<
" ; descriptors2.at<unsigned char>(i,j)=" << descriptors2.at<
unsigned char>(i, j) << std::endl;
233 if (descriptors1.at<
char>(i, j) != descriptors2.at<
char>(i, j)) {
234 std::cerr <<
"descriptors1.at<char>(i,j)=" << descriptors1.at<
char>(i, j)
235 <<
" ; descriptors2.at<char>(i,j)=" << descriptors2.at<
char>(i, j) << std::endl;
241 if (descriptors1.at<
unsigned short>(i, j) != descriptors2.at<
unsigned short>(i, j)) {
242 std::cerr <<
"descriptors1.at<unsigned short>(i,j)=" << descriptors1.at<
unsigned short>(i, j)
243 <<
" ; descriptors2.at<unsigned short>(i,j)=" << descriptors2.at<
unsigned short>(i, j) << std::endl;
249 if (descriptors1.at<
short>(i, j) != descriptors2.at<
short>(i, j)) {
250 std::cerr <<
"descriptors1.at<short>(i,j)=" << descriptors1.at<
short>(i, j)
251 <<
" ; descriptors2.at<short>(i,j)=" << descriptors2.at<
short>(i, j) << std::endl;
257 if (descriptors1.at<
int>(i, j) != descriptors2.at<
int>(i, j)) {
258 std::cerr <<
"descriptors1.at<int>(i,j)=" << descriptors1.at<
int>(i, j)
259 <<
" ; descriptors2.at<int>(i,j)=" << descriptors2.at<
int>(i, j) << std::endl;
265 if (!
vpMath::equal(descriptors1.at<
float>(i, j), descriptors2.at<
float>(i, j),
266 std::numeric_limits<float>::epsilon())) {
267 std::cerr << std::fixed << std::setprecision(9)
268 <<
"descriptors1.at<float>(i,j)=" << descriptors1.at<
float>(i, j)
269 <<
" ; descriptors2.at<float>(i,j)=" << descriptors2.at<
float>(i, j) << std::endl;
275 if (!
vpMath::equal(descriptors1.at<
double>(i, j), descriptors2.at<
double>(i, j),
276 std::numeric_limits<double>::epsilon())) {
277 std::cerr << std::fixed << std::setprecision(17)
278 <<
"descriptors1.at<double>(i,j)=" << descriptors1.at<
double>(i, j)
279 <<
" ; descriptors2.at<double>(i,j)=" << descriptors2.at<
double>(i, j) << std::endl;
294 template <
typename Type>
void run_test(
const std::string &env_ipath,
const std::string &opath,
vpImage<Type> &I)
296 std::string filename;
308 std::cout <<
"Detect ORB keypoints" << std::endl;
309 std::string keypointName =
"ORB";
315 std::vector<cv::KeyPoint> trainKeyPoints;
318 if (trainKeyPoints.empty() || trainDescriptors.empty() || (
int)trainKeyPoints.size() != trainDescriptors.rows) {
321 "computing descriptors !");
328 std::cout <<
"Save keypoints in binary with image in: " << filename << std::endl;
333 std::stringstream ss;
334 ss <<
"Problem when saving file=" << filename;
340 std::cout <<
"Read keypoints from file: " << filename << std::endl;
343 std::vector<cv::KeyPoint> trainKeyPoints_read;
347 std::cout <<
"Compare keypoints" << std::endl;
348 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
350 "in binary with train images saved !");
353 std::cout <<
"Compare descriptors" << std::endl;
354 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
356 "learning file saved in "
357 "binary with train images saved !");
364 std::cout <<
"Save keypoints in binary without image in: " << filename << std::endl;
369 std::stringstream ss;
370 ss <<
"Problem when saving file=" << filename;
376 std::cout <<
"Read keypoints from file: " << filename << std::endl;
378 trainKeyPoints_read.clear();
382 std::cout <<
"Compare keypoints" << std::endl;
383 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
385 "binary without train images !");
388 std::cout <<
"Compare descriptors" << std::endl;
389 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
391 "learning file saved in "
392 "binary without train images !");
395 #if defined(VISP_HAVE_PUGIXML)
400 std::cout <<
"Save keypoints in xml with image in: " << filename << std::endl;
405 std::stringstream ss;
406 ss <<
"Problem when saving file=" << filename;
412 std::cout <<
"Read keypoints from file: " << filename << std::endl;
414 trainKeyPoints_read.clear();
418 std::cout <<
"Compare keypoints" << std::endl;
419 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
421 "xml with train images saved !");
424 std::cout <<
"Compare descriptors" << std::endl;
425 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
427 "learning file saved in "
428 "xml with train images saved !");
435 std::cout <<
"Save keypoints in xml without image in: " << filename << std::endl;
440 std::stringstream ss;
441 ss <<
"Problem when saving file=" << filename;
448 trainKeyPoints_read.clear();
449 std::cout <<
"Read keypoints from file: " << filename << std::endl;
453 std::cout <<
"Compare keypoints" << std::endl;
454 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
456 "xml without train images saved !");
459 std::cout <<
"Compare descriptors" << std::endl;
460 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
462 "learning file saved in "
463 "xml without train images saved !");
466 std::cout <<
"Saving / loading learning files with binary descriptor are ok !" << std::endl;
470 #if defined(VISP_HAVE_OPENCV_NONFREE) || \
471 ((VISP_HAVE_OPENCV_VERSION >= 0x030000) && defined(VISP_HAVE_OPENCV_XFEATURES2D) || \
472 (VISP_HAVE_OPENCV_VERSION >= 0x030411 && CV_MAJOR_VERSION < 4) || (VISP_HAVE_OPENCV_VERSION >= 0x040400))
474 #if (VISP_HAVE_OPENCV_VERSION != 0x040504) && (VISP_HAVE_OPENCV_VERSION != 0x040505) && \
475 (VISP_HAVE_OPENCV_VERSION != 0x040600) && (VISP_HAVE_OPENCV_VERSION != 0x040700) && \
476 (VISP_HAVE_OPENCV_VERSION != 0x040900) && (VISP_HAVE_OPENCV_VERSION != 0x040A00) && \
477 (defined(__APPLE__) && defined(__MACH__))
481 std::string keypointName =
"SIFT";
482 std::cout <<
"Use " << keypointName <<
" keypoints" << std::endl;
486 std::cout <<
"Detect keypoints" << std::endl;
489 std::vector<cv::KeyPoint> trainKeyPoints;
491 std::cout <<
"Get descriptors" << std::endl;
493 if (trainKeyPoints.empty() || trainDescriptors.empty() || (
int)trainKeyPoints.size() != trainDescriptors.rows) {
495 "computing descriptors (SIFT) !");
502 std::cout <<
"Save keypoints in binary with image in: " << filename << std::endl;
507 std::stringstream ss;
508 ss <<
"Problem when saving file=" << filename;
514 std::cout <<
"Load keypoints from: " << filename << std::endl;
516 std::vector<cv::KeyPoint> trainKeyPoints_read;
520 std::cout <<
"Compare keypoints" << std::endl;
521 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
523 "binary with train images saved !");
526 std::cout <<
"Compare descriptors" << std::endl;
527 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
529 "learning file saved in "
530 "binary with train images saved !");
537 std::cout <<
"Save keypoints in binary without image in: " << filename << std::endl;
542 std::stringstream ss;
543 ss <<
"Problem when saving file=" << filename;
549 std::cout <<
"Load keypoints from: " << filename << std::endl;
551 trainKeyPoints_read.clear();
555 std::cout <<
"Compare keypoints" << std::endl;
556 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
558 "binary without train images saved !");
561 std::cout <<
"Compare descriptors" << std::endl;
562 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
564 "learning file saved in "
565 "binary without train images saved !");
568 #if defined(VISP_HAVE_PUGIXML)
577 std::stringstream ss;
578 ss <<
"Problem when saving file=" << filename;
585 trainKeyPoints_read.clear();
589 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
591 "xml with train images saved !");
594 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
596 "learning file saved in "
597 "xml with train images saved !");
608 std::stringstream ss;
609 ss <<
"Problem when saving file=" << filename;
616 trainKeyPoints_read.clear();
620 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_read)) {
622 "xml without train images saved !");
625 if (!compareDescriptors(trainDescriptors, trainDescriptors_read)) {
627 "learning file saved in "
628 "xml without train images saved !");
631 std::cout <<
"Saving / loading learning files with floating point descriptor are ok !" << std::endl;
636 keypointName =
"ORB";
637 std::cout <<
"Use " << keypointName <<
" as keypoints" << std::endl;
642 std::cout << keypointName <<
" keypoints are detected" << std::endl;
645 keypoint_reset.
reset();
647 keypointName =
"SIFT";
648 std::cout <<
"Use " << keypointName <<
" as keypoints" << std::endl;
653 std::cout << keypointName <<
" keypoints are detected" << std::endl;
655 std::vector<cv::KeyPoint> trainKeyPoints_reset;
657 std::cout <<
"Get descriptors" << std::endl;
661 std::cout <<
"Compare keypoints" << std::endl;
662 if (!compareKeyPoints(trainKeyPoints, trainKeyPoints_reset)) {
666 std::cout <<
"Compare descriptors" << std::endl;
667 if (!compareDescriptors(trainDescriptors, trainDescriptors_reset)) {
671 std::cout <<
"vpKeyPoint::reset() is ok with trainKeyPoints and trainDescriptors !" << std::endl;
677 int main(
int argc,
const char **argv)
680 std::string env_ipath;
681 std::string opt_opath;
682 std::string username;
689 if (env_ipath.empty()) {
695 opt_opath =
"C:/temp";
704 if (getOptions(argc, argv, opt_opath, username) ==
false) {
709 if (!opt_opath.empty()) {
719 std::cout <<
"-- Test on gray level images" << std::endl;
720 run_test(env_ipath, opath, I);
726 std::cout <<
"-- Test on color images" << std::endl;
727 run_test(env_ipath, opath, I);
732 std::cerr << e.
what() << std::endl;
736 std::cout <<
"Saving / loading learning files are ok !" << std::endl;
737 std::cout <<
"testKeyPoint-7 is ok !" << std::endl;
743 std::cerr <<
"You need OpenCV library." << std::endl;
error that can be emitted by ViSP classes.
const char * what() const
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 detection (and descriptors extraction) and matching thanks to OpenCV libr...
void getTrainKeyPoints(std::vector< cv::KeyPoint > &keyPoints) const
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)
unsigned int buildReference(const vpImage< unsigned char > &I)
static bool equal(double x, double y, double threshold=0.001)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)