Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
displayOpenCV.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  * Read an image on the disk and display it using OpenCV.
33  *
34 *****************************************************************************/
44 #include <iostream>
45 #include <stdlib.h>
46 #include <visp3/core/vpConfig.h>
47 #include <visp3/core/vpDebug.h>
48 
49 #if defined(HAVE_OPENCV_HIGHGUI)
50 
51 #include <visp3/core/vpImage.h>
52 #include <visp3/core/vpIoTools.h>
53 #include <visp3/gui/vpDisplayOpenCV.h>
54 #include <visp3/io/vpImageIo.h>
55 #include <visp3/io/vpParseArgv.h>
56 
57 #include <visp3/core/vpTime.h>
58 
68 // List of allowed command line options
69 #define GETOPTARGS "cdi:o:p:h"
70 
71 #ifdef ENABLE_VISP_NAMESPACE
72 using namespace VISP_NAMESPACE_NAME;
73 #endif
74 
86 void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user)
87 {
88  fprintf(stdout, "\n\
89 Read an image on the disk, display it using OpenCV, display some\n\
90 features (line, circle, characters) in overlay and finally write \n\
91 the image and the overlayed features in an image on the disk.\n\
92 \n\
93 SYNOPSIS\n\
94  %s [-i <input image path>] [-o <output image path>]\n\
95  [-c] [-d] [-h]\n \
96 ",
97 name);
98 
99  fprintf(stdout, "\n\
100 OPTIONS: Default\n\
101  -i <input image path> %s\n\
102  Set image input path.\n\
103  From this path read \"Klimt/Klimt.pgm\"\n\
104  image.\n\
105  Setting the VISP_INPUT_IMAGE_PATH environment\n\
106  variable produces the same behaviour than using\n\
107  this option.\n\
108 \n\
109  -o <output image path> %s\n\
110  Set image output path.\n\
111  From this directory, creates the \"%s\"\n\
112  subdirectory depending on the username, where \n\
113  Klimt_grey.overlay.ppm output image is written.\n\
114 \n\
115  -c\n\
116  Disable the mouse click. Useful to automate the \n\
117  execution of this program without human intervention.\n\
118 \n\
119  -d \n\
120  Disable the image display. This can be useful \n\
121  for automatic tests using crontab under Unix or \n\
122  using the task manager under Windows.\n\
123 \n\
124  -h\n\
125  Print the help.\n\n",
126  ipath.c_str(), opath.c_str(), user.c_str());
127 
128  if (badparam) {
129  fprintf(stderr, "ERROR: \n");
130  fprintf(stderr, "\nBad parameter [%s]\n", badparam);
131  }
132 }
133 
152 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, bool &click_allowed,
153  const std::string &user, bool &display)
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 'i':
167  ipath = optarg_;
168  break;
169  case 'o':
170  opath = optarg_;
171  break;
172  case 'h':
173  usage(argv[0], nullptr, ipath, opath, user);
174  return false;
175  break;
176 
177  default:
178  usage(argv[0], optarg_, ipath, opath, user);
179  return false;
180  break;
181  }
182  }
183 
184  if ((c == 1) || (c == -1)) {
185  // standalone param or error
186  usage(argv[0], nullptr, ipath, opath, user);
187  std::cerr << "ERROR: " << std::endl;
188  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
189  return false;
190  }
191 
192  return true;
193 }
194 
195 int main(int argc, const char **argv)
196 {
197  try {
198  std::string env_ipath;
199  std::string opt_ipath;
200  std::string opt_opath;
201  std::string ipath;
202  std::string opath;
203  std::string filename;
204  std::string username;
205  bool opt_click_allowed = true;
206  bool opt_display = true;
207 
208  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
209  // environment variable value
210  env_ipath = vpIoTools::getViSPImagesDataPath();
211 
212  // Set the default input path
213  if (!env_ipath.empty())
214  ipath = env_ipath;
215 
216  // Set the default output path
217 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
218  opt_opath = "/tmp";
219 #elif defined(_WIN32)
220  opt_opath = "C:\\temp";
221 #endif
222 
223  // Get the user login name
224  vpIoTools::getUserName(username);
225 
226  // Read the command line options
227  if (getOptions(argc, argv, opt_ipath, opt_opath, opt_click_allowed, username, opt_display) == false) {
228  return EXIT_FAILURE;
229  }
230 
231  // Get the option values
232  if (!opt_ipath.empty())
233  ipath = opt_ipath;
234  if (!opt_opath.empty())
235  opath = opt_opath;
236 
237  // Append to the output path string, the login name of the user
238  std::string odirname = vpIoTools::createFilePath(opath, username);
239 
240  // Test if the output path exist. If no try to create it
241  if (vpIoTools::checkDirectory(odirname) == false) {
242  try {
243  // Create the dirname
244  vpIoTools::makeDirectory(odirname);
245  }
246  catch (...) {
247  usage(argv[0], nullptr, ipath, opath, username);
248  std::cerr << std::endl << "ERROR:" << std::endl;
249  std::cerr << " Cannot create " << odirname << std::endl;
250  std::cerr << " Check your -o " << opath << " option " << std::endl;
251  return EXIT_FAILURE;
252  }
253  }
254 
255  // Compare ipath and env_ipath. If they differ, we take into account
256  // the input path coming from the command line option
257  if (!opt_ipath.empty() && !env_ipath.empty()) {
258  if (ipath != env_ipath) {
259  std::cout << std::endl << "WARNING: " << std::endl;
260  std::cout << " Since -i <visp image path=" << ipath << "> "
261  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
262  << " we skip the environment variable." << std::endl;
263  }
264  }
265 
266  // Test if an input path is set
267  if (opt_ipath.empty() && env_ipath.empty()) {
268  usage(argv[0], nullptr, ipath, opath, username);
269  std::cerr << std::endl << "ERROR:" << std::endl;
270  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
271  << " environment variable to specify the location of the " << std::endl
272  << " image path where test images are located." << std::endl
273  << std::endl;
274  return EXIT_FAILURE;
275  }
276 
277  // Create a grey level image
279  vpImagePoint ip, ip1, ip2;
280 
281  // Load a grey image from the disk
282  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
283  vpImageIo::read(I, filename);
284 
285  // Create a display using X11
286  vpDisplayOpenCV display;
287 
288  if (opt_display) {
289  // For this grey level image, open a X11 display at position 100,100
290  // in the screen, and with title "X11 display"
291  display.init(I, 100, 100, "X11 display");
292 
293  // Display the image
295 
296  // Display in overlay a red cross at position 10,10 in the
297  // image. The lines are 10 pixels long
298  ip.set_i(100);
299  ip.set_j(10);
300 
302 
303  // Display in overlay horizontal red lines
304  for (unsigned i = 0; i < I.getHeight(); i += 20) {
305  ip1.set_i(i);
306  ip1.set_j(0);
307  ip2.set_i(i);
308  ip2.set_j(I.getWidth());
309  vpDisplay::displayLine(I, ip1, ip2, vpColor::red);
310  }
311 
312  // Display a ligne in the diagonal
313  ip1.set_i(-10);
314  ip1.set_j(-10);
315  ip2.set_i(I.getHeight() + 10);
316  ip2.set_j(I.getWidth() + 10);
317 
318  vpDisplay::displayLine(I, ip1, ip2, vpColor::red);
319 
320  // Display in overlay vertical green dot lines
321  for (unsigned i = 0; i < I.getWidth(); i += 20) {
322  ip1.set_i(0);
323  ip1.set_j(i);
324  ip2.set_i(I.getWidth());
325  ip2.set_j(i);
327  }
328 
329  // Display a transparent rectangle
330  ip.set_i(I.getHeight() - 45);
331  ip.set_j(-10);
332  vpDisplay::displayRectangle(I, ip, 60, 80, vpColor(vpColor::orange, 127), true, 2U);
333 
334  // Display a transparent circle onto the image
335  vpColor transparent_red(vpColor::red, 127);
336  vpDisplay::displayCircle(I, vpImagePoint(I.getHeight() / 3, I.getWidth() / 2), I.getHeight() / 4, transparent_red,
337  true);
338 
339  // Display a second transparent circle
340  vpColor very_transparent_blue(0, 0, 255, 63);
341  vpDisplay::displayCircle(I, vpImagePoint(2 * I.getHeight() / 3, I.getWidth() / 2), I.getHeight() / 4,
342  very_transparent_blue, true);
343 
344  // Display in overlay a blue arrow
345  ip1.set_i(0);
346  ip1.set_j(0);
347  ip2.set_i(100);
348  ip2.set_j(100);
350 
351  // Display in overlay some circles. The position of the center is 200,
352  // 200 the radius is increased by 20 pixels for each circle
353 
354  for (unsigned int i = 0; i < 100; i += 20) {
355  ip.set_i(80);
356  ip.set_j(80);
358  }
359 
360  ip.set_i(-10);
361  ip.set_j(300);
363 
364  // Display in overlay a yellow string
365  ip.set_i(85);
366  ip.set_j(100);
367  vpDisplay::displayText(I, ip, "ViSP is a marvelous software", vpColor::yellow);
368  // Flush the display
369  vpDisplay::flush(I);
370 
371  // Create a color image
372  vpImage<vpRGBa> Ioverlay;
373  // Updates the color image with the original loaded image and the
374  // overlay
375  vpDisplay::getImage(I, Ioverlay);
376 
377  // Write the color image on the disk
378  filename = vpIoTools::createFilePath(odirname, "Klimt_grey.overlay.ppm");
379  vpImageIo::write(Ioverlay, filename);
380 
381  // If click is allowed, wait for a mouse click to close the display
382  if (opt_click_allowed) {
383  std::cout << "\nA click to close the windows..." << std::endl;
384  // Wait for a blocking mouse click
386  }
387 
388  // Close the display
389  vpDisplay::close(I);
390  }
391 
392  // Create a color image
393  vpImage<vpRGBa> Irgba;
394 
395  // Load a grey image from the disk and convert it to a color image
396  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.ppm");
397  vpImageIo::read(Irgba, filename);
398 
399  // Create a new display
400  vpDisplayOpenCV displayRGBa;
401 
402  if (opt_display) {
403  // For this color image, open a X11 display at position 100,100
404  // in the screen, and with title "X11 color display"
405  displayRGBa.init(Irgba, 100, 100, "X11 color display");
406 
407  // Display the color image
408  vpDisplay::display(Irgba);
409  vpDisplay::flush(Irgba);
410 
411  // If click is allowed, wait for a blocking mouse click to display a
412  // cross at the clicked pixel position
413  if (opt_click_allowed) {
414  std::cout << "\nA click to display a cross..." << std::endl;
415  // Blocking wait for a click. Get the position of the selected pixel
416  // (i correspond to the row and j to the column coordinates in the
417  // image)
418  vpDisplay::getClick(Irgba, ip);
419  // Display a red cross on the click pixel position
420  std::cout << "Cross position: " << ip << std::endl;
421  vpDisplay::displayCross(Irgba, ip, 15, vpColor::red);
422  }
423  else {
424  ip.set_i(10);
425  ip.set_j(20);
426  // Display a red cross at position i, j (i correspond to the row
427  // and j to the column coordinates in the image)
428  std::cout << "Cross position: " << ip << std::endl;
429  vpDisplay::displayCross(Irgba, ip, 15, vpColor::red);
430  }
431  // Flush the display. Sometimes the display content is
432  // bufferized. Force to display the content that has been bufferized.
433  vpDisplay::flush(Irgba);
434 
435  // Create a color image
436  vpImage<vpRGBa> Ioverlay;
437  // Updates the color image with the original loaded image and the
438  // overlay
439  vpDisplay::getImage(Irgba, Ioverlay);
440 
441  // Write the color image on the disk
442  filename = vpIoTools::createFilePath(odirname, "Klimt_color.overlay.ppm");
443  vpImageIo::write(Ioverlay, filename);
444 
445  // If click is allowed, wait for a blocking mouse click to exit.
446  if (opt_click_allowed) {
447  std::cout << "\nA click to exit the program..." << std::endl;
448  vpDisplay::getClick(Irgba);
449  std::cout << "Bye" << std::endl;
450  }
451  }
452  return EXIT_SUCCESS;
453  }
454  catch (const vpException &e) {
455  std::cout << "Catch an exception: " << e << std::endl;
456  return EXIT_FAILURE;
457  }
458 }
459 #else
460 int main()
461 {
462  std::cout << "You do not have OpenCV functionalities to display images..." << std::endl;
463  std::cout << "Tip:" << std::endl;
464  std::cout << "- Install OpenCV, configure again ViSP using cmake and build again this example" << std::endl;
465  return EXIT_SUCCESS;
466  }
467 #endif
Class to define RGB colors available for display functionalities.
Definition: vpColor.h:157
static const vpColor red
Definition: vpColor.h:217
static const vpColor orange
Definition: vpColor.h:227
static const vpColor blue
Definition: vpColor.h:223
static const vpColor yellow
Definition: vpColor.h:225
static const vpColor green
Definition: vpColor.h:220
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="") VP_OVERRIDE
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void displayCircle(const vpImage< unsigned char > &I, const vpImageCircle &circle, const vpColor &color, bool fill=false, unsigned int thickness=1)
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 getImage(const vpImage< unsigned char > &Is, vpImage< vpRGBa > &Id)
Definition: vpDisplay.cpp:140
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, unsigned int thickness=1)
static void close(vpImage< unsigned char > &I)
static void flush(const vpImage< unsigned char > &I)
static void displayArrow(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color=vpColor::white, unsigned int w=4, unsigned int h=2, unsigned int thickness=1)
static void displayDotLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1)
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:60
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:147
static void write(const vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:291
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
void set_j(double jj)
Definition: vpImagePoint.h:309
void set_i(double ii)
Definition: vpImagePoint.h:298
unsigned int getWidth() const
Definition: vpImage.h:242
unsigned int getHeight() const
Definition: vpImage.h:181
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1053
static bool checkDirectory(const std::string &dirname)
Definition: vpIoTools.cpp:396
static std::string getUserName()
Definition: vpIoTools.cpp:285
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1427
static void makeDirectory(const std::string &dirname)
Definition: vpIoTools.cpp:550
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:70