Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
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 
69 #ifdef ENABLE_VISP_NAMESPACE
70 using namespace VISP_NAMESPACE_NAME;
71 #endif
72 
84 void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user)
85 {
86  fprintf(stdout, "\n\
87 Read an image on the disk, display it using X11, display some\n\
88 features (line, circle, characters) in overlay and finally write \n\
89 the image and the overlayed features in an image on the disk.\n\
90 \n\
91 SYNOPSIS\n\
92  %s [-i <input image path>] [-o <output image path>]\n\
93  [-c] [-d] [-h]\n \
94 ",
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 human 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",
124  ipath.c_str(), opath.c_str(), user.c_str());
125 
126  if (badparam) {
127  fprintf(stderr, "ERROR: \n");
128  fprintf(stderr, "\nBad parameter [%s]\n", badparam);
129  }
130 }
131 
150 bool getOptions(int argc, const char **argv, std::string &ipath, std::string &opath, bool &click_allowed,
151  const std::string &user, bool &display)
152 {
153  const char *optarg_;
154  int c;
155  while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
156 
157  switch (c) {
158  case 'c':
159  click_allowed = false;
160  break;
161  case 'd':
162  display = false;
163  break;
164  case 'i':
165  ipath = optarg_;
166  break;
167  case 'o':
168  opath = optarg_;
169  break;
170  case 'h':
171  usage(argv[0], nullptr, ipath, opath, user);
172  return false;
173  break;
174 
175  default:
176  usage(argv[0], optarg_, ipath, opath, user);
177  return false;
178  break;
179  }
180  }
181 
182  if ((c == 1) || (c == -1)) {
183  // standalone param or error
184  usage(argv[0], nullptr, ipath, opath, user);
185  std::cerr << "ERROR: " << std::endl;
186  std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
187  return false;
188  }
189 
190  return true;
191 }
192 
193 int main(int argc, const char **argv)
194 {
195  try {
196  std::string env_ipath;
197  std::string opt_ipath;
198  std::string opt_opath;
199  std::string ipath;
200  std::string opath;
201  std::string filename;
202  std::string username;
203  bool opt_click_allowed = true;
204  bool opt_display = true;
205 
206  // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
207  // environment variable value
208  env_ipath = vpIoTools::getViSPImagesDataPath();
209 
210  // Set the default input path
211  if (!env_ipath.empty())
212  ipath = env_ipath;
213 
214  // Set the default output path
215 #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) // UNIX
216  opt_opath = "/tmp";
217 #elif defined(_WIN32)
218  opt_opath = "C:\\temp";
219 #endif
220 
221  // Get the user login name
222  vpIoTools::getUserName(username);
223 
224  // Read the command line options
225  if (getOptions(argc, argv, opt_ipath, opt_opath, opt_click_allowed, username, opt_display) == false) {
226  return EXIT_FAILURE;
227  }
228 
229  // Get the option values
230  if (!opt_ipath.empty())
231  ipath = opt_ipath;
232  if (!opt_opath.empty())
233  opath = opt_opath;
234 
235  // Append to the output path string, the login name of the user
236  std::string odirname = vpIoTools::createFilePath(opath, username);
237 
238  // Test if the output path exist. If no try to create it
239  if (vpIoTools::checkDirectory(odirname) == false) {
240  try {
241  // Create the dirname
242  vpIoTools::makeDirectory(odirname);
243  }
244  catch (...) {
245  usage(argv[0], nullptr, ipath, opath, username);
246  std::cerr << std::endl << "ERROR:" << std::endl;
247  std::cerr << " Cannot create " << odirname << std::endl;
248  std::cerr << " Check your -o " << opath << " option " << std::endl;
249  return EXIT_FAILURE;
250  }
251  }
252 
253  // Compare ipath and env_ipath. If they differ, we take into account
254  // the input path coming from the command line option
255  if (!opt_ipath.empty() && !env_ipath.empty()) {
256  if (ipath != env_ipath) {
257  std::cout << std::endl << "WARNING: " << std::endl;
258  std::cout << " Since -i <visp image path=" << ipath << "> "
259  << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
260  << " we skip the environment variable." << std::endl;
261  }
262  }
263 
264  // Test if an input path is set
265  if (opt_ipath.empty() && env_ipath.empty()) {
266  usage(argv[0], nullptr, ipath, opath, username);
267  std::cerr << std::endl << "ERROR:" << std::endl;
268  std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
269  << " environment variable to specify the location of the " << std::endl
270  << " image path where test images are located." << std::endl
271  << std::endl;
272  return EXIT_FAILURE;
273  }
274 
275  // Create a grey level image
277  vpImagePoint ip, ip1, ip2;
278 
279  // Load a grey image from the disk
280  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
281  vpImageIo::read(I, filename);
282 
283  // Create a display using X11
284  vpDisplayX display;
285 
286  if (opt_display) {
287  // For this grey level image, open a X11 display at position 100,100
288  // in the screen, and with title "X11 display"
289  display.init(I, 100, 100, "X11 display");
290 
291  // Display the image
293 
294  // Display in overlay a red cross at position 10,10 in the
295  // image. The lines are 10 pixels long
296  ip.set_i(100);
297  ip.set_j(10);
298 
300 
301  // Display in overlay horizontal red lines
302  for (unsigned i = 0; i < I.getHeight(); i += 20) {
303  ip1.set_i(i);
304  ip1.set_j(0);
305  ip2.set_i(i);
306  ip2.set_j(I.getWidth());
307  vpDisplay::displayLine(I, ip1, ip2, vpColor::red);
308  }
309 
310  // Display a ligne in the diagonal
311  ip1.set_i(-10);
312  ip1.set_j(-10);
313  ip2.set_i(I.getHeight() + 10);
314  ip2.set_j(I.getWidth() + 10);
315 
316  vpDisplay::displayLine(I, ip1, ip2, vpColor::red);
317 
318  // Display in overlay vertical green dot lines
319  for (unsigned i = 0; i < I.getWidth(); i += 20) {
320  ip1.set_i(0);
321  ip1.set_j(i);
322  ip2.set_i(I.getWidth());
323  ip2.set_j(i);
325  }
326 
327  // Display a rectangle
328  ip.set_i(I.getHeight() - 45);
329  ip.set_j(-10);
331 
332  // Display in overlay a blue arrow
333  ip1.set_i(0);
334  ip1.set_j(0);
335  ip2.set_i(100);
336  ip2.set_j(100);
338 
339  // Display in overlay some circles. The position of the center is 200,
340  // 200 the radius is increased by 20 pixels for each circle
341 
342  for (unsigned int i = 0; i < 100; i += 20) {
343  ip.set_i(80);
344  ip.set_j(80);
346  }
347 
348  ip.set_i(-10);
349  ip.set_j(300);
351 
352  // Display in overlay a yellow string
353  ip.set_i(85);
354  ip.set_j(100);
355  vpDisplay::displayText(I, ip, "ViSP is a marvelous software", vpColor::yellow);
356  // Flush the display
357  vpDisplay::flush(I);
358 
359  // Create a color image
360  vpImage<vpRGBa> Ioverlay;
361  // Updates the color image with the original loaded image and the
362  // overlay
363  vpDisplay::getImage(I, Ioverlay);
364 
365  // Write the color image on the disk
366  filename = vpIoTools::createFilePath(odirname, "Klimt_grey.overlay.ppm");
367  vpImageIo::write(Ioverlay, filename);
368 
369  // If click is allowed, wait for a mouse click to close the display
370  if (opt_click_allowed) {
371  std::cout << "\nA click to close the windows..." << std::endl;
372  // Wait for a blocking mouse click
374  }
375 
376  // Close the display
377  vpDisplay::close(I);
378  }
379 
380  // Create a color image
381  vpImage<vpRGBa> Irgba;
382 
383  // Load a grey image from the disk and convert it to a color image
384  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.ppm");
385  vpImageIo::read(Irgba, filename);
386 
387  // Create a new display
388  vpDisplayX displayRGBa;
389 
390  if (opt_display) {
391  // For this color image, open a X11 display at position 100,100
392  // in the screen, and with title "X11 color display"
393  displayRGBa.init(Irgba, 100, 100, "X11 color display");
394 
395  // Display the color image
396  vpDisplay::display(Irgba);
397  vpDisplay::flush(Irgba);
398 
399  // If click is allowed, wait for a blocking mouse click to display a
400  // cross at the clicked pixel position
401  if (opt_click_allowed) {
402  std::cout << "\nA click to display a cross..." << std::endl;
403  // Blocking wait for a click. Get the position of the selected pixel
404  // (i correspond to the row and j to the column coordinates in the
405  // image)
406  vpDisplay::getClick(Irgba, ip);
407  // Display a red cross on the click pixel position
408  std::cout << "Cross position: " << ip << std::endl;
409  vpDisplay::displayCross(Irgba, ip, 15, vpColor::red);
410  }
411  else {
412  ip.set_i(10);
413  ip.set_j(20);
414  // Display a red cross at position i, j (i correspond to the row
415  // and j to the column coordinates in the image)
416  std::cout << "Cross position: " << ip << std::endl;
417  vpDisplay::displayCross(Irgba, ip, 15, vpColor::red);
418  }
419  // Flush the display. Sometimes the display content is
420  // bufferized. Force to display the content that has been bufferized.
421  vpDisplay::flush(Irgba);
422 
423  // Create a color image
424  vpImage<vpRGBa> Ioverlay;
425  // Updates the color image with the original loaded image and the
426  // overlay
427  vpDisplay::getImage(Irgba, Ioverlay);
428 
429  // Write the color image on the disk
430  filename = vpIoTools::createFilePath(odirname, "Klimt_color.overlay.ppm");
431  vpImageIo::write(Ioverlay, filename);
432 
433  // If click is allowed, wait for a blocking mouse click to exit.
434  if (opt_click_allowed) {
435  std::cout << "\nA click to exit the program..." << std::endl;
436  vpDisplay::getClick(Irgba);
437  std::cout << "Bye" << std::endl;
438  }
439  }
440  return EXIT_SUCCESS;
441  }
442  catch (const vpException &e) {
443  std::cout << "Catch an exception: " << e << std::endl;
444  return EXIT_FAILURE;
445  }
446 }
447 #else
448 int main()
449 {
450  std::cout << "You do not have X11 functionalities to display images..." << 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  return EXIT_SUCCESS;
454  }
455 #endif
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
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