Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
fernClassifier.cpp
1/****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5 *
6 * This software is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 * See the file LICENSE.txt at the root directory of this source
11 * distribution for additional information about the GNU GPL.
12 *
13 * For using ViSP with software that can not be combined with the GNU
14 * GPL, please contact Inria about acquiring a ViSP Professional
15 * Edition License.
16 *
17 * See https://visp.inria.fr for more information.
18 *
19 * This software was developed at:
20 * Inria Rennes - Bretagne Atlantique
21 * Campus Universitaire de Beaulieu
22 * 35042 Rennes Cedex
23 * France
24 *
25 * If you have questions regarding the use of this file, please contact
26 * Inria at visp@inria.fr
27 *
28 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 *
31 * Description:
32 * Detection of points of interests and matching using the Ferns classifier.
33 *
34*****************************************************************************/
48#include <visp3/core/vpConfig.h>
49#include <visp3/core/vpDebug.h>
50
51#if ((defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)) && \
52 (VISP_HAVE_OPENCV_VERSION >= 0x020408) && (VISP_HAVE_OPENCV_VERSION < 0x030000))
53
54#include <iomanip>
55#include <iostream>
56#include <stdlib.h>
57#include <visp3/core/vpImage.h>
58#include <visp3/core/vpIoTools.h>
59#include <visp3/core/vpTime.h>
60#include <visp3/gui/vpDisplayGDI.h>
61#include <visp3/gui/vpDisplayGTK.h>
62#include <visp3/gui/vpDisplayX.h>
63#include <visp3/io/vpImageIo.h>
64#include <visp3/io/vpParseArgv.h>
65#include <visp3/vision/vpFernClassifier.h>
66#include <visp3/vision/vpHomography.h>
67
68#define GETOPTARGS "hlcdb:i:p"
69
78void usage(const char *name, const char *badparam)
79{
80#if VISP_HAVE_DATASET_VERSION >= 0x030600
81 std::string ext("png");
82#else
83 std::string ext("pgm");
84#endif
85 fprintf(stdout, "\n\
86Detection of points of interests and matching using the Ferns classifier. The \
87object needs first to be learned (-l option). This learning process will create\
88a file used to detect the object.\n\
89\n\
90SYNOPSIS\n\
91 %s [-l] [-h] [-b] [-c] [-d] [-p] [-i]\n",
92 name);
93
94 fprintf(stdout, "\n\
95OPTIONS: \n\
96 -l\n\
97 learn an object.\n\
98\n\
99 -i <input image path> \n\
100 Set image input path.\n\
101 From this path read \"line/image.%%04d.%s\"\n\
102 images. \n\
103 Setting the VISP_INPUT_IMAGE_PATH environment\n\
104 variable produces the same behaviour than using\n\
105 this option.\n\
106\n\
107 -b\n\
108 database filename to use (default is ./dataFern).\n\
109\n\
110 -c\n\
111 Disable the mouse click. Useful to automate the \n\
112 execution of this program without human intervention.\n\
113\n\
114 -d \n\
115 Turn off the display.\n\
116\n\
117 -p \n\
118 display points of interest.\n\
119\n\
120 -h\n\
121 Print this help.\n",
122 ext.c_str());
123
124 if (badparam)
125 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
126}
127
144bool getOptions(int argc, const char **argv, bool &isLearning, std::string &dataFile, bool &click_allowed,
145 bool &display, bool &displayPoints, std::string &ipath)
146{
147 const char *optarg_;
148 int c;
149 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
150
151 switch (c) {
152 case 'c':
153 click_allowed = false;
154 break;
155 case 'd':
156 display = false;
157 break;
158 case 'l':
159 isLearning = true;
160 break;
161 case 'h':
162 usage(argv[0], NULL);
163 return false;
164 break;
165 case 'b':
166 dataFile = optarg_;
167 break;
168 case 'p':
169 displayPoints = true;
170 break;
171 case 'i':
172 ipath = optarg_;
173 break;
174 default:
175 usage(argv[0], optarg_);
176 return false;
177 break;
178 }
179 }
180
181 if ((c == 1) || (c == -1)) {
182 // standalone param or error
183 usage(argv[0], NULL);
184 std::cerr << "ERROR: " << std::endl;
185 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
186 return false;
187 }
188
189 return true;
190}
191
192int main(int argc, const char **argv)
193{
194 try {
195 bool isLearning = false;
196 std::string dataFile("./dataFern");
197 bool opt_click_allowed = true;
198 bool opt_display = true;
199 std::string objectName("object");
200 bool displayPoints = false;
201 std::string opt_ipath;
202 std::string ipath;
203 std::string env_ipath;
204 std::string dirname;
205 std::string filename;
206
207#if VISP_HAVE_DATASET_VERSION >= 0x030600
208 std::string ext("png");
209#else
210 std::string ext("pgm");
211#endif
212
213 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
214 // environment variable value
216
217 // Set the default input path
218 if (!env_ipath.empty()) {
219 ipath = env_ipath;
220 }
221
222 // Read the command line options
223 if (getOptions(argc, argv, isLearning, dataFile, opt_click_allowed, opt_display, displayPoints, opt_ipath) ==
224 false) {
225 return EXIT_FAILURE;
226 }
227
228 // Get the option values
229 if (!opt_ipath.empty()) {
230 ipath = opt_ipath;
231 }
232
233 // Compare ipath and env_ipath. If they differ, we take into account
234 // the input path comming from the command line option
235 if (!opt_ipath.empty() && !env_ipath.empty()) {
236 if (ipath != env_ipath) {
237 std::cout << std::endl << "WARNING: " << std::endl;
238 std::cout << " Since -i <visp image path=" << ipath << "> "
239 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
240 << " we skip the environment variable." << std::endl;
241 }
242 }
243
244 // Test if an input path is set
245 if (opt_ipath.empty() && env_ipath.empty()) {
246 usage(argv[0], NULL);
247 std::cerr << std::endl << "ERROR:" << std::endl;
248 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
249 << " environment variable to specify the location of the " << std::endl
250 << " image path where test images are located." << std::endl
251 << std::endl;
252 return EXIT_FAILURE;
253 }
254
255 // Declare two images, these are gray level images (unsigned char)
258
259 // Set the path location of the image sequence
260 dirname = vpIoTools::createFilePath(ipath, "cube");
261
262 // Build the name of the image file
263 unsigned iter = 0; // Image number
264 std::ostringstream s;
265 s.setf(std::ios::right, std::ios::adjustfield);
266 s << "image." << std::setw(4) << std::setfill('0') << iter << "." << ext;
267 filename = vpIoTools::createFilePath(dirname, s.str());
268
269 // Read image named "filename" and put the bitmap in I
270 try {
271 std::cout << "Load: " << filename << std::endl;
272 vpImageIo::read(Iref, filename);
273 I = Iref;
274 }
275 catch (...) {
276 std::cerr << std::endl << "ERROR:" << std::endl;
277 std::cerr << " Cannot read " << filename << std::endl;
278 std::cerr << " Check your -i " << ipath << " option " << std::endl
279 << " or VISP_INPUT_IMAGE_PATH environment variable." << std::endl;
280 return EXIT_FAILURE;
281 }
282
283#if defined(VISP_HAVE_X11)
284 vpDisplayX display;
285#elif defined(VISP_HAVE_GTK)
286 vpDisplayGTK display;
287#elif defined(VISP_HAVE_GDI)
288 vpDisplayGDI display;
289#endif
290
291#if defined(VISP_HAVE_X11)
292 vpDisplayX displayRef;
293#elif defined(VISP_HAVE_GTK)
294 vpDisplayGTK displayRef;
295#elif defined(VISP_HAVE_GDI)
296 vpDisplayGDI displayRef;
297#endif
298
299 // declare a planar object detector
300 vpFernClassifier fern;
301
302 if (isLearning) {
303 if (opt_display) {
304 displayRef.init(Iref, 100, 100, "Reference image");
305 vpDisplay::display(Iref);
306 vpDisplay::flush(Iref);
307 }
308 vpImagePoint corners[2];
309 if (opt_display && opt_click_allowed) {
310 std::cout << "Click on the top left and the bottom right corners to "
311 "define the reference plane"
312 << std::endl;
313 for (int i = 0; i < 2; i++) {
314 vpDisplay::getClick(Iref, corners[i]);
315 std::cout << corners[i] << std::endl;
316 }
317 }
318 else {
319 corners[0].set_ij(1, 1);
320 corners[1].set_ij(I.getHeight() - 2, I.getWidth() - 2);
321 }
322
323 if (opt_display) {
324 // Display the rectangle which defines the part of the image where the
325 // reference points are computed.
326 vpDisplay::displayRectangle(Iref, corners[0], corners[1], vpColor::green);
327 vpDisplay::flush(Iref);
328 }
329
330 if (opt_click_allowed) {
331 std::cout << "Click on the image to continue" << std::endl;
333 }
334
335 vpRect roi(corners[0], corners[1]);
336
337 std::cout << "> train the classifier on the selected plane. (may take "
338 "up to several minutes)."
339 << std::endl;
340 if (opt_display) {
341 vpDisplay::display(Iref);
342 vpDisplay::flush(Iref);
343 }
344
345 try {
346 fern.buildReference(Iref, roi);
347 }
348 catch (const vpException &e) {
349 std::cout << e.getMessage() << std::endl;
350 }
351 catch (...) {
352 std::cout << "unknown error, line " << __LINE__ << std::endl;
353 }
354 try {
355 fern.record(objectName, dataFile);
356 }
357 catch (const vpException &e) {
358 std::cout << e.getMessage() << std::endl;
359 }
360 catch (...) {
361 std::cout << "unknown error, line " << __LINE__ << std::endl;
362 }
363 std::cout << __LINE__ << std::endl;
364 }
365 else {
366 if (!vpIoTools::checkFilename(dataFile)) {
367 vpERROR_TRACE("cannot load the database with the specified name. Has "
368 "the object been learned with the -l option? ");
369 return EXIT_FAILURE;
370 }
371 try {
372 // load a previously recorded file
373 fern.load(dataFile, objectName);
374 }
375 catch (...) {
376 vpERROR_TRACE("cannot load the database with the specified name. Has "
377 "the object been learned with the -l option? ");
378 return EXIT_FAILURE;
379 }
380 }
381
382 if (opt_display) {
383 display.init(I, 110 + (int)Iref.getWidth(), 100, "Current image");
386 }
387
388 if (opt_display && opt_click_allowed) {
389 std::cout << "Click on the current image to continue" << std::endl;
390 vpDisplay::displayText(I, vpImagePoint(15, 15), "Click on the current image to continue", vpColor::red);
393 }
394
395 for (;;) {
396 // acquire a new image
397 iter++;
398 if (iter >= 80) {
399 break;
400 }
401 s.str("");
402 s << "image." << std::setw(4) << std::setfill('0') << iter << "." << ext;
403 filename = vpIoTools::createFilePath(dirname, s.str());
404 // read the image
405 vpImageIo::read(I, filename);
406
407 if (opt_display) {
409 if (isLearning)
410 vpDisplay::display(Iref);
411 }
412
413 double t0 = vpTime::measureTimeMs();
414 // detection of the reference image
415 unsigned int nbpts;
416 try {
417 nbpts = fern.matchPoint(I);
418 }
419 catch (const vpException &e) {
420 std::cout << e.getMessage() << std::endl;
421 return EXIT_FAILURE;
422 }
423 catch (...) {
424 std::cout << "unknown error line " << __LINE__ << std::endl;
425 return EXIT_FAILURE;
426 }
427 std::cout << "matching " << nbpts << " points : " << vpTime::measureTimeMs() - t0 << " ms" << std::endl;
428
429 if (opt_display) {
430 fern.display(Iref, I, 7);
432 if (isLearning)
433 vpDisplay::flush(Iref);
434 if (vpDisplay::getClick(I, false)) {
435 break;
436 }
437 }
438 }
439
440 return EXIT_SUCCESS;
441 }
442 catch (const vpException &e) {
443 std::cout << "Catch an exception: " << e << std::endl;
444 return EXIT_SUCCESS;
445 }
446}
447
448#else
449int main()
450{
451#if (!(defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)))
452 std::cout << "You do not have X11, or GTK, or GDI (Graphical Device Interface) functionalities to display images..."
453 << std::endl;
454 std::cout << "Tip if you are on a unix-like system:" << std::endl;
455 std::cout << "- Install X11, configure again ViSP using cmake and build again this example" << std::endl;
456 std::cout << "Tip if you are on a windows-like system:" << std::endl;
457 std::cout << "- Install GDI, configure again ViSP using cmake and build again this example" << std::endl;
458#else
459 std::cout << "You do not have OpenCV functionalities" << std::endl;
460 std::cout << "Tip:" << std::endl;
461 std::cout << "- Install OpenCV, configure again ViSP using cmake and build again this example" << std::endl;
462#endif
463 return EXIT_SUCCESS;
464}
465
466#endif
static const vpColor red
Definition vpColor.h:211
static const vpColor green
Definition vpColor.h:214
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...
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition vpDisplayX.h:132
void init(vpImage< unsigned char > &I, int win_x=-1, int win_y=-1, const std::string &win_title="")
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
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.
Definition vpException.h:59
const char * getMessage() const
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 ...
void set_ij(double ii, double jj)
Definition of the vpImage class member functions.
Definition vpImage.h:135
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getHeight() const
Definition vpImage.h:184
static std::string getViSPImagesDataPath()
static bool checkFilename(const std::string &filename)
static std::string createFilePath(const std::string &parent, const std::string &child)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Defines a rectangle in the plane.
Definition vpRect.h:76
#define vpERROR_TRACE
Definition vpDebug.h:388
VISP_EXPORT double measureTimeMs()