Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
planarObjectDetector.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 planar surface using Fern classifier.
33 *
34*****************************************************************************/
47#include <visp3/core/vpConfig.h>
48#include <visp3/core/vpDebug.h>
49
50#if ((defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)) && \
51 (VISP_HAVE_OPENCV_VERSION >= 0x020408) && (VISP_HAVE_OPENCV_VERSION < 0x030000))
52
53#include <iomanip>
54#include <iostream>
55#include <stdlib.h>
56#include <visp3/core/vpConfig.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/sensor/vp1394TwoGrabber.h>
66#include <visp3/sensor/vpV4l2Grabber.h>
67#include <visp3/vision/vpHomography.h>
68#include <visp3/vision/vpPlanarObjectDetector.h>
69
70#define GETOPTARGS "hlcdb:i:p"
71
72void usage(const char *name, const char *badparam);
73bool getOptions(int argc, const char **argv, bool &isLearning, std::string &dataFile, bool &click_allowed,
74 bool &display, bool &displayPoints, std::string &ipath);
75
84void usage(const char *name, const char *badparam)
85{
86#if VISP_HAVE_DATASET_VERSION >= 0x030600
87 std::string ext("png");
88#else
89 std::string ext("pgm");
90#endif
91 fprintf(stdout, "\n\
92Test of detection of planar surface using a Fern classifier. The object needs \
93 first to be learned (-l option). This learning process will create a file used\
94 to detect the object.\n\
95\n\
96SYNOPSIS\n\
97 %s [-l] [-h] [-b] [-c] [-d] [-p] [-i] [-s]\n",
98 name);
99
100 fprintf(stdout, "\n\
101OPTIONS: \n\
102 -l\n\
103 learn an object.\n\
104\n\
105 -i <input image path> \n\
106 Set image input path.\n\
107 From this path read \"line/image.%%04d.%s\"\n\
108 images. \n\
109 Setting the VISP_INPUT_IMAGE_PATH environment\n\
110 variable produces the same behaviour than using\n\
111 this option.\n\
112\n\
113 -b\n\
114 database filename to use (default is ./dataPlanar).\n\
115\n\
116 -c\n\
117 Disable the mouse click. Useful to automate the \n\
118 execution of this program without human intervention.\n\
119\n\
120 -d \n\
121 Turn off the display.\n\
122\n\
123 -s \n\
124 Turn off the use of the sequence and use a webcam.\n\
125\n\
126 -p \n\
127 display points of interest.\n\
128\n\
129 -h\n\
130 Print this help.\n", ext.c_str());
131
132 if (badparam)
133 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
134}
135
152bool getOptions(int argc, const char **argv, bool &isLearning, std::string &dataFile, bool &click_allowed,
153 bool &display, bool &displayPoints, std::string &ipath)
154{
155 const char *optarg_;
156 int c;
157 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
158
159 switch (c) {
160 case 'c':
161 click_allowed = false;
162 break;
163 case 'd':
164 display = false;
165 break;
166 case 'l':
167 isLearning = true;
168 break;
169 case 'h':
170 usage(argv[0], NULL);
171 return false;
172 break;
173 case 'b':
174 dataFile = optarg_;
175 break;
176 case 'p':
177 displayPoints = true;
178 break;
179 case 'i':
180 ipath = optarg_;
181 break;
182 default:
183 usage(argv[0], optarg_);
184 return false;
185 break;
186 }
187 }
188
189 if ((c == 1) || (c == -1)) {
190 // standalone param or error
191 usage(argv[0], NULL);
192 std::cerr << "ERROR: " << std::endl;
193 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
194 return false;
195 }
196
197 return true;
198}
199
200int main(int argc, const char **argv)
201{
202 try {
203 bool isLearning = false;
204 std::string dataFile("./dataPlanar");
205 bool opt_click_allowed = true;
206 bool opt_display = true;
207 std::string objectName("object");
208 bool displayPoints = false;
209 std::string opt_ipath;
210 std::string ipath;
211 std::string env_ipath;
212 std::string dirname;
213 std::string filename;
214
215#if VISP_HAVE_DATASET_VERSION >= 0x030600
216 std::string ext("png");
217#else
218 std::string ext("pgm");
219#endif
220
221 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
222 // environment variable value
224
225 // Set the default input path
226 if (!env_ipath.empty()) {
227 ipath = env_ipath;
228 }
229
230 // Read the command line options
231 if (getOptions(argc, argv, isLearning, dataFile, opt_click_allowed, opt_display, displayPoints, opt_ipath) ==
232 false) {
233 return EXIT_FAILURE;
234 }
235
236 // Get the option values
237 if (!opt_ipath.empty()) {
238 ipath = opt_ipath;
239 }
240
241 // Compare ipath and env_ipath. If they differ, we take into account
242 // the input path comming from the command line option
243 if (!opt_ipath.empty() && !env_ipath.empty()) {
244 if (ipath != env_ipath) {
245 std::cout << std::endl << "WARNING: " << std::endl;
246 std::cout << " Since -i <visp image path=" << ipath << "> "
247 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
248 << " we skip the environment variable." << std::endl;
249 }
250 }
251
252 // Test if an input path is set
253 if (opt_ipath.empty() && env_ipath.empty()) {
254 usage(argv[0], NULL);
255 std::cerr << std::endl << "ERROR:" << std::endl;
256 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
257 << " environment variable to specify the location of the " << std::endl
258 << " image path where test images are located." << std::endl
259 << std::endl;
260 return EXIT_FAILURE;
261 }
262
263 // Declare two images, these are gray level images (unsigned char)
266
267 // Set the path location of the image sequence
268 dirname = vpIoTools::createFilePath(ipath, "cube");
269
270 // Build the name of the image file
271 unsigned iter = 0; // Image number
272 std::ostringstream s;
273 s.setf(std::ios::right, std::ios::adjustfield);
274 s << "image." << std::setw(4) << std::setfill('0') << iter << "." << ext;
275 filename = vpIoTools::createFilePath(dirname, s.str());
276
277 // Read image named "filename" and put the bitmap in I
278 try {
279 std::cout << "Load: " << filename << std::endl;
280 vpImageIo::read(Iref, filename);
281 I = Iref;
282 }
283 catch (...) {
284 std::cerr << std::endl << "ERROR:" << std::endl;
285 std::cerr << " Cannot read " << filename << std::endl;
286 std::cerr << " Check your -i " << ipath << " option " << std::endl
287 << " or VISP_INPUT_IMAGE_PATH environment variable." << std::endl;
288 return EXIT_FAILURE;
289 }
290
291#if defined(VISP_HAVE_X11)
292 vpDisplayX display;
293#elif defined(VISP_HAVE_GTK)
294 vpDisplayGTK display;
295#elif defined(VISP_HAVE_GDI)
296 vpDisplayGDI display;
297#endif
298
299#if defined(VISP_HAVE_X11)
300 vpDisplayX displayRef;
301#elif defined(VISP_HAVE_GTK)
302 vpDisplayGTK displayRef;
303#elif defined(VISP_HAVE_GDI)
304 vpDisplayGDI displayRef;
305#endif
306
307 // declare a planar object detector
308 vpPlanarObjectDetector planar;
309
310 vpImagePoint corners[2];
311 if (isLearning) {
312 if (opt_display) {
313 displayRef.init(Iref, 100, 100, "Reference image");
314 vpDisplay::display(Iref);
315 vpDisplay::flush(Iref);
316 }
317 if (opt_display && opt_click_allowed) {
318 std::cout << "Click on the top left and the bottom right corners to "
319 "define the reference plane"
320 << std::endl;
321 for (int i = 0; i < 2; i++) {
322 vpDisplay::getClick(Iref, corners[i]);
323 std::cout << corners[i] << std::endl;
324 }
325 }
326 else {
327 corners[0].set_ij(50, I.getWidth() - 100); // small ROI for the automated test
328 corners[1].set_ij(I.getHeight() - 100, I.getWidth() - 2);
329 }
330
331 if (opt_display) {
332 // Display the rectangle which defines the part of the image where the
333 // reference points are computed.
334 vpDisplay::displayRectangle(Iref, corners[0], corners[1], vpColor::green);
335 vpDisplay::flush(Iref);
336 }
337
338 if (opt_click_allowed) {
339 std::cout << "Click on the image to continue" << std::endl;
341 }
342
343 vpRect roi(corners[0], corners[1]);
344
345 std::cout << "> train the classifier on the selected plane (may take "
346 "up to several minutes)."
347 << std::endl;
348 if (opt_display) {
349 vpDisplay::display(Iref);
350 vpDisplay::flush(Iref);
351 }
352 double t0 = vpTime::measureTimeMs();
353 planar.buildReference(Iref, roi);
354 std::cout << "build reference in " << vpTime::measureTimeMs() - t0 << " ms" << std::endl;
356 planar.recordDetector(objectName, dataFile);
357 std::cout << "record detector in " << vpTime::measureTimeMs() - t0 << " ms" << std::endl;
358 }
359 else {
360 if (!vpIoTools::checkFilename(dataFile)) {
361 vpERROR_TRACE("cannot load the database with the specified name. Has "
362 "the object been learned with the -l option? ");
363 return EXIT_FAILURE;
364 }
365 try {
366 // load a previously recorded file
367 planar.load(dataFile, objectName);
368 }
369 catch (...) {
370 vpERROR_TRACE("cannot load the database with the specified name. Has "
371 "the object been learned with the -l option? ");
372 return EXIT_FAILURE;
373 }
374 }
375
376 if (opt_display) {
377 display.init(I, 110 + (int)Iref.getWidth(), 100, "Current image");
380 }
381
382 if (opt_display && opt_click_allowed) {
383 std::cout << "Click on the reference image to continue" << std::endl;
384 vpDisplay::displayText(Iref, vpImagePoint(15, 15), "Click on the reference image to continue", vpColor::red);
385 vpDisplay::flush(Iref);
387 }
388
389 for (;;) {
390 // acquire a new image
391 iter++;
392 if (iter >= 80) {
393 break;
394 }
395 s.str("");
396 s << "image." << std::setw(4) << std::setfill('0') << iter << "." << ext;
397 filename = vpIoTools::createFilePath(dirname, s.str());
398 // read the image
399 vpImageIo::read(I, filename);
400
401 if (opt_display) {
403 }
404
405 double t0 = vpTime::measureTimeMs();
406 // detection of the reference planar surface
407 bool isDetected = planar.matchPoint(I);
408 std::cout << "matching in " << vpTime::measureTimeMs() - t0 << " ms" << std::endl;
409
410 if (isDetected) {
411 vpHomography H;
412 planar.getHomography(H);
413 std::cout << " > computed homography:" << std::endl << H << std::endl;
414 if (opt_display) {
415 if (isLearning) {
416 vpDisplay::display(Iref);
417 vpDisplay::displayRectangle(Iref, corners[0], corners[1], vpColor::green);
418 planar.display(Iref, I, displayPoints);
419 vpDisplay::flush(Iref);
420 }
421 else {
422 planar.display(I, displayPoints);
423 }
424 }
425 }
426 else {
427 std::cout << " > reference is not detected in the image" << std::endl;
428 }
429 if (opt_display) {
431 if (vpDisplay::getClick(I, false)) {
432 break;
433 }
434 }
435 }
436
437 return EXIT_SUCCESS;
438 }
439 catch (const vpException &e) {
440 std::cout << "Catch an exception: " << e << std::endl;
441 return EXIT_FAILURE;
442 }
443}
444
445#else
446int main()
447{
448#if (!(defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK) || defined(VISP_HAVE_GDI)))
449 std::cout << "You do not have X11, or GTK, or GDI (Graphical Device Interface) functionalities to display images..."
450 << std::endl;
451 std::cout << "Tip if you are on a unix-like system:" << std::endl;
452 std::cout << "- Install X11, configure again ViSP using cmake and build again this example" << std::endl;
453 std::cout << "Tip if you are on a windows-like system:" << std::endl;
454 std::cout << "- Install GDI, configure again ViSP using cmake and build again this example" << std::endl;
455#else
456 std::cout << "You do not have OpenCV functionalities" << std::endl;
457 std::cout << "Tip:" << std::endl;
458 std::cout << "- Install OpenCV, configure again ViSP using cmake and build again this example" << std::endl;
459#endif
460 return EXIT_SUCCESS;
461}
462
463#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
Implementation of an homography and operations on homographies.
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()