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