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