Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
displayXMulti.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 <visp3/core/vpConfig.h>
45 #include <visp3/core/vpDebug.h>
46 
47 #ifdef VISP_HAVE_X11
48 
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <visp3/core/vpImage.h>
53 #include <visp3/gui/vpDisplayX.h>
54 #include <visp3/io/vpImageIo.h>
55 
56 #include <visp3/core/vpIoTools.h>
57 #include <visp3/io/vpParseArgv.h>
58 
69 // List of allowed command line options
70 #define GETOPTARGS "cdi:o:h"
71 
72 #ifdef ENABLE_VISP_NAMESPACE
73 using namespace VISP_NAMESPACE_NAME;
74 #endif
75 
87 void usage(const char *name, const char *badparam, std::string ipath, std::string opath, std::string user)
88 {
89  fprintf(stdout, "\n\
90 Read an image on the disk, display it using X11, display some\n\
91 features (line, circle, characters) in overlay and finally write \n\
92 the image and the overlayed features in an image on the disk.\n\
93 \n\
94 SYNOPSIS\n\
95  %s [-i <input image path>] [-o <output image path>]\n\
96  [-c] [-d] [-h]\n\
97 ",
98 name);
99 
100  fprintf(stdout, "\n\
101 OPTIONS: Default\n\
102  -i <input image path> %s\n\
103  Set image input path.\n\
104  From this path read \"Klimt/Klimt.pgm\"\n\
105  and \"Klimt/Klimt.ppm\" images.\n\
106  Setting the VISP_INPUT_IMAGE_PATH environment\n\
107  variable produces the same behaviour than using\n\
108  this option.\n\
109 \n\
110  -o <output image path> %s\n\
111  Set image output path.\n\
112  From this directory, creates the \"%s\"\n\
113  subdirectory depending on the username, where \n\
114  Klimt_grey.overlay.ppm output image is written.\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  Disable the image display. This can be useful \n\
122  for automatic tests using crontab under Unix or \n\
123  using the task manager under Windows.\n\
124 \n\
125  -h\n\
126  Print the help.\n\n",
127  ipath.c_str(), opath.c_str(), user.c_str());
128 
129  if (badparam) {
130  fprintf(stderr, "ERROR: \n");
131  fprintf(stderr, "\nBad parameter [%s]\n", badparam);
132  }
133 }
134 
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 two color images
278  vpImage<vpRGBa> I1, I2;
279  vpImagePoint ip, ip1, ip2;
280 
281  try {
282  // Load a grey image from the disk
283  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.pgm");
284  vpImageIo::read(I1, filename);
285  }
286  catch (...) {
287  std::cerr << std::endl << "ERROR:" << std::endl;
288  std::cerr << " Cannot read " << filename << std::endl;
289  std::cerr << " Check your -i " << ipath << " option " << std::endl
290  << " or VISP_INPUT_IMAGE_PATH environment variable." << std::endl;
291  return EXIT_FAILURE;
292  }
293  try {
294  // Load a color image from the disk
295  filename = vpIoTools::createFilePath(ipath, "Klimt/Klimt.ppm");
296  vpImageIo::read(I2, filename);
297  }
298  catch (...) {
299  std::cerr << std::endl << "ERROR:" << std::endl;
300  std::cerr << " Cannot read " << filename << std::endl;
301  std::cerr << " Check your -i " << ipath << " option " << std::endl
302  << " or VISP_INPUT_IMAGE_PATH environment variable." << std::endl;
303  return EXIT_FAILURE;
304  }
305 
306  // For each image, open a X11 display
307  vpDisplayX display1;
308  vpDisplayX display2;
309 
310  if (opt_display) {
311  // Attach image 1 to display 1
312  display1.init(I1, 0, 0, "X11 Display 1...");
313  // Attach image 2 to display 2
314  display2.init(I2, 200, 200, "X11 Display 2...");
315  // Display the images
316  vpDisplay::display(I1);
317  vpDisplay::display(I2);
318 
319  // In the first display, display in overlay horizontal red lines
320  for (unsigned int i = 0; i < I1.getHeight(); i += 20) {
321  ip1.set_i(i);
322  ip1.set_j(0);
323  ip2.set_i(i);
324  ip2.set_j(I1.getWidth());
325  vpDisplay::displayLine(I1, ip1, ip2, vpColor::red);
326  }
327 
328  // In the first display, display in overlay vertical green dot lines
329  for (unsigned int i = 0; i < I1.getWidth(); i += 20) {
330  ip1.set_i(0);
331  ip1.set_j(i);
332  ip2.set_i(I1.getWidth());
333  ip2.set_j(i);
335  }
336 
337  // In the first display, display in overlay a blue arrow
338  ip1.set_i(0);
339  ip1.set_j(0);
340  ip2.set_i(100);
341  ip2.set_j(100);
342  vpDisplay::displayArrow(I1, ip1, ip2, vpColor::blue);
343 
344  // In the first display, display in overlay some circles. The
345  // position of the center is 200, 200 the radius is increased by 20
346  // pixels for each circle
347  for (unsigned int i = 0; i < 100; i += 20) {
348  ip.set_i(200);
349  ip.set_j(200);
350  vpDisplay::displayCircle(I1, ip, 20 + i, vpColor::yellow);
351  }
352 
353  // In the first display, display in overlay a yellow string
354  ip.set_i(100);
355  ip.set_j(100);
356  vpDisplay::displayText(I1, ip, "ViSP is a marvelous software", vpColor::blue);
357 
358  // Flush displays. The displays must be flushed to show the overlay.
359  // without this line, nothing will be displayed.
360  vpDisplay::flush(I1);
361  vpDisplay::flush(I2);
362 
363  // If click is allowed, wait for a blocking mouse click in the first
364  // display, to display a cross at the clicked pixel position
365  if (opt_click_allowed) {
366  std::cout << "\nA click in the first display to draw a cross..." << std::endl;
367  // Blocking wait for a click. Get the position of the selected pixel
368  // (i correspond to the row and j to the column coordinates in the
369  // image)
370  vpDisplay::getClick(I1, ip);
371  // Display a red cross on the click pixel position
372  std::cout << "Cross position: " << ip << std::endl;
374  vpDisplay::flush(I1);
375  }
376  else {
377  ip.set_i(50);
378  ip.set_j(50);
379  // Display a red cross at position ip in the first display
380  std::cout << "Cross position: " << ip << std::endl;
382  vpDisplay::flush(I1);
383  }
384 
385  // Create a color image
386  vpImage<vpRGBa> Ioverlay;
387  // Updates the color image with the original loaded image 1 and the
388  // overlay
389  vpDisplay::getImage(I1, Ioverlay);
390 
391  // Write the color image on the disk
392  filename = vpIoTools::createFilePath(odirname, "Klimt_grey.overlay.ppm");
393  vpImageIo::write(Ioverlay, filename);
394 
395  // If click is allowed, wait for a mouse click to close the display
396  if (opt_click_allowed) {
397  std::cout << "\nA click in the second display to close the windows "
398  "and exit..."
399  << std::endl;
400  // Wait for a blocking mouse click
402  }
403  }
404  return EXIT_SUCCESS;
405  }
406  catch (const vpException &e) {
407  std::cout << "Catch an exception: " << e << std::endl;
408  return EXIT_FAILURE;
409  }
410 }
411 #else
412 int main()
413 {
414  std::cout << "You do not have X11 functionalities to display images..." << std::endl;
415  std::cout << "Tip if you are on a unix-like system:" << std::endl;
416  std::cout << "- Install X11, configure again ViSP using cmake and build again this example" << std::endl;
417  return EXIT_SUCCESS;
418  }
419 #endif
static const vpColor red
Definition: vpColor.h:217
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 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 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