Point Cloud Library (PCL)  1.7.1
image_viewer.h
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2012, Willow Garage, Inc.
6  * Copyright (c) 2012-, Open Perception, Inc.
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of the copyright holder(s) nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  */
38 
39 #ifndef PCL_VISUALIZATION_IMAGE_VISUALIZER_H__
40 #define PCL_VISUALIZATION_IMAGE_VISUALIZER_H__
41 
42 #include <pcl/pcl_macros.h>
43 #include <pcl/point_types.h>
44 #include <pcl/console/print.h>
45 #include <pcl/visualization/interactor.h>
46 #include <pcl/visualization/interactor_style.h>
47 #include <pcl/visualization/vtk/pcl_image_canvas_source_2d.h>
48 #include <pcl/visualization/vtk/pcl_context_item.h>
49 #include <pcl/geometry/planar_polygon.h>
50 #include <pcl/correspondence.h>
51 
52 #include <boost/shared_array.hpp>
53 
54 #include <vtkInteractorStyleImage.h>
55 
56 class vtkImageSlice;
57 class vtkContextActor;
58 class vtkImageViewer;
59 class vtkImageFlip;
60 
61 namespace pcl
62 {
63  namespace visualization
64  {
65  typedef Eigen::Array<unsigned char, 3, 1> Vector3ub;
66  static const Vector3ub green_color (0, 255, 0);
67  static const Vector3ub red_color (255, 0, 0);
68  static const Vector3ub blue_color (0, 0, 255);
69 
70  /** \brief An image viewer interactor style, tailored for ImageViewer.
71  * \author Radu B. Rusu
72  * \ingroup visualization
73  */
74  class PCL_EXPORTS ImageViewerInteractorStyle : public vtkInteractorStyleImage
75  {
76  public:
77  static ImageViewerInteractorStyle *New ();
79 
80  virtual void OnMouseWheelForward () {}
81  virtual void OnMouseWheelBackward () {}
82  virtual void OnMiddleButtonDown () {}
83  virtual void OnRightButtonDown () {}
84  virtual void OnLeftButtonDown ();
85 
86  virtual void
87  OnChar ();
88 
89  void
90  adjustCamera (vtkImageData *image, vtkRenderer *ren);
91 
92  void
93  adjustCamera (vtkRenderer *ren);
94  };
95 
96  /** \brief ImageViewer is a class for 2D image visualization.
97  *
98  * Features include:
99  * - add and remove different layers with different opacity (transparency) values
100  * - add 2D geometric shapes (circles, boxes, etc) in separate layers
101  * - display RGB, monochrome, float, angle images
102  *
103  * Simple usage example:
104  * \code
105  * pcl::visualization::ImageViewer iv;
106  * iv.addCircle (10, 10, 5, 1.0, 0.0, 0.0, "circles", 1.0); // add a red, fully opaque circle with radius 5 pixels at (10,10) in layer "circles"
107  * iv.addFilledRectangle (10, 20, 10, 20, 0.0, 1.0, 0.0, "boxes", 0.5); // add a green, 50% transparent box at (10,10->20,20) in layer "boxes"
108  * iv.addRGBImage<pcl::PointXYZRGBA> (cloud); // add a RGB image from a point cloud dataset in an "rgb_image" default layer
109  * iv.spin (); // press 'q' to exit
110  * iv.removeLayer ("circles"); // remove layer "circles"
111  * iv.spin (); // press 'q' to exit
112  * \endcode
113  *
114  * \author Radu B. Rusu, Suat Gedikli
115  * \ingroup visualization
116  */
117  class PCL_EXPORTS ImageViewer
118  {
119  public:
120  typedef boost::shared_ptr<ImageViewer> Ptr;
121 
122  /** \brief Constructor.
123  * \param[in] window_title the title of the window
124  */
125  ImageViewer (const std::string& window_title = "");
126 
127  /** \brief Destructor. */
128  virtual ~ImageViewer ();
129 
130 #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION > 4)))
131  /** \brief Set up the interactor style. By default the interactor style is set to
132  * vtkInteractorStyleImage you can use this to set it to another type.
133  * \param[in] style user set interactor style.
134  */
135  void
136  setInteractorStyle (vtkInteractorObserver *style)
137  {
138  interactor_->SetInteractorStyle (style);
139  }
140 #endif
141  /** \brief Show a monochrome 2D image on screen.
142  * \param[in] data the input data representing the image
143  * \param[in] width the width of the image
144  * \param[in] height the height of the image
145  * \param[in] layer_id the name of the layer (default: "image")
146  * \param[in] opacity the opacity of the layer (default: 1.0)
147  */
148  void
149  showMonoImage (const unsigned char* data, unsigned width, unsigned height,
150  const std::string &layer_id = "mono_image", double opacity = 1.0);
151 
152  /** \brief Add a monochrome 2D image layer, but do not render it (use spin/spinOnce to update).
153  * \param[in] data the input data representing the image
154  * \param[in] width the width of the image
155  * \param[in] height the height of the image
156  * \param[in] layer_id the name of the layer (default: "image")
157  * \param[in] opacity the opacity of the layer (default: 1.0)
158  */
159  void
160  addMonoImage (const unsigned char* data, unsigned width, unsigned height,
161  const std::string &layer_id = "mono_image", double opacity = 1.0);
162 
163  /** \brief Show a monochrome 2D image on screen.
164  * \param[in] cloud the input data representing the grayscale point cloud
165  * \param[in] layer_id the name of the layer (default: "image")
166  * \param[in] opacity the opacity of the layer (default: 1.0)
167  */
168  inline void
170  const std::string &layer_id = "mono_image", double opacity = 1.0)
171  {
172  return (showMonoImage (*cloud, layer_id, opacity));
173  }
174 
175  /** \brief Add a monochrome 2D image layer, but do not render it (use spin/spinOnce to update).
176  * \param[in] cloud the input data representing the grayscale point cloud
177  * \param[in] layer_id the name of the layer (default: "image")
178  * \param[in] opacity the opacity of the layer (default: 1.0)
179  */
180  inline void
182  const std::string &layer_id = "mono_image", double opacity = 1.0)
183  {
184  return (addMonoImage (*cloud, layer_id, opacity));
185  }
186 
187  /** \brief Show a monochrome 2D image on screen.
188  * \param[in] cloud the input data representing the grayscale point cloud
189  * \param[in] layer_id the name of the layer (default: "image")
190  * \param[in] opacity the opacity of the layer (default: 1.0)
191  */
192  void
193  showMonoImage (const pcl::PointCloud<pcl::Intensity> &cloud,
194  const std::string &layer_id = "mono_image", double opacity = 1.0);
195 
196  /** \brief Add a monochrome 2D image layer, but do not render it (use spin/spinOnce to update).
197  * \param[in] cloud the input data representing the RGB point cloud
198  * \param[in] layer_id the name of the layer (default: "image")
199  * \param[in] opacity the opacity of the layer (default: 1.0)
200  */
201  void
202  addMonoImage (const pcl::PointCloud<pcl::Intensity> &cloud,
203  const std::string &layer_id = "mono_image", double opacity = 1.0);
204 
205  /** \brief Show a monochrome 2D image on screen.
206  * \param[in] cloud the input data representing the grayscale point cloud
207  * \param[in] layer_id the name of the layer (default: "image")
208  * \param[in] opacity the opacity of the layer (default: 1.0)
209  */
210  inline void
212  const std::string &layer_id = "mono_image", double opacity = 1.0)
213  {
214  return (showMonoImage (*cloud, layer_id, opacity));
215  }
216 
217  /** \brief Add a monochrome 2D image layer, but do not render it (use spin/spinOnce to update).
218  * \param[in] cloud the input data representing the grayscale point cloud
219  * \param[in] layer_id the name of the layer (default: "image")
220  * \param[in] opacity the opacity of the layer (default: 1.0)
221  */
222  inline void
224  const std::string &layer_id = "mono_image", double opacity = 1.0)
225  {
226  return (addMonoImage (*cloud, layer_id, opacity));
227  }
228 
229  /** \brief Show a monochrome 2D image on screen.
230  * \param[in] cloud the input data representing the grayscale point cloud
231  * \param[in] layer_id the name of the layer (default: "image")
232  * \param[in] opacity the opacity of the layer (default: 1.0)
233  */
234  void
235  showMonoImage (const pcl::PointCloud<pcl::Intensity8u> &cloud,
236  const std::string &layer_id = "mono_image", double opacity = 1.0);
237 
238  /** \brief Add a monochrome 2D image layer, but do not render it (use spin/spinOnce to update).
239  * \param[in] cloud the input data representing the RGB point cloud
240  * \param[in] layer_id the name of the layer (default: "image")
241  * \param[in] opacity the opacity of the layer (default: 1.0)
242  */
243  void
244  addMonoImage (const pcl::PointCloud<pcl::Intensity8u> &cloud,
245  const std::string &layer_id = "mono_image", double opacity = 1.0);
246 
247  /** \brief Show a 2D RGB image on screen.
248  * \param[in] data the input data representing the image
249  * \param[in] width the width of the image
250  * \param[in] height the height of the image
251  * \param[in] layer_id the name of the layer (default: "image")
252  * \param[in] opacity the opacity of the layer (default: 1.0)
253  */
254  void
255  showRGBImage (const unsigned char* data, unsigned width, unsigned height,
256  const std::string &layer_id = "rgb_image", double opacity = 1.0);
257 
258  /** \brief Add an RGB 2D image layer, but do not render it (use spin/spinOnce to update).
259  * \param[in] data the input data representing the image
260  * \param[in] width the width of the image
261  * \param[in] height the height of the image
262  * \param[in] layer_id the name of the layer (default: "image")
263  * \param[in] opacity the opacity of the layer (default: 1.0)
264  */
265  void
266  addRGBImage (const unsigned char* data, unsigned width, unsigned height,
267  const std::string &layer_id = "rgb_image", double opacity = 1.0);
268 
269  /** \brief Show a 2D image on screen, obtained from the RGB channel of a point cloud.
270  * \param[in] cloud the input data representing the RGB point cloud
271  * \param[in] layer_id the name of the layer (default: "image")
272  * \param[in] opacity the opacity of the layer (default: 1.0)
273  */
274  template <typename T> inline void
276  const std::string &layer_id = "rgb_image", double opacity = 1.0)
277  {
278  return (showRGBImage<T> (*cloud, layer_id, opacity));
279  }
280 
281  /** \brief Add an RGB 2D image layer, but do not render it (use spin/spinOnce to update).
282  * \param[in] cloud the input data representing the RGB point cloud
283  * \param[in] layer_id the name of the layer (default: "image")
284  * \param[in] opacity the opacity of the layer (default: 1.0)
285  */
286  template <typename T> inline void
288  const std::string &layer_id = "rgb_image", double opacity = 1.0)
289  {
290  return (addRGBImage<T> (*cloud, layer_id, opacity));
291  }
292 
293  /** \brief Show a 2D image on screen, obtained from the RGB channel of a point cloud.
294  * \param[in] cloud the input data representing the RGB point cloud
295  * \param[in] layer_id the name of the layer (default: "image")
296  * \param[in] opacity the opacity of the layer (default: 1.0)
297  */
298  template <typename T> void
299  showRGBImage (const pcl::PointCloud<T> &cloud,
300  const std::string &layer_id = "rgb_image", double opacity = 1.0);
301 
302  /** \brief Add an RGB 2D image layer, but do not render it (use spin/spinOnce to update).
303  * \param[in] cloud the input data representing the RGB point cloud
304  * \param[in] layer_id the name of the layer (default: "image")
305  * \param[in] opacity the opacity of the layer (default: 1.0)
306  */
307  template <typename T> void
308  addRGBImage (const pcl::PointCloud<T> &cloud,
309  const std::string &layer_id = "rgb_image", double opacity = 1.0);
310 
311  /** \brief Show a 2D image (float) on screen.
312  * \param[in] data the input data representing the image in float format
313  * \param[in] width the width of the image
314  * \param[in] height the height of the image
315  * \param[in] min_value filter all values in the image to be larger than this minimum value
316  * \param[in] max_value filter all values in the image to be smaller than this maximum value
317  * \param[in] grayscale show data as grayscale (true) or not (false). Default: false
318  * \param[in] layer_id the name of the layer (default: "image")
319  * \param[in] opacity the opacity of the layer (default: 1.0)
320  */
321  void
322  showFloatImage (const float* data, unsigned int width, unsigned int height,
323  float min_value = std::numeric_limits<float>::min (),
324  float max_value = std::numeric_limits<float>::max (), bool grayscale = false,
325  const std::string &layer_id = "float_image", double opacity = 1.0);
326 
327  /** \brief Add a float 2D image layer, but do not render it (use spin/spinOnce to update).
328  * \param[in] data the input data representing the image in float format
329  * \param[in] width the width of the image
330  * \param[in] height the height of the image
331  * \param[in] min_value filter all values in the image to be larger than this minimum value
332  * \param[in] max_value filter all values in the image to be smaller than this maximum value
333  * \param[in] grayscale show data as grayscale (true) or not (false). Default: false
334  * \param[in] layer_id the name of the layer (default: "image")
335  * \param[in] opacity the opacity of the layer (default: 1.0)
336  */
337  void
338  addFloatImage (const float* data, unsigned int width, unsigned int height,
339  float min_value = std::numeric_limits<float>::min (),
340  float max_value = std::numeric_limits<float>::max (), bool grayscale = false,
341  const std::string &layer_id = "float_image", double opacity = 1.0);
342 
343  /** \brief Show a 2D image (unsigned short) on screen.
344  * \param[in] short_image the input data representing the image in unsigned short format
345  * \param[in] width the width of the image
346  * \param[in] height the height of the image
347  * \param[in] min_value filter all values in the image to be larger than this minimum value
348  * \param[in] max_value filter all values in the image to be smaller than this maximum value
349  * \param[in] grayscale show data as grayscale (true) or not (false). Default: false
350  * \param[in] layer_id the name of the layer (default: "image")
351  * \param[in] opacity the opacity of the layer (default: 1.0)
352  */
353  void
354  showShortImage (const unsigned short* short_image, unsigned int width, unsigned int height,
355  unsigned short min_value = std::numeric_limits<unsigned short>::min (),
356  unsigned short max_value = std::numeric_limits<unsigned short>::max (), bool grayscale = false,
357  const std::string &layer_id = "short_image", double opacity = 1.0);
358 
359  /** \brief Add a short 2D image layer, but do not render it (use spin/spinOnce to update).
360  * \param[in] short_image the input data representing the image in unsigned short format
361  * \param[in] width the width of the image
362  * \param[in] height the height of the image
363  * \param[in] min_value filter all values in the image to be larger than this minimum value
364  * \param[in] max_value filter all values in the image to be smaller than this maximum value
365  * \param[in] grayscale show data as grayscale (true) or not (false). Default: false
366  * \param[in] layer_id the name of the layer (default: "image")
367  * \param[in] opacity the opacity of the layer (default: 1.0)
368  */
369  void
370  addShortImage (const unsigned short* short_image, unsigned int width, unsigned int height,
371  unsigned short min_value = std::numeric_limits<unsigned short>::min (),
372  unsigned short max_value = std::numeric_limits<unsigned short>::max (), bool grayscale = false,
373  const std::string &layer_id = "short_image", double opacity = 1.0);
374 
375  /** \brief Show a 2D image on screen representing angle data.
376  * \param[in] data the input data representing the image
377  * \param[in] width the width of the image
378  * \param[in] height the height of the image
379  * \param[in] layer_id the name of the layer (default: "image")
380  * \param[in] opacity the opacity of the layer (default: 1.0)
381  */
382  void
383  showAngleImage (const float* data, unsigned width, unsigned height,
384  const std::string &layer_id = "angle_image", double opacity = 1.0);
385 
386  /** \brief Add an angle 2D image layer, but do not render it (use spin/spinOnce to update).
387  * \param[in] data the input data representing the image
388  * \param[in] width the width of the image
389  * \param[in] height the height of the image
390  * \param[in] layer_id the name of the layer (default: "image")
391  * \param[in] opacity the opacity of the layer (default: 1.0)
392  */
393  void
394  addAngleImage (const float* data, unsigned width, unsigned height,
395  const std::string &layer_id = "angle_image", double opacity = 1.0);
396 
397  /** \brief Show a 2D image on screen representing half angle data.
398  * \param[in] data the input data representing the image
399  * \param[in] width the width of the image
400  * \param[in] height the height of the image
401  * \param[in] layer_id the name of the layer (default: "image")
402  * \param[in] opacity the opacity of the layer (default: 1.0)
403  */
404  void
405  showHalfAngleImage (const float* data, unsigned width, unsigned height,
406  const std::string &layer_id = "half_angle_image", double opacity = 1.0);
407 
408  /** \brief Add a half angle 2D image layer, but do not render it (use spin/spinOnce to update).
409  * \param[in] data the input data representing the image
410  * \param[in] width the width of the image
411  * \param[in] height the height of the image
412  * \param[in] layer_id the name of the layer (default: "image")
413  * \param[in] opacity the opacity of the layer (default: 1.0)
414  */
415  void
416  addHalfAngleImage (const float* data, unsigned width, unsigned height,
417  const std::string &layer_id = "half_angle_image", double opacity = 1.0);
418 
419  /** \brief Sets the pixel at coordinates(u,v) to color while setting the neighborhood to another
420  * \param[in] u the u/x coordinate of the pixel
421  * \param[in] v the v/y coordinate of the pixel
422  * \param[in] fg_color the pixel color
423  * \param[in] bg_color the neighborhood color
424  * \param[in] radius the circle radius around the pixel
425  * \param[in] layer_id the name of the layer (default: "points")
426  * \param[in] opacity the opacity of the layer (default: 1.0)
427  */
428  void
429  markPoint (size_t u, size_t v, Vector3ub fg_color, Vector3ub bg_color = red_color, double radius = 3.0,
430  const std::string &layer_id = "points", double opacity = 1.0);
431 
432  /** \brief Set the window title name
433  * \param[in] name the window title
434  */
435  void
436  setWindowTitle (const std::string& name);
437 
438  /** \brief Spin method. Calls the interactor and runs an internal loop. */
439  void
440  spin ();
441 
442  /** \brief Spin once method. Calls the interactor and updates the screen once.
443  * \param[in] time - How long (in ms) should the visualization loop be allowed to run.
444  * \param[in] force_redraw - if false it might return without doing anything if the
445  * interactor's framerate does not require a redraw yet.
446  */
447  void
448  spinOnce (int time = 1, bool force_redraw = true);
449 
450  /** \brief Register a callback function for keyboard events
451  * \param[in] callback the function that will be registered as a callback for a keyboard event
452  * \param[in] cookie user data that is passed to the callback
453  * \return a connection object that allows to disconnect the callback function.
454  */
455  boost::signals2::connection
457  void* cookie = NULL)
458  {
459  return (registerKeyboardCallback (boost::bind (callback, _1, cookie)));
460  }
461 
462  /** \brief Register a callback function for keyboard events
463  * \param[in] callback the member function that will be registered as a callback for a keyboard event
464  * \param[in] instance instance to the class that implements the callback function
465  * \param[in] cookie user data that is passed to the callback
466  * \return a connection object that allows to disconnect the callback function.
467  */
468  template<typename T> boost::signals2::connection
469  registerKeyboardCallback (void (T::*callback) (const pcl::visualization::KeyboardEvent&, void*),
470  T& instance, void* cookie = NULL)
471  {
472  return (registerKeyboardCallback (boost::bind (callback, boost::ref (instance), _1, cookie)));
473  }
474 
475  /** \brief Register a callback boost::function for keyboard events
476  * \param[in] cb the boost function that will be registered as a callback for a keyboard event
477  * \return a connection object that allows to disconnect the callback function.
478  */
479  boost::signals2::connection
480  registerKeyboardCallback (boost::function<void (const pcl::visualization::KeyboardEvent&)> cb);
481 
482  /** \brief Register a callback boost::function for mouse events
483  * \param[in] callback the function that will be registered as a callback for a mouse event
484  * \param[in] cookie user data that is passed to the callback
485  * \return a connection object that allows to disconnect the callback function.
486  */
487  boost::signals2::connection
488  registerMouseCallback (void (*callback) (const pcl::visualization::MouseEvent&, void*),
489  void* cookie = NULL)
490  {
491  return (registerMouseCallback (boost::bind (callback, _1, cookie)));
492  }
493 
494  /** \brief Register a callback function for mouse events
495  * \param[in] callback the member function that will be registered as a callback for a mouse event
496  * \param[in] instance instance to the class that implements the callback function
497  * \param[in] cookie user data that is passed to the callback
498  * \return a connection object that allows to disconnect the callback function.
499  */
500  template<typename T> boost::signals2::connection
501  registerMouseCallback (void (T::*callback) (const pcl::visualization::MouseEvent&, void*),
502  T& instance, void* cookie = NULL)
503  {
504  return (registerMouseCallback (boost::bind (callback, boost::ref (instance), _1, cookie)));
505  }
506 
507  /** \brief Register a callback function for mouse events
508  * \param[in] cb the boost function that will be registered as a callback for a mouse event
509  * \return a connection object that allows to disconnect the callback function.
510  */
511  boost::signals2::connection
512  registerMouseCallback (boost::function<void (const pcl::visualization::MouseEvent&)> cb);
513 
514  /** \brief Set the position in screen coordinates.
515  * \param[in] x where to move the window to (X)
516  * \param[in] y where to move the window to (Y)
517  */
518  void
519  setPosition (int x, int y);
520 
521  /** \brief Set the window size in screen coordinates.
522  * \param[in] xw window size in horizontal (pixels)
523  * \param[in] yw window size in vertical (pixels)
524  */
525  void
526  setSize (int xw, int yw);
527 
528  /** \brief Return the window size in pixels. */
529  int*
530  getSize ();
531 
532  /** \brief Returns true when the user tried to close the window */
533  bool
534  wasStopped () const { return (stopped_); }
535 
536  /** \brief Stop the interaction and close the visualizaton window. */
537  void
538  close ()
539  {
540  stopped_ = true;
541  // This tends to close the window...
542 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION <= 4))
543  interactor_->stopLoop ();
544 #else
545  interactor_->TerminateApp ();
546 #endif
547  }
548 
549  /** \brief Add a circle shape from a point and a radius
550  * \param[in] x the x coordinate of the circle center
551  * \param[in] y the y coordinate of the circle center
552  * \param[in] radius the radius of the circle
553  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
554  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
555  */
556  bool
557  addCircle (unsigned int x, unsigned int y, double radius,
558  const std::string &layer_id = "circles", double opacity = 1.0);
559 
560  /** \brief Add a circle shape from a point and a radius
561  * \param[in] x the x coordinate of the circle center
562  * \param[in] y the y coordinate of the circle center
563  * \param[in] radius the radius of the circle
564  * \param[in] r the red channel of the color that the sphere should be rendered with (0.0 -> 1.0)
565  * \param[in] g the green channel of the color that the sphere should be rendered with (0.0 -> 1.0)
566  * \param[in] b the blue channel of the color that the sphere should be rendered with (0.0 -> 1.0)
567  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
568  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
569  */
570  bool
571  addCircle (unsigned int x, unsigned int y, double radius,
572  double r, double g, double b,
573  const std::string &layer_id = "circles", double opacity = 1.0);
574 
575  /** \brief Add a 2D box and color its edges with a given color
576  * \param[in] min_pt the X,Y min coordinate
577  * \param[in] max_pt the X,Y max coordinate
578  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
579  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
580  */
581  bool
582  addRectangle (const pcl::PointXY &min_pt, const pcl::PointXY &max_pt,
583  const std::string &layer_id = "rectangles", double opacity = 1.0);
584 
585  /** \brief Add a 2D box and color its edges with a given color
586  * \param[in] min_pt the X,Y min coordinate
587  * \param[in] max_pt the X,Y max coordinate
588  * \param[in] r the red channel of the color that the box should be rendered with (0.0 -> 1.0)
589  * \param[in] g the green channel of the color that the box should be rendered with (0.0 -> 1.0)
590  * \param[in] b the blue channel of the color that the box should be rendered with (0.0 -> 1.0)
591  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
592  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
593  */
594  bool
595  addRectangle (const pcl::PointXY &min_pt, const pcl::PointXY &max_pt,
596  double r, double g, double b,
597  const std::string &layer_id = "rectangles", double opacity = 1.0);
598 
599  /** \brief Add a 2D box and color its edges with a given color
600  * \param[in] x_min the X min coordinate
601  * \param[in] x_max the X max coordinate
602  * \param[in] y_min the Y min coordinate
603  * \param[in] y_max the Y max coordinate
604  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
605  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
606  */
607  bool
608  addRectangle (unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
609  const std::string &layer_id = "rectangles", double opacity = 1.0);
610 
611  /** \brief Add a 2D box and color its edges with a given color
612  * \param[in] x_min the X min coordinate
613  * \param[in] x_max the X max coordinate
614  * \param[in] y_min the Y min coordinate
615  * \param[in] y_max the Y max coordinate
616  * \param[in] r the red channel of the color that the box should be rendered with (0.0 -> 1.0)
617  * \param[in] g the green channel of the color that the box should be rendered with (0.0 -> 1.0)
618  * \param[in] b the blue channel of the color that the box should be rendered with (0.0 -> 1.0)
619  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
620  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
621  */
622  bool
623  addRectangle (unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
624  double r, double g, double b,
625  const std::string &layer_id = "rectangles", double opacity = 1.0);
626 
627  /** \brief Add a 2D box and color its edges with a given color
628  * \param[in] image the organized point cloud dataset containing the image data
629  * \param[in] min_pt the X,Y min coordinate
630  * \param[in] max_pt the X,Y max coordinate
631  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
632  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
633  */
634  template <typename T> bool
635  addRectangle (const typename pcl::PointCloud<T>::ConstPtr &image,
636  const T &min_pt, const T &max_pt,
637  const std::string &layer_id = "rectangles", double opacity = 1.0);
638 
639  /** \brief Add a 2D box and color its edges with a given color
640  * \param[in] image the organized point cloud dataset containing the image data
641  * \param[in] min_pt the X,Y min coordinate
642  * \param[in] max_pt the X,Y max coordinate
643  * \param[in] r the red channel of the color that the box should be rendered with (0.0 -> 1.0)
644  * \param[in] g the green channel of the color that the box should be rendered with (0.0 -> 1.0)
645  * \param[in] b the blue channel of the color that the box should be rendered with (0.0 -> 1.0)
646  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
647  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
648  */
649  template <typename T> bool
650  addRectangle (const typename pcl::PointCloud<T>::ConstPtr &image,
651  const T &min_pt, const T &max_pt,
652  double r, double g, double b,
653  const std::string &layer_id = "rectangles", double opacity = 1.0);
654 
655  /** \brief Add a 2D box that contains a given image mask and color its edges
656  * \param[in] image the organized point cloud dataset containing the image data
657  * \param[in] mask the point data representing the mask that we want to draw
658  * \param[in] r the red channel of the color that the mask should be rendered with
659  * \param[in] g the green channel of the color that the mask should be rendered with
660  * \param[in] b the blue channel of the color that the mask should be rendered with
661  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
662  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
663  */
664  template <typename T> bool
665  addRectangle (const typename pcl::PointCloud<T>::ConstPtr &image, const pcl::PointCloud<T> &mask,
666  double r, double g, double b,
667  const std::string &layer_id = "rectangles", double opacity = 1.0);
668 
669  /** \brief Add a 2D box that contains a given image mask and color its edges in red
670  * \param[in] image the organized point cloud dataset containing the image data
671  * \param[in] mask the point data representing the mask that we want to draw
672  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
673  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
674  */
675  template <typename T> bool
676  addRectangle (const typename pcl::PointCloud<T>::ConstPtr &image, const pcl::PointCloud<T> &mask,
677  const std::string &layer_id = "image_mask", double opacity = 1.0);
678 
679  /** \brief Add a 2D box and fill it in with a given color
680  * \param[in] x_min the X min coordinate
681  * \param[in] x_max the X max coordinate
682  * \param[in] y_min the Y min coordinate
683  * \param[in] y_max the Y max coordinate
684  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
685  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 0.5)
686  */
687  bool
688  addFilledRectangle (unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
689  const std::string &layer_id = "boxes", double opacity = 0.5);
690 
691  /** \brief Add a 2D box and fill it in with a given color
692  * \param[in] x_min the X min coordinate
693  * \param[in] x_max the X max coordinate
694  * \param[in] y_min the Y min coordinate
695  * \param[in] y_max the Y max coordinate
696  * \param[in] r the red channel of the color that the box should be rendered with (0.0 -> 1.0)
697  * \param[in] g the green channel of the color that the box should be rendered with (0.0 -> 1.0)
698  * \param[in] b the blue channel of the color that the box should be rendered with (0.0 -> 1.0)
699  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
700  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 0.5)
701  */
702  bool
703  addFilledRectangle (unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
704  double r, double g, double b,
705  const std::string &layer_id = "boxes", double opacity = 0.5);
706 
707  /** \brief Add a 2D line with a given color
708  * \param[in] x_min the X min coordinate
709  * \param[in] y_min the Y min coordinate
710  * \param[in] x_max the X max coordinate
711  * \param[in] y_max the Y max coordinate
712  * \param[in] r the red channel of the color that the line should be rendered with (0.0 -> 1.0)
713  * \param[in] g the green channel of the color that the line should be rendered with (0.0 -> 1.0)
714  * \param[in] b the blue channel of the color that the line should be rendered with (0.0 -> 1.0)
715  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
716  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
717  */
718  bool
719  addLine (unsigned int x_min, unsigned int y_min, unsigned int x_max, unsigned int y_max,
720  double r, double g, double b,
721  const std::string &layer_id = "line", double opacity = 1.0);
722 
723  /** \brief Add a 2D line with a given color
724  * \param[in] x_min the X min coordinate
725  * \param[in] y_min the Y min coordinate
726  * \param[in] x_max the X max coordinate
727  * \param[in] y_max the Y max coordinate
728  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
729  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
730  */
731  bool
732  addLine (unsigned int x_min, unsigned int y_min, unsigned int x_max, unsigned int y_max,
733  const std::string &layer_id = "line", double opacity = 1.0);
734 
735  /** \brief Add a 2D text with a given color
736  * \param[in] x the X coordinate
737  * \param[in] y the Y coordinate
738  * \param[in] text the text string to be displayed
739  * \param[in] r the red channel of the color that the line should be rendered with (0.0 -> 1.0)
740  * \param[in] g the green channel of the color that the line should be rendered with (0.0 -> 1.0)
741  * \param[in] b the blue channel of the color that the line should be rendered with (0.0 -> 1.0)
742  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
743  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
744  */
745  bool
746  addText (unsigned int x, unsigned int y, const std::string& text,
747  double r, double g, double b,
748  const std::string &layer_id = "line", double opacity = 1.0);
749 
750  /** \brief Add a 2D text with a given color
751  * \param[in] x the X coordinate
752  * \param[in] y the Y coordinate
753  * \param[in] text the text string to be displayed
754  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
755  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
756  */
757  bool
758  addText (unsigned int x, unsigned int y, const std::string& text,
759  const std::string &layer_id = "line", double opacity = 1.0);
760 
761  /** \brief Add a generic 2D mask to an image
762  * \param[in] image the organized point cloud dataset containing the image data
763  * \param[in] mask the point data representing the mask that we want to draw
764  * \param[in] r the red channel of the color that the mask should be rendered with
765  * \param[in] g the green channel of the color that the mask should be rendered with
766  * \param[in] b the blue channel of the color that the mask should be rendered with
767  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
768  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 0.5)
769  */
770  template <typename T> bool
771  addMask (const typename pcl::PointCloud<T>::ConstPtr &image, const pcl::PointCloud<T> &mask,
772  double r, double g, double b,
773  const std::string &layer_id = "image_mask", double opacity = 0.5);
774 
775  /** \brief Add a generic 2D mask to an image (colored in red)
776  * \param[in] image the organized point cloud dataset containing the image data
777  * \param[in] mask the point data representing the mask that we want to draw
778  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
779  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 0.5)
780  */
781  template <typename T> bool
782  addMask (const typename pcl::PointCloud<T>::ConstPtr &image, const pcl::PointCloud<T> &mask,
783  const std::string &layer_id = "image_mask", double opacity = 0.5);
784 
785  /** \brief Add a generic 2D planar polygon to an image
786  * \param[in] image the organized point cloud dataset containing the image data
787  * \param[in] polygon the point data representing the polygon that we want to draw.
788  * A line will be drawn from each point to the next in the dataset.
789  * \param[in] r the red channel of the color that the polygon should be rendered with
790  * \param[in] g the green channel of the color that the polygon should be rendered with
791  * \param[in] b the blue channel of the color that the polygon should be rendered with
792  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
793  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
794  */
795  template <typename T> bool
796  addPlanarPolygon (const typename pcl::PointCloud<T>::ConstPtr &image, const pcl::PlanarPolygon<T> &polygon,
797  double r, double g, double b,
798  const std::string &layer_id = "planar_polygon", double opacity = 1.0);
799 
800  /** \brief Add a generic 2D planar polygon to an image
801  * \param[in] image the organized point cloud dataset containing the image data
802  * \param[in] polygon the point data representing the polygon that we want to draw.
803  * A line will be drawn from each point to the next in the dataset.
804  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
805  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
806  */
807  template <typename T> bool
808  addPlanarPolygon (const typename pcl::PointCloud<T>::ConstPtr &image, const pcl::PlanarPolygon<T> &polygon,
809  const std::string &layer_id = "planar_polygon", double opacity = 1.0);
810 
811  /** \brief Add a new 2D rendering layer to the viewer.
812  * \param[in] layer_id the name of the layer
813  * \param[in] width the width of the layer
814  * \param[in] height the height of the layer
815  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 0.5)
816  */
817  bool
818  addLayer (const std::string &layer_id, int width, int height, double opacity = 0.5);
819 
820  /** \brief Remove a 2D layer given by its ID.
821  * \param[in] layer_id the name of the layer
822  */
823  void
824  removeLayer (const std::string &layer_id);
825 
826  /** \brief Add the specified correspondences to the display.
827  * \param[in] source_img The source RGB image
828  * \param[in] target_img The target RGB image
829  * \param[in] correspondences The list of correspondences to display.
830  * \param[in] nth display only the Nth correspondence (e.g., skip the rest)
831  * \param[in] layer_id the layer id (default: "correspondences")
832  */
833  template <typename PointT> bool
834  showCorrespondences (const pcl::PointCloud<PointT> &source_img,
835  const pcl::PointCloud<PointT> &target_img,
836  const pcl::Correspondences &correspondences,
837  int nth = 1,
838  const std::string &layer_id = "correspondences");
839 
840  protected:
841  /** \brief Trigger a render call. */
842  void
843  render ();
844 
845  /** \brief Convert the Intensity information in a PointCloud<Intensity> to an unsigned char array
846  * \param[in] cloud the input cloud containing the grayscale intensity information
847  * \param[out] data a boost shared array of unsigned char type
848  * \note The method assumes that the data array has already been allocated and
849  * contains enough space to copy all the data from cloud!
850  */
851  void
852  convertIntensityCloudToUChar (const pcl::PointCloud<pcl::Intensity> &cloud,
853  boost::shared_array<unsigned char> data);
854 
855  /** \brief Convert the Intensity8u information in a PointCloud<Intensity8u> to an unsigned char array
856  * \param[in] cloud the input cloud containing the grayscale intensity information
857  * \param[out] data a boost shared array of unsigned char type
858  * \note The method assumes that the data array has already been allocated and
859  * contains enough space to copy all the data from cloud!
860  */
861  void
862  convertIntensityCloud8uToUChar (const pcl::PointCloud<pcl::Intensity8u> &cloud,
863  boost::shared_array<unsigned char> data);
864 
865  /** \brief Convert the RGB information in a PointCloud<T> to an unsigned char array
866  * \param[in] cloud the input cloud containing the RGB information
867  * \param[out] data a boost shared array of unsigned char type
868  * \note The method assumes that the data array has already been allocated and
869  * contains enough space to copy all the data from cloud!
870  */
871  template <typename T> void
872  convertRGBCloudToUChar (const pcl::PointCloud<T> &cloud,
873  boost::shared_array<unsigned char> &data);
874 
875  /** \brief Set the stopped flag back to false */
876  void
877  resetStoppedFlag () { stopped_ = false; }
878 
879  /** \brief Fire up a mouse event with a specified event ID
880  * \param[int] event_id the id of the event
881  */
882  void
883  emitMouseEvent (unsigned long event_id);
884 
885  /** \brief Fire up a keyboard event with a specified event ID
886  * \param[int] event_id the id of the event
887  */
888  void
889  emitKeyboardEvent (unsigned long event_id);
890 
891  // Callbacks used to register for vtk command
892  static void
893  MouseCallback (vtkObject*, unsigned long eid, void* clientdata, void *calldata);
894  static void
895  KeyboardCallback (vtkObject*, unsigned long eid, void* clientdata, void *calldata);
896 
897  protected: // types
898  struct ExitMainLoopTimerCallback : public vtkCommand
899  {
900  ExitMainLoopTimerCallback () : right_timer_id (), window () {}
901 
903  {
904  return (new ExitMainLoopTimerCallback);
905  }
906  virtual void
907  Execute (vtkObject* vtkNotUsed (caller), unsigned long event_id, void* call_data)
908  {
909  if (event_id != vtkCommand::TimerEvent)
910  return;
911  int timer_id = *static_cast<int*> (call_data);
912  if (timer_id != right_timer_id)
913  return;
914 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION <= 4))
915  window->interactor_->stopLoop ();
916 #else
917  window->interactor_->TerminateApp ();
918 #endif
919  }
922  };
923  struct ExitCallback : public vtkCommand
924  {
925  ExitCallback () : window () {}
926 
927  static ExitCallback* New ()
928  {
929  return (new ExitCallback);
930  }
931  virtual void
932  Execute (vtkObject*, unsigned long event_id, void*)
933  {
934  if (event_id != vtkCommand::ExitEvent)
935  return;
936  window->stopped_ = true;
937 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION <= 4))
938  window->interactor_->stopLoop ();
939 #else
940  window->interactor_->TerminateApp ();
941 #endif
942  }
944  };
945 
946  private:
947  /** \brief Internal structure describing a layer. */
948  struct Layer
949  {
950  Layer () : actor (), layer_name () {}
952  std::string layer_name;
953  };
954 
955  typedef std::vector<Layer> LayerMap;
956 
957  /** \brief Add a new 2D rendering layer to the viewer.
958  * \param[in] layer_id the name of the layer
959  * \param[in] width the width of the layer
960  * \param[in] height the height of the layer
961  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 0.5)
962  * \param[in] fill_box set to true to fill in the image with one black box before starting
963  */
964  LayerMap::iterator
965  createLayer (const std::string &layer_id, int width, int height, double opacity = 0.5, bool fill_box = true);
966 
967  boost::signals2::signal<void (const pcl::visualization::MouseEvent&)> mouse_signal_;
968  boost::signals2::signal<void (const pcl::visualization::KeyboardEvent&)> keyboard_signal_;
969 
970 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION <= 4))
972 #else
974 #endif
976  vtkSmartPointer<vtkCallbackCommand> keyboard_command_;
977 
978  /** \brief Callback object enabling us to leave the main loop, when a timer fires. */
979  vtkSmartPointer<ExitMainLoopTimerCallback> exit_main_loop_timer_callback_;
980  vtkSmartPointer<ExitCallback> exit_callback_;
981 
982  /** \brief The ImageViewer widget. */
983  vtkSmartPointer<vtkImageViewer> image_viewer_;
984 
985  /** \brief The render window. */
987 
988  /** \brief The renderer. */
990 
991 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION >= 10))
992  /** \brief Global prop. This is the actual "actor". */
994 #endif
995  /** \brief The interactor style. */
997 
998  /** \brief The data array representing the image. Used internally. */
999  boost::shared_array<unsigned char> data_;
1000 
1001  /** \brief The data array (representing the image) size. Used internally. */
1002  size_t data_size_;
1003 
1004  /** \brief Set to false if the interaction loop is running. */
1005  bool stopped_;
1006 
1007  /** \brief Global timer ID. Used in destructor only. */
1008  int timer_id_;
1009 
1010  // /** \brief Internal blender used to overlay 2D geometry over the image. */
1011  // vtkSmartPointer<vtkImageBlend> blend_;
1012 
1013  /** \brief Internal list with different 2D layers shapes. */
1014  LayerMap layer_map_;
1015 
1016  /** \brief Image reslice, used for flipping the image. */
1018 
1019  /** \brief Internal data array. Used everytime add***Image is called.
1020  * Cleared, everytime the render loop is executed.
1021  */
1022  std::vector<unsigned char*> image_data_;
1023 
1024  struct LayerComparator
1025  {
1026  LayerComparator (const std::string &str) : str_ (str) {}
1027  const std::string &str_;
1028 
1029  bool
1030  operator () (const Layer &layer)
1031  {
1032  return (layer.layer_name == str_);
1033  }
1034  };
1035 
1036  public:
1037  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
1038  };
1039  }
1040 }
1041 
1042 #include <pcl/visualization/impl/image_viewer.hpp>
1043 
1044 #endif /* __IMAGE_VISUALIZER_H__ */
1045