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