Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
testKeyPoint-3.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Test keypoint matching with mostly OpenCV functions calls
32 * to detect potential memory leaks in testKeyPoint.cpp.
33 */
34
41
42#include <iostream>
43
44#include <visp3/core/vpConfig.h>
45
46#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGPROC) && (defined(HAVE_OPENCV_FEATURES2D) || defined(HAVE_OPENCV_FEATURES))
47
48#if defined(HAVE_OPENCV_FEATURES)
49#include <opencv2/features.hpp>
50#endif
51
52#if defined(HAVE_OPENCV_FEATURES2D)
53#include <opencv2/features2d/features2d.hpp>
54#endif
55
56#include <visp3/core/vpImage.h>
57#include <visp3/core/vpIoTools.h>
58#include <visp3/gui/vpDisplayFactory.h>
59#include <visp3/io/vpImageIo.h>
60#include <visp3/io/vpParseArgv.h>
61#include <visp3/io/vpVideoReader.h>
62
63// List of allowed command line options
64#define GETOPTARGS "cdh"
65
66#ifdef ENABLE_VISP_NAMESPACE
67using namespace VISP_NAMESPACE_NAME;
68#endif
69
70void usage(const char *name, const char *badparam);
71bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display);
72
80void usage(const char *name, const char *badparam)
81{
82 fprintf(stdout, "\n\
83Test keypoints matching.\n\
84\n\
85SYNOPSIS\n\
86 %s [-c] [-d] [-h]\n",
87 name);
88
89 fprintf(stdout, "\n\
90OPTIONS: \n\
91\n\
92 -c\n\
93 Disable the mouse click. Useful to automate the \n\
94 execution of this program without human intervention.\n\
95\n\
96 -d \n\
97 Turn off the display.\n\
98\n\
99 -h\n\
100 Print the help.\n");
101
102 if (badparam)
103 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
104}
105
117bool getOptions(int argc, const char **argv, bool &click_allowed, bool &display)
118{
119 const char *optarg_;
120 int c;
121 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
122
123 switch (c) {
124 case 'c':
125 click_allowed = false;
126 break;
127 case 'd':
128 display = false;
129 break;
130 case 'h':
131 usage(argv[0], nullptr);
132 return false;
133
134 default:
135 usage(argv[0], optarg_);
136 return false;
137 }
138 }
139
140 if ((c == 1) || (c == -1)) {
141 // standalone param or error
142 usage(argv[0], nullptr);
143 std::cerr << "ERROR: " << std::endl;
144 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
145 return false;
146 }
147
148 return true;
149}
150
151template <typename Type>
152void run_test(const std::string &env_ipath, bool opt_click_allowed, bool opt_display, vpImage<Type> &Iref,
153 vpImage<Type> &Icur, vpImage<Type> &Imatch)
154{
155#if defined(VISP_HAVE_DATASET)
156#if VISP_HAVE_DATASET_VERSION >= 0x030600
157 std::string ext("png");
158#else
159 std::string ext("pgm");
160#endif
161#else
162 // We suppose that the user will download a recent dataset
163 std::string ext("png");
164#endif
165 // Set the path location of the image sequence
166 std::string dirname = vpIoTools::createFilePath(env_ipath, "mbt/cube");
167
168 // Build the name of the image files
169 std::string filenameRef = vpIoTools::createFilePath(dirname, "image0000." + ext);
170 vpImageIo::read(Iref, filenameRef);
171 std::string filenameCur = vpIoTools::createFilePath(dirname, "image%04d." + ext);
172
173 // Init keypoints
174 cv::Ptr<cv::FeatureDetector> detector;
175 cv::Ptr<cv::DescriptorExtractor> extractor;
176 cv::Ptr<cv::DescriptorMatcher> matcher;
177
178#if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x030000)
179 detector = cv::ORB::create();
180 extractor = cv::ORB::create();
181#elif defined(VISP_HAVE_OPENCV)
182 detector = cv::FeatureDetector::create("ORB");
183 extractor = cv::DescriptorExtractor::create("ORB");
184#endif
185 matcher = cv::DescriptorMatcher::create("BruteForce-Hamming");
186
187 std::vector<cv::KeyPoint> trainKeyPoints;
188 cv::Mat matImg, trainDescriptors;
189 vpImageConvert::convert(Iref, matImg);
190 detector->detect(matImg, trainKeyPoints);
191 extractor->compute(matImg, trainKeyPoints, trainDescriptors);
192
194 g.setFileName(filenameCur);
195 g.open(Icur);
196 g.acquire(Icur);
197
198 Imatch.resize(Icur.getHeight(), 2 * Icur.getWidth());
199 Imatch.insert(Iref, vpImagePoint(0, 0));
200
201 vpDisplay *display = nullptr;
202
203 if (opt_display) {
204#ifdef VISP_HAVE_DISPLAY
205 display = vpDisplayFactory::allocateDisplay(Imatch, 0, 0, "ORB keypoints matching");
206 display->setDownScalingFactor(vpDisplay::SCALE_AUTO);
207#else
208 std::cout << "No image viewer is available..." << std::endl;
209#endif
210 }
211
212 bool opt_click = false;
214 while (!g.end()) {
215 g.acquire(Icur);
216 Imatch.insert(Icur, vpImagePoint(0, Icur.getWidth()));
217
218 if (opt_display) {
219 vpDisplay::display(Imatch);
220 }
221
222 vpImageConvert::convert(Icur, matImg);
223 std::vector<cv::KeyPoint> queryKeyPoints;
224 detector->detect(matImg, queryKeyPoints);
225
226 cv::Mat queryDescriptors;
227 extractor->compute(matImg, queryKeyPoints, queryDescriptors);
228
229 std::vector<std::vector<cv::DMatch> > knn_matches;
230 std::vector<cv::DMatch> matches;
231 matcher->knnMatch(queryDescriptors, trainDescriptors, knn_matches, 2);
232 for (std::vector<std::vector<cv::DMatch> >::const_iterator it = knn_matches.begin(); it != knn_matches.end();
233 ++it) {
234 if (it->size() > 1) {
235 double ratio = (*it)[0].distance / (*it)[1].distance;
236 if (ratio < 0.85) {
237 matches.push_back((*it)[0]);
238 }
239 }
240 }
241
242 if (opt_display) {
243 for (std::vector<cv::DMatch>::const_iterator it = matches.begin(); it != matches.end(); ++it) {
244 vpImagePoint leftPt(trainKeyPoints[static_cast<size_t>(it->trainIdx)].pt.y, trainKeyPoints[static_cast<size_t>(it->trainIdx)].pt.x);
245 vpImagePoint rightPt(queryKeyPoints[static_cast<size_t>(it->queryIdx)].pt.y,
246 queryKeyPoints[static_cast<size_t>(it->queryIdx)].pt.x + Iref.getWidth());
247 vpDisplay::displayLine(Imatch, leftPt, rightPt, vpColor::green);
248 }
249
250 vpDisplay::flush(Imatch);
251 }
252
253 // Click requested to process next image
254 if (opt_click_allowed && opt_display) {
255 if (opt_click) {
256 vpDisplay::getClick(Imatch, button, true);
257 if (button == vpMouseButton::button3) {
258 opt_click = false;
259 }
260 }
261 else {
262 // Use right click to enable/disable step by step tracking
263 if (vpDisplay::getClick(Imatch, button, false)) {
264 if (button == vpMouseButton::button3) {
265 opt_click = true;
266 }
267 else if (button == vpMouseButton::button1) {
268 break;
269 }
270 }
271 }
272 }
273 }
274
275 if (display) {
276 delete display;
277 }
278}
279
280int main(int argc, const char **argv)
281{
282 try {
283 std::string env_ipath;
284 bool opt_click_allowed = true;
285 bool opt_display = true;
286
287 // Read the command line options
288 if (getOptions(argc, argv, opt_click_allowed, opt_display) == false) {
289 return EXIT_FAILURE;
290 }
291
292 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
293 // environment variable value
295
296 if (env_ipath.empty()) {
297 std::cerr << "Please set the VISP_INPUT_IMAGE_PATH environment "
298 "variable value."
299 << std::endl;
300 return EXIT_FAILURE;
301 }
302
303 {
304 vpImage<unsigned char> Iref, Icur, Imatch;
305
306 std::cout << "-- Test on gray level images" << std::endl;
307 run_test(env_ipath, opt_click_allowed, opt_display, Iref, Icur, Imatch);
308 }
309
310 {
311 vpImage<vpRGBa> Iref, Icur, Imatch;
312
313 std::cout << "-- Test on color images" << std::endl;
314 run_test(env_ipath, opt_click_allowed, opt_display, Iref, Icur, Imatch);
315 }
316
317 }
318 catch (const vpException &e) {
319 std::cerr << e.what() << std::endl;
320 return EXIT_FAILURE;
321 }
322
323 std::cout << "testKeyPoint-3 is ok !" << std::endl;
324 return EXIT_SUCCESS;
325}
326
327#else
328int main()
329{
330 std::cerr << "You need OpenCV library." << std::endl;
331
332 return EXIT_SUCCESS;
333}
334
335#endif
static const vpColor green
Definition vpColor.h:201
Class that defines generic functionalities for display.
Definition vpDisplay.h:171
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1, bool segment=true)
static void flush(const vpImage< unsigned char > &I)
error that can be emitted by ViSP classes.
Definition vpException.h:60
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
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.
Definition vpImage.h:131
unsigned int getWidth() const
Definition vpImage.h:242
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
Definition vpImage.h:544
void insert(const vpImage< Type > &src, const vpImagePoint &topLeft)
Definition vpImage.h:639
unsigned int getHeight() const
Definition vpImage.h:181
static std::string getViSPImagesDataPath()
static std::string createFilePath(const std::string &parent, const std::string &child)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Class that enables to manipulate easily a video file or a sequence of images. As it inherits from the...
void open(vpImage< vpRGBa > &I) VP_OVERRIDE
void setFileName(const std::string &filename)
void acquire(vpImage< vpRGBa > &I) VP_OVERRIDE
vpDisplay * allocateDisplay()
Return a newly allocated vpDisplay specialization if a GUI library is available or nullptr otherwise.