1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2019 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 http://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  * Read an image on the disk and display it using OpenCV.
33  *
34  * Authors:
35  * Nicolas Melchior
36  *
37  *****************************************************************************/
38 /*!
39   \file displayOpenCV.cpp
40 
41   \brief Read an image on the disk, display it using vpDisplayOpenCV class,
42   display some features (line, circle, caracters) in overlay and finaly
43   write the image and the overlayed features in an image on the disk.
44 
45 */
46 
47 #include <iostream>
48 #include <stdlib.h>
49 #include <visp3/core/vpConfig.h>
50 #include <visp3/core/vpDebug.h>
51 
52 #if defined(VISP_HAVE_OPENCV)
53 
54 #include <visp3/core/vpImage.h>
55 #include <visp3/core/vpIoTools.h>
56 #include <visp3/gui/vpDisplayOpenCV.h>
57 #include <visp3/io/vpImageIo.h>
58 #include <visp3/io/vpParseArgv.h>
59 
60 #include <visp3/core/vpTime.h>
61 
62 /*!
63   \example displayOpenCV.cpp
64 
65   Read an image on the disk, display it using vpDisplayOpenCV class,
66   display some features (line, circle, caracters) in overlay and finaly
67   write the image and the overlayed features in an image on the disk.
68 
69 */
70 
71 // List of allowed command line options
72 #define GETOPTARGS "cdi:o:p:h"
73 
74 /*!
75 
76   Print the program options.
77 
78   \param name : Program name.
79   \param badparam : Bad parameter name.
80   \param ipath : Input image path.
81   \param opath : Output image path.
82   \param user : Username.
83 
84  */
usage(const char * name,const char * badparam,std::string ipath,std::string opath,std::string user)85 void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user)
86 {
87   fprintf(stdout, "\n\
88 Read an image on the disk, display it using OpenCV, display some\n\
89 features (line, circle, caracters) in overlay and finaly write \n\
90 the image and the overlayed features in an image on the disk.\n\
91 \n\
92 SYNOPSIS\n\
93   %s [-i <input image path>] [-o <output image path>]\n\
94      [-c] [-d] [-h]\n						      \
95 ", name);
96 
97   fprintf(stdout, "\n\
98 OPTIONS:                                               Default\n\
99   -i <input image path>                                %s\n\
100      Set image input path.\n\
101      From this path read \"Klimt/Klimt.pgm\"\n\
102      image.\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   -o <output image path>                               %s\n\
108      Set image output path.\n\
109      From this directory, creates the \"%s\"\n\
110      subdirectory depending on the username, where \n\
111      Klimt_grey.overlay.ppm output image is written.\n\
112 \n\
113   -c\n\
114      Disable the mouse click. Useful to automate the \n\
115      execution of this program without humain intervention.\n\
116 \n\
117   -d                                             \n\
118      Disable the image display. This can be useful \n\
119      for automatic tests using crontab under Unix or \n\
120      using the task manager under Windows.\n\
121 \n\
122   -h\n\
123      Print the help.\n\n", ipath.c_str(), opath.c_str(), user.c_str());
124 
125   if (badparam) {
126     fprintf(stderr, "ERROR: \n");
127     fprintf(stderr, "\nBad parameter [%s]\n", badparam);
128   }
129 }
130 
131 /*!
132 
133   Set the program options.
134 
135   \param argc : Command line number of parameters.
136   \param argv : Array of command line parameters.
137   \param ipath : Input image path.
138   \param opath : Output image path.
139   \param click_allowed : Enable/disable mouse click.
140   \param user : Username.
141   \param display : Set as true, activates the image display. This is
142   the default configuration. When set to false, the display is
143   disabled. This can be useful for automatic tests using crontab
144   under Unix or using the task manager under Windows.
145 
146   \return false if the program has to be stopped, true otherwise.
147 
148 */
getOptions(int argc,const char ** argv,std::string & ipath,std::string & opath,bool & click_allowed,const std::string & user,bool & display)149 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, bool &click_allowed,
150                 const std::string &user, bool &display)
151 {
152   const char *optarg_;
153   int c;
154   while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
155 
156     switch (c) {
157     case 'c':
158       click_allowed = false;
159       break;
160     case 'd':
161       display = false;
162       break;
163     case 'i':
164       ipath = optarg_;
165       break;
166     case 'o':
167       opath = optarg_;
168       break;
169     case 'h':
170       usage(argv[0], NULL, ipath, opath, user);
171       return false;
172       break;
173 
174     default:
175       usage(argv[0], optarg_, ipath, opath, user);
176       return false;
177       break;
178     }
179   }
180 
181   if ((c == 1) || (c == -1)) {
182     // standalone param or error
183     usage(argv[0], NULL, ipath, opath, user);
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 
main(int argc,const char ** argv)192 int main(int argc, const char **argv)
193 {
194   try {
195     std::string env_ipath;
196     std::string opt_ipath;
197     std::string opt_opath;
198     std::string ipath;
199     std::string opath;
200     std::string filename;
201     std::string username;
202     bool opt_click_allowed = true;
203     bool opt_display = true;
204 
205     // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
206     // environment variable value
207     env_ipath = vpIoTools::getViSPImagesDataPath();
208 
209     // Set the default input path
210     if (!env_ipath.empty())
211       ipath = env_ipath;
212 
213 // Set the default output path
214 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
215     opt_opath = "/tmp";
216 #elif defined(_WIN32)
217     opt_opath = "C:\\temp";
218 #endif
219 
220     // Get the user login name
221     vpIoTools::getUserName(username);
222 
223     // Read the command line options
224     if (getOptions(argc, argv, opt_ipath, opt_opath, opt_click_allowed, username, opt_display) == false) {
225       exit(-1);
226     }
227 
228     // Get the option values
229     if (!opt_ipath.empty())
230       ipath = opt_ipath;
231     if (!opt_opath.empty())
232       opath = opt_opath;
233 
234     // Append to the output path string, the login name of the user
235     std::string odirname = vpIoTools::createFilePath(opath, username);
236 
237     // Test if the output path exist. If no try to create it
238     if (vpIoTools::checkDirectory(odirname) == false) {
239       try {
240         // Create the dirname
241         vpIoTools::makeDirectory(odirname);
242       } catch (...) {
243         usage(argv[0], NULL, ipath, opath, username);
244         std::cerr << std::endl << "ERROR:" << std::endl;
245         std::cerr << "  Cannot create " << odirname << std::endl;
246         std::cerr << "  Check your -o " << opath << " option " << std::endl;
247         exit(-1);
248       }
249     }
250 
251     // Compare ipath and env_ipath. If they differ, we take into account
252     // the input path comming from the command line option
253     if (!opt_ipath.empty() && !env_ipath.empty()) {
254       if (ipath != env_ipath) {
255         std::cout << std::endl << "WARNING: " << std::endl;
256         std::cout << "  Since -i <visp image path=" << ipath << "> "
257                   << "  is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
258                   << "  we skip the environment variable." << std::endl;
259       }
260     }
261 
262     // Test if an input path is set
263     if (opt_ipath.empty() && env_ipath.empty()) {
264       usage(argv[0], NULL, ipath, opath, username);
265       std::cerr << std::endl << "ERROR:" << std::endl;
266       std::cerr << "  Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
267                 << "  environment variable to specify the location of the " << std::endl
268                 << "  image path where test images are located." << std::endl
269                 << std::endl;
270       exit(-1);
271     }
272 
273     // Create a grey level image
274     vpImage<unsigned char> I;
275     vpImagePoint ip, ip1, ip2;
276 
277     // Load a grey image from the disk
278     filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
279     vpImageIo::read(I, filename);
280 
281     // Create a display using X11
282     vpDisplayOpenCV display;
283 
284     if (opt_display) {
285       // For this grey level image, open a X11 display at position 100,100
286       // in the screen, and with title "X11 display"
287       display.init(I, 100, 100, "X11 display");
288 
289       // Display the image
290       vpDisplay::display(I);
291 
292       // Display in overlay a red cross at position 10,10 in the
293       // image. The lines are 10 pixels long
294       ip.set_i(100);
295       ip.set_j(10);
296 
297       vpDisplay::displayCross(I, ip, 20, vpColor::red);
298 
299       // Display in overlay horizontal red lines
300       for (unsigned i = 0; i < I.getHeight(); i += 20) {
301         ip1.set_i(i);
302         ip1.set_j(0);
303         ip2.set_i(i);
304         ip2.set_j(I.getWidth());
305         vpDisplay::displayLine(I, ip1, ip2, vpColor::red);
306       }
307 
308       // Display a ligne in the diagonal
309       ip1.set_i(-10);
310       ip1.set_j(-10);
311       ip2.set_i(I.getHeight() + 10);
312       ip2.set_j(I.getWidth() + 10);
313 
314       vpDisplay::displayLine(I, ip1, ip2, vpColor::red);
315 
316       // Display in overlay vertical green dot lines
317       for (unsigned i = 0; i < I.getWidth(); i += 20) {
318         ip1.set_i(0);
319         ip1.set_j(i);
320         ip2.set_i(I.getWidth());
321         ip2.set_j(i);
322         vpDisplay::displayDotLine(I, ip1, ip2, vpColor::green);
323       }
324 
325       // Display a transparent rectangle
326       ip.set_i(I.getHeight() - 45);
327       ip.set_j(-10);
328       vpDisplay::displayRectangle(I, ip, 60, 80, vpColor(vpColor::orange, 127), true, 2U);
329 
330       // Display a transparent circle onto the image
331       vpColor transparent_red(vpColor::red, 127);
332       vpDisplay::displayCircle(I, vpImagePoint(I.getHeight() / 3, I.getWidth() / 2), I.getHeight() / 4,
333                                transparent_red, true);
334 
335       // Display a second transparent circle
336       vpColor very_transparent_blue(0, 0, 255, 63);
337       vpDisplay::displayCircle(I, vpImagePoint(2 * I.getHeight() / 3, I.getWidth() / 2), I.getHeight() / 4,
338                                very_transparent_blue, true);
339 
340       // Display in overlay a blue arrow
341       ip1.set_i(0);
342       ip1.set_j(0);
343       ip2.set_i(100);
344       ip2.set_j(100);
345       vpDisplay::displayArrow(I, ip1, ip2, vpColor::blue);
346 
347       // Display in overlay some circles. The position of the center is 200,
348       // 200 the radius is increased by 20 pixels for each circle
349 
350       for (unsigned int i = 0; i < 100; i += 20) {
351         ip.set_i(80);
352         ip.set_j(80);
353         vpDisplay::displayCircle(I, ip, 20 + i, vpColor::yellow);
354       }
355 
356       ip.set_i(-10);
357       ip.set_j(300);
358       vpDisplay::displayCircle(I, ip, 100, vpColor::yellow);
359 
360       // Display in overlay a yellow string
361       ip.set_i(85);
362       ip.set_j(100);
363       vpDisplay::displayText(I, ip, "ViSP is a marvelous software", vpColor::yellow);
364       // Flush the display
365       vpDisplay::flush(I);
366 
367       // Create a color image
368       vpImage<vpRGBa> Ioverlay;
369       // Updates the color image with the original loaded image and the
370       // overlay
371       vpDisplay::getImage(I, Ioverlay);
372 
373       // Write the color image on the disk
374       filename = vpIoTools::createFilePath(odirname, "Klimt_grey.overlay.ppm");
375       vpImageIo::write(Ioverlay, filename);
376 
377       // If click is allowed, wait for a mouse click to close the display
378       if (opt_click_allowed) {
379         std::cout << "\nA click to close the windows..." << std::endl;
380         // Wait for a blocking mouse click
381         vpDisplay::getClick(I);
382       }
383 
384       // Close the display
385       vpDisplay::close(I);
386     }
387 
388     // Create a color image
389     vpImage<vpRGBa> Irgba;
390 
391     // Load a grey image from the disk and convert it to a color image
392     filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.ppm");
393     vpImageIo::read(Irgba, filename);
394 
395     // Create a new display
396     vpDisplayOpenCV displayRGBa;
397 
398     if (opt_display) {
399       // For this color image, open a X11 display at position 100,100
400       // in the screen, and with title "X11 color display"
401       displayRGBa.init(Irgba, 100, 100, "X11 color display");
402 
403       // Display the color image
404       vpDisplay::display(Irgba);
405       vpDisplay::flush(Irgba);
406 
407       // If click is allowed, wait for a blocking mouse click to display a
408       // cross at the clicked pixel position
409       if (opt_click_allowed) {
410         std::cout << "\nA click to display a cross..." << std::endl;
411         // Blocking wait for a click. Get the position of the selected pixel
412         // (i correspond to the row and j to the column coordinates in the
413         // image)
414         vpDisplay::getClick(Irgba, ip);
415         // Display a red cross on the click pixel position
416         std::cout << "Cross position: " << ip << std::endl;
417         vpDisplay::displayCross(Irgba, ip, 15, vpColor::red);
418       } else {
419         ip.set_i(10);
420         ip.set_j(20);
421         // Display a red cross at position i, j (i correspond to the row
422         // and j to the column coordinates in the image)
423         std::cout << "Cross position: " << ip << std::endl;
424         vpDisplay::displayCross(Irgba, ip, 15, vpColor::red);
425       }
426       // Flush the display. Sometimes the display content is
427       // bufferized. Force to display the content that has been bufferized.
428       vpDisplay::flush(Irgba);
429 
430       // Create a color image
431       vpImage<vpRGBa> Ioverlay;
432       // Updates the color image with the original loaded image and the
433       // overlay
434       vpDisplay::getImage(Irgba, Ioverlay);
435 
436       // Write the color image on the disk
437       filename = vpIoTools::createFilePath(odirname, "Klimt_color.overlay.ppm");
438       vpImageIo::write(Ioverlay, filename);
439 
440       // If click is allowed, wait for a blocking mouse click to exit.
441       if (opt_click_allowed) {
442         std::cout << "\nA click to exit the program..." << std::endl;
443         vpDisplay::getClick(Irgba);
444         std::cout << "Bye" << std::endl;
445       }
446     }
447     return EXIT_SUCCESS;
448   } catch (const vpException &e) {
449     std::cout << "Catch an exception: " << e << std::endl;
450     return EXIT_FAILURE;
451   }
452 }
453 #else
main()454 int main()
455 {
456   std::cout << "You do not have OpenCV functionalities to display images..." << 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   return EXIT_SUCCESS;
460 }
461 #endif
462