Point Cloud Library (PCL)  1.7.0
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  /** \brief Show a monochrome 2D image on screen.
131  * \param[in] data the input data representing the image
132  * \param[in] width the width of the image
133  * \param[in] height the height of the image
134  * \param[in] layer_id the name of the layer (default: "image")
135  * \param[in] opacity the opacity of the layer (default: 1.0)
136  */
137  void
138  showMonoImage (const unsigned char* data, unsigned width, unsigned height,
139  const std::string &layer_id = "mono_image", double opacity = 1.0);
140 
141  /** \brief Add a monochrome 2D image layer, but do not render it (use spin/spinOnce to update).
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  addMonoImage (const unsigned char* data, unsigned width, unsigned height,
150  const std::string &layer_id = "mono_image", double opacity = 1.0);
151 
152  /** \brief Show a monochrome 2D image on screen.
153  * \param[in] cloud the input data representing the grayscale point cloud
154  * \param[in] layer_id the name of the layer (default: "image")
155  * \param[in] opacity the opacity of the layer (default: 1.0)
156  */
157  inline void
158  showMonoImage (const pcl::PointCloud<pcl::Intensity>::ConstPtr &cloud,
159  const std::string &layer_id = "mono_image", double opacity = 1.0)
160  {
161  return (showMonoImage (*cloud, layer_id, opacity));
162  }
163 
164  /** \brief Add a monochrome 2D image layer, but do not render it (use spin/spinOnce to update).
165  * \param[in] cloud the input data representing the grayscale point cloud
166  * \param[in] layer_id the name of the layer (default: "image")
167  * \param[in] opacity the opacity of the layer (default: 1.0)
168  */
169  inline void
170  addMonoImage (const pcl::PointCloud<pcl::Intensity>::ConstPtr &cloud,
171  const std::string &layer_id = "mono_image", double opacity = 1.0)
172  {
173  return (addMonoImage (*cloud, layer_id, opacity));
174  }
175 
176  /** \brief Show a monochrome 2D image on screen.
177  * \param[in] cloud the input data representing the grayscale point cloud
178  * \param[in] layer_id the name of the layer (default: "image")
179  * \param[in] opacity the opacity of the layer (default: 1.0)
180  */
181  void
182  showMonoImage (const pcl::PointCloud<pcl::Intensity> &cloud,
183  const std::string &layer_id = "mono_image", double opacity = 1.0);
184 
185  /** \brief Add a monochrome 2D image layer, but do not render it (use spin/spinOnce to update).
186  * \param[in] cloud the input data representing the RGB point cloud
187  * \param[in] layer_id the name of the layer (default: "image")
188  * \param[in] opacity the opacity of the layer (default: 1.0)
189  */
190  void
191  addMonoImage (const pcl::PointCloud<pcl::Intensity> &cloud,
192  const std::string &layer_id = "mono_image", double opacity = 1.0);
193 
194  /** \brief Show a monochrome 2D image on screen.
195  * \param[in] cloud the input data representing the grayscale point cloud
196  * \param[in] layer_id the name of the layer (default: "image")
197  * \param[in] opacity the opacity of the layer (default: 1.0)
198  */
199  inline void
200  showMonoImage (const pcl::PointCloud<pcl::Intensity8u>::ConstPtr &cloud,
201  const std::string &layer_id = "mono_image", double opacity = 1.0)
202  {
203  return (showMonoImage (*cloud, layer_id, opacity));
204  }
205 
206  /** \brief Add a monochrome 2D image layer, but do not render it (use spin/spinOnce to update).
207  * \param[in] cloud the input data representing the grayscale point cloud
208  * \param[in] layer_id the name of the layer (default: "image")
209  * \param[in] opacity the opacity of the layer (default: 1.0)
210  */
211  inline void
213  const std::string &layer_id = "mono_image", double opacity = 1.0)
214  {
215  return (addMonoImage (*cloud, layer_id, opacity));
216  }
217 
218  /** \brief Show a monochrome 2D image on screen.
219  * \param[in] cloud the input data representing the grayscale point cloud
220  * \param[in] layer_id the name of the layer (default: "image")
221  * \param[in] opacity the opacity of the layer (default: 1.0)
222  */
223  void
224  showMonoImage (const pcl::PointCloud<pcl::Intensity8u> &cloud,
225  const std::string &layer_id = "mono_image", double opacity = 1.0);
226 
227  /** \brief Add a monochrome 2D image layer, but do not render it (use spin/spinOnce to update).
228  * \param[in] cloud the input data representing the RGB point cloud
229  * \param[in] layer_id the name of the layer (default: "image")
230  * \param[in] opacity the opacity of the layer (default: 1.0)
231  */
232  void
233  addMonoImage (const pcl::PointCloud<pcl::Intensity8u> &cloud,
234  const std::string &layer_id = "mono_image", double opacity = 1.0);
235 
236  /** \brief Show a 2D RGB image on screen.
237  * \param[in] data the input data representing the image
238  * \param[in] width the width of the image
239  * \param[in] height the height of the image
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  showRGBImage (const unsigned char* data, unsigned width, unsigned height,
245  const std::string &layer_id = "rgb_image", double opacity = 1.0);
246 
247  /** \brief Add an RGB 2D image layer, but do not render it (use spin/spinOnce to update).
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  addRGBImage (const unsigned char* data, unsigned width, unsigned height,
256  const std::string &layer_id = "rgb_image", double opacity = 1.0);
257 
258  /** \brief Show a 2D image on screen, obtained from the RGB channel of a point cloud.
259  * \param[in] cloud the input data representing the RGB point cloud
260  * \param[in] layer_id the name of the layer (default: "image")
261  * \param[in] opacity the opacity of the layer (default: 1.0)
262  */
263  template <typename T> inline void
264  showRGBImage (const typename pcl::PointCloud<T>::ConstPtr &cloud,
265  const std::string &layer_id = "rgb_image", double opacity = 1.0)
266  {
267  return (showRGBImage<T> (*cloud, layer_id, opacity));
268  }
269 
270  /** \brief Add an RGB 2D image layer, but do not render it (use spin/spinOnce to update).
271  * \param[in] cloud the input data representing the RGB point cloud
272  * \param[in] layer_id the name of the layer (default: "image")
273  * \param[in] opacity the opacity of the layer (default: 1.0)
274  */
275  template <typename T> inline void
276  addRGBImage (const typename pcl::PointCloud<T>::ConstPtr &cloud,
277  const std::string &layer_id = "rgb_image", double opacity = 1.0)
278  {
279  return (addRGBImage<T> (*cloud, layer_id, opacity));
280  }
281 
282  /** \brief Show a 2D image on screen, obtained from the RGB channel of a point cloud.
283  * \param[in] cloud the input data representing the RGB point cloud
284  * \param[in] layer_id the name of the layer (default: "image")
285  * \param[in] opacity the opacity of the layer (default: 1.0)
286  */
287  template <typename T> void
288  showRGBImage (const pcl::PointCloud<T> &cloud,
289  const std::string &layer_id = "rgb_image", double opacity = 1.0);
290 
291  /** \brief Add an RGB 2D image layer, but do not render it (use spin/spinOnce to update).
292  * \param[in] cloud the input data representing the RGB point cloud
293  * \param[in] layer_id the name of the layer (default: "image")
294  * \param[in] opacity the opacity of the layer (default: 1.0)
295  */
296  template <typename T> void
297  addRGBImage (const pcl::PointCloud<T> &cloud,
298  const std::string &layer_id = "rgb_image", double opacity = 1.0);
299 
300  /** \brief Show a 2D image (float) on screen.
301  * \param[in] data the input data representing the image in float format
302  * \param[in] width the width of the image
303  * \param[in] height the height of the image
304  * \param[in] min_value filter all values in the image to be larger than this minimum value
305  * \param[in] max_value filter all values in the image to be smaller than this maximum value
306  * \param[in] grayscale show data as grayscale (true) or not (false). Default: false
307  * \param[in] layer_id the name of the layer (default: "image")
308  * \param[in] opacity the opacity of the layer (default: 1.0)
309  */
310  void
311  showFloatImage (const float* data, unsigned int width, unsigned int height,
312  float min_value = std::numeric_limits<float>::min (),
313  float max_value = std::numeric_limits<float>::max (), bool grayscale = false,
314  const std::string &layer_id = "float_image", double opacity = 1.0);
315 
316  /** \brief Add a float 2D image layer, but do not render it (use spin/spinOnce to update).
317  * \param[in] data the input data representing the image in float format
318  * \param[in] width the width of the image
319  * \param[in] height the height of the image
320  * \param[in] min_value filter all values in the image to be larger than this minimum value
321  * \param[in] max_value filter all values in the image to be smaller than this maximum value
322  * \param[in] grayscale show data as grayscale (true) or not (false). Default: false
323  * \param[in] layer_id the name of the layer (default: "image")
324  * \param[in] opacity the opacity of the layer (default: 1.0)
325  */
326  void
327  addFloatImage (const float* data, unsigned int width, unsigned int height,
328  float min_value = std::numeric_limits<float>::min (),
329  float max_value = std::numeric_limits<float>::max (), bool grayscale = false,
330  const std::string &layer_id = "float_image", double opacity = 1.0);
331 
332  /** \brief Show a 2D image (unsigned short) on screen.
333  * \param[in] short_image the input data representing the image in unsigned short format
334  * \param[in] width the width of the image
335  * \param[in] height the height of the image
336  * \param[in] min_value filter all values in the image to be larger than this minimum value
337  * \param[in] max_value filter all values in the image to be smaller than this maximum value
338  * \param[in] grayscale show data as grayscale (true) or not (false). Default: false
339  * \param[in] layer_id the name of the layer (default: "image")
340  * \param[in] opacity the opacity of the layer (default: 1.0)
341  */
342  void
343  showShortImage (const unsigned short* short_image, unsigned int width, unsigned int height,
344  unsigned short min_value = std::numeric_limits<unsigned short>::min (),
345  unsigned short max_value = std::numeric_limits<unsigned short>::max (), bool grayscale = false,
346  const std::string &layer_id = "short_image", double opacity = 1.0);
347 
348  /** \brief Add a short 2D image layer, but do not render it (use spin/spinOnce to update).
349  * \param[in] short_image the input data representing the image in unsigned short format
350  * \param[in] width the width of the image
351  * \param[in] height the height of the image
352  * \param[in] min_value filter all values in the image to be larger than this minimum value
353  * \param[in] max_value filter all values in the image to be smaller than this maximum value
354  * \param[in] grayscale show data as grayscale (true) or not (false). Default: false
355  * \param[in] layer_id the name of the layer (default: "image")
356  * \param[in] opacity the opacity of the layer (default: 1.0)
357  */
358  void
359  addShortImage (const unsigned short* short_image, unsigned int width, unsigned int height,
360  unsigned short min_value = std::numeric_limits<unsigned short>::min (),
361  unsigned short max_value = std::numeric_limits<unsigned short>::max (), bool grayscale = false,
362  const std::string &layer_id = "short_image", double opacity = 1.0);
363 
364  /** \brief Show a 2D image on screen representing angle data.
365  * \param[in] data the input data representing the image
366  * \param[in] width the width of the image
367  * \param[in] height the height of the image
368  * \param[in] layer_id the name of the layer (default: "image")
369  * \param[in] opacity the opacity of the layer (default: 1.0)
370  */
371  void
372  showAngleImage (const float* data, unsigned width, unsigned height,
373  const std::string &layer_id = "angle_image", double opacity = 1.0);
374 
375  /** \brief Add an angle 2D image layer, but do not render it (use spin/spinOnce to update).
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  addAngleImage (const float* data, unsigned width, unsigned height,
384  const std::string &layer_id = "angle_image", double opacity = 1.0);
385 
386  /** \brief Show a 2D image on screen representing half angle data.
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  showHalfAngleImage (const float* data, unsigned width, unsigned height,
395  const std::string &layer_id = "half_angle_image", double opacity = 1.0);
396 
397  /** \brief Add a half angle 2D image layer, but do not render it (use spin/spinOnce to update).
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  addHalfAngleImage (const float* data, unsigned width, unsigned height,
406  const std::string &layer_id = "half_angle_image", double opacity = 1.0);
407 
408  /** \brief Sets the pixel at coordinates(u,v) to color while setting the neighborhood to another
409  * \param[in] u the u/x coordinate of the pixel
410  * \param[in] v the v/y coordinate of the pixel
411  * \param[in] fg_color the pixel color
412  * \param[in] bg_color the neighborhood color
413  * \param[in] radius the circle radius around the pixel
414  * \param[in] layer_id the name of the layer (default: "points")
415  * \param[in] opacity the opacity of the layer (default: 1.0)
416  */
417  void
418  markPoint (size_t u, size_t v, Vector3ub fg_color, Vector3ub bg_color = red_color, double radius = 3.0,
419  const std::string &layer_id = "points", double opacity = 1.0);
420 
421  /** \brief Set the window title name
422  * \param[in] name the window title
423  */
424  void
425  setWindowTitle (const std::string& name);
426 
427  /** \brief Spin method. Calls the interactor and runs an internal loop. */
428  void
429  spin ();
430 
431  /** \brief Spin once method. Calls the interactor and updates the screen once.
432  * \param[in] time - How long (in ms) should the visualization loop be allowed to run.
433  * \param[in] force_redraw - if false it might return without doing anything if the
434  * interactor's framerate does not require a redraw yet.
435  */
436  void
437  spinOnce (int time = 1, bool force_redraw = true);
438 
439  /** \brief Register a callback function for keyboard events
440  * \param[in] callback the function that will be registered as a callback for a keyboard event
441  * \param[in] cookie user data that is passed to the callback
442  * \return a connection object that allows to disconnect the callback function.
443  */
444  boost::signals2::connection
445  registerKeyboardCallback (void (*callback) (const pcl::visualization::KeyboardEvent&, void*),
446  void* cookie = NULL)
447  {
448  return (registerKeyboardCallback (boost::bind (callback, _1, cookie)));
449  }
450 
451  /** \brief Register a callback function for keyboard events
452  * \param[in] callback the member function that will be registered as a callback for a keyboard event
453  * \param[in] instance instance to the class that implements the callback function
454  * \param[in] cookie user data that is passed to the callback
455  * \return a connection object that allows to disconnect the callback function.
456  */
457  template<typename T> boost::signals2::connection
458  registerKeyboardCallback (void (T::*callback) (const pcl::visualization::KeyboardEvent&, void*),
459  T& instance, void* cookie = NULL)
460  {
461  return (registerKeyboardCallback (boost::bind (callback, boost::ref (instance), _1, cookie)));
462  }
463 
464  /** \brief Register a callback boost::function for keyboard events
465  * \param[in] cb the boost function that will be registered as a callback for a keyboard event
466  * \return a connection object that allows to disconnect the callback function.
467  */
468  boost::signals2::connection
469  registerKeyboardCallback (boost::function<void (const pcl::visualization::KeyboardEvent&)> cb);
470 
471  /** \brief Register a callback boost::function for mouse events
472  * \param[in] callback the function that will be registered as a callback for a mouse event
473  * \param[in] cookie user data that is passed to the callback
474  * \return a connection object that allows to disconnect the callback function.
475  */
476  boost::signals2::connection
477  registerMouseCallback (void (*callback) (const pcl::visualization::MouseEvent&, void*),
478  void* cookie = NULL)
479  {
480  return (registerMouseCallback (boost::bind (callback, _1, cookie)));
481  }
482 
483  /** \brief Register a callback function for mouse events
484  * \param[in] callback the member function that will be registered as a callback for a mouse event
485  * \param[in] instance instance to the class that implements the callback function
486  * \param[in] cookie user data that is passed to the callback
487  * \return a connection object that allows to disconnect the callback function.
488  */
489  template<typename T> boost::signals2::connection
490  registerMouseCallback (void (T::*callback) (const pcl::visualization::MouseEvent&, void*),
491  T& instance, void* cookie = NULL)
492  {
493  return (registerMouseCallback (boost::bind (callback, boost::ref (instance), _1, cookie)));
494  }
495 
496  /** \brief Register a callback function for mouse events
497  * \param[in] cb the boost function that will be registered as a callback for a mouse event
498  * \return a connection object that allows to disconnect the callback function.
499  */
500  boost::signals2::connection
501  registerMouseCallback (boost::function<void (const pcl::visualization::MouseEvent&)> cb);
502 
503  /** \brief Set the position in screen coordinates.
504  * \param[in] x where to move the window to (X)
505  * \param[in] y where to move the window to (Y)
506  */
507  void
508  setPosition (int x, int y);
509 
510  /** \brief Set the window size in screen coordinates.
511  * \param[in] xw window size in horizontal (pixels)
512  * \param[in] yw window size in vertical (pixels)
513  */
514  void
515  setSize (int xw, int yw);
516 
517  /** \brief Return the window size in pixels. */
518  int*
519  getSize ();
520 
521  /** \brief Returns true when the user tried to close the window */
522  bool
523  wasStopped () const { return (stopped_); }
524 
525  /** \brief Stop the interaction and close the visualizaton window. */
526  void
527  close ()
528  {
529  stopped_ = true;
530  // This tends to close the window...
531 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION <= 4))
532  interactor_->stopLoop ();
533 #else
534  interactor_->TerminateApp ();
535 #endif
536  }
537 
538  /** \brief Add a circle shape from a point and a radius
539  * \param[in] x the x coordinate of the circle center
540  * \param[in] y the y coordinate of the circle center
541  * \param[in] radius the radius of the circle
542  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
543  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
544  */
545  bool
546  addCircle (unsigned int x, unsigned int y, double radius,
547  const std::string &layer_id = "circles", double opacity = 1.0);
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] r the red channel of the color that the sphere should be rendered with (0.0 -> 1.0)
554  * \param[in] g the green channel of the color that the sphere should be rendered with (0.0 -> 1.0)
555  * \param[in] b the blue channel of the color that the sphere should be rendered with (0.0 -> 1.0)
556  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
557  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
558  */
559  bool
560  addCircle (unsigned int x, unsigned int y, double radius,
561  double r, double g, double b,
562  const std::string &layer_id = "circles", double opacity = 1.0);
563 
564  /** \brief Add a 2D box and color its edges with a given color
565  * \param[in] min_pt the X,Y min coordinate
566  * \param[in] max_pt the X,Y max coordinate
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  addRectangle (const pcl::PointXY &min_pt, const pcl::PointXY &max_pt,
572  const std::string &layer_id = "rectangles", double opacity = 1.0);
573 
574  /** \brief Add a 2D box and color its edges with a given color
575  * \param[in] min_pt the X,Y min coordinate
576  * \param[in] max_pt the X,Y max coordinate
577  * \param[in] r the red channel of the color that the box should be rendered with (0.0 -> 1.0)
578  * \param[in] g the green channel of the color that the box should be rendered with (0.0 -> 1.0)
579  * \param[in] b the blue channel of the color that the box should be rendered with (0.0 -> 1.0)
580  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
581  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
582  */
583  bool
584  addRectangle (const pcl::PointXY &min_pt, const pcl::PointXY &max_pt,
585  double r, double g, double b,
586  const std::string &layer_id = "rectangles", double opacity = 1.0);
587 
588  /** \brief Add a 2D box and color its edges with a given color
589  * \param[in] x_min the X min coordinate
590  * \param[in] x_max the X max coordinate
591  * \param[in] y_min the Y min coordinate
592  * \param[in] y_max the Y max coordinate
593  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
594  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
595  */
596  bool
597  addRectangle (unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
598  const std::string &layer_id = "rectangles", double opacity = 1.0);
599 
600  /** \brief Add a 2D box and color its edges with a given color
601  * \param[in] x_min the X min coordinate
602  * \param[in] x_max the X max coordinate
603  * \param[in] y_min the Y min coordinate
604  * \param[in] y_max the Y max coordinate
605  * \param[in] r the red channel of the color that the box should be rendered with (0.0 -> 1.0)
606  * \param[in] g the green channel of the color that the box should be rendered with (0.0 -> 1.0)
607  * \param[in] b the blue channel of the color that the box should be rendered with (0.0 -> 1.0)
608  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
609  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
610  */
611  bool
612  addRectangle (unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
613  double r, double g, double b,
614  const std::string &layer_id = "rectangles", double opacity = 1.0);
615 
616  /** \brief Add a 2D box and color its edges with a given color
617  * \param[in] image the organized point cloud dataset containing the image data
618  * \param[in] min_pt the X,Y min coordinate
619  * \param[in] max_pt the X,Y max coordinate
620  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
621  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
622  */
623  template <typename T> bool
624  addRectangle (const typename pcl::PointCloud<T>::ConstPtr &image,
625  const T &min_pt, const T &max_pt,
626  const std::string &layer_id = "rectangles", double opacity = 1.0);
627 
628  /** \brief Add a 2D box and color its edges with a given color
629  * \param[in] image the organized point cloud dataset containing the image data
630  * \param[in] min_pt the X,Y min coordinate
631  * \param[in] max_pt the X,Y max coordinate
632  * \param[in] r the red channel of the color that the box should be rendered with (0.0 -> 1.0)
633  * \param[in] g the green channel of the color that the box should be rendered with (0.0 -> 1.0)
634  * \param[in] b the blue channel of the color that the box should be rendered with (0.0 -> 1.0)
635  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
636  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
637  */
638  template <typename T> bool
639  addRectangle (const typename pcl::PointCloud<T>::ConstPtr &image,
640  const T &min_pt, const T &max_pt,
641  double r, double g, double b,
642  const std::string &layer_id = "rectangles", double opacity = 1.0);
643 
644  /** \brief Add a 2D box that contains a given image mask and color its edges
645  * \param[in] image the organized point cloud dataset containing the image data
646  * \param[in] mask the point data representing the mask that we want to draw
647  * \param[in] r the red channel of the color that the mask should be rendered with
648  * \param[in] g the green channel of the color that the mask should be rendered with
649  * \param[in] b the blue channel of the color that the mask should be rendered with
650  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
651  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
652  */
653  template <typename T> bool
654  addRectangle (const typename pcl::PointCloud<T>::ConstPtr &image, const pcl::PointCloud<T> &mask,
655  double r, double g, double b,
656  const std::string &layer_id = "rectangles", double opacity = 1.0);
657 
658  /** \brief Add a 2D box that contains a given image mask and color its edges in red
659  * \param[in] image the organized point cloud dataset containing the image data
660  * \param[in] mask the point data representing the mask that we want to draw
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  const std::string &layer_id = "image_mask", double opacity = 1.0);
667 
668  /** \brief Add a 2D box and fill it in with a given color
669  * \param[in] x_min the X min coordinate
670  * \param[in] x_max the X max coordinate
671  * \param[in] y_min the Y min coordinate
672  * \param[in] y_max the Y max coordinate
673  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
674  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 0.5)
675  */
676  bool
677  addFilledRectangle (unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
678  const std::string &layer_id = "boxes", double opacity = 0.5);
679 
680  /** \brief Add a 2D box and fill it in with a given color
681  * \param[in] x_min the X min coordinate
682  * \param[in] x_max the X max coordinate
683  * \param[in] y_min the Y min coordinate
684  * \param[in] y_max the Y max coordinate
685  * \param[in] r the red channel of the color that the box should be rendered with (0.0 -> 1.0)
686  * \param[in] g the green channel of the color that the box should be rendered with (0.0 -> 1.0)
687  * \param[in] b the blue channel of the color that the box should be rendered with (0.0 -> 1.0)
688  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
689  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 0.5)
690  */
691  bool
692  addFilledRectangle (unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max,
693  double r, double g, double b,
694  const std::string &layer_id = "boxes", double opacity = 0.5);
695 
696  /** \brief Add a 2D line with a given color
697  * \param[in] x_min the X min coordinate
698  * \param[in] y_min the Y min coordinate
699  * \param[in] x_max the X max coordinate
700  * \param[in] y_max the Y max coordinate
701  * \param[in] r the red channel of the color that the line should be rendered with (0.0 -> 1.0)
702  * \param[in] g the green channel of the color that the line should be rendered with (0.0 -> 1.0)
703  * \param[in] b the blue channel of the color that the line should be rendered with (0.0 -> 1.0)
704  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
705  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
706  */
707  bool
708  addLine (unsigned int x_min, unsigned int y_min, unsigned int x_max, unsigned int y_max,
709  double r, double g, double b,
710  const std::string &layer_id = "line", double opacity = 1.0);
711 
712  /** \brief Add a 2D line with a given color
713  * \param[in] x_min the X min coordinate
714  * \param[in] y_min the Y min coordinate
715  * \param[in] x_max the X max coordinate
716  * \param[in] y_max the Y max coordinate
717  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
718  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
719  */
720  bool
721  addLine (unsigned int x_min, unsigned int y_min, unsigned int x_max, unsigned int y_max,
722  const std::string &layer_id = "line", double opacity = 1.0);
723 
724 
725  /** \brief Add a generic 2D mask to an image
726  * \param[in] image the organized point cloud dataset containing the image data
727  * \param[in] mask the point data representing the mask that we want to draw
728  * \param[in] r the red channel of the color that the mask should be rendered with
729  * \param[in] g the green channel of the color that the mask should be rendered with
730  * \param[in] b the blue channel of the color that the mask should be rendered with
731  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
732  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 0.5)
733  */
734  template <typename T> bool
735  addMask (const typename pcl::PointCloud<T>::ConstPtr &image, const pcl::PointCloud<T> &mask,
736  double r, double g, double b,
737  const std::string &layer_id = "image_mask", double opacity = 0.5);
738 
739  /** \brief Add a generic 2D mask to an image (colored in red)
740  * \param[in] image the organized point cloud dataset containing the image data
741  * \param[in] mask the point data representing the mask that we want to draw
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: 0.5)
744  */
745  template <typename T> bool
746  addMask (const typename pcl::PointCloud<T>::ConstPtr &image, const pcl::PointCloud<T> &mask,
747  const std::string &layer_id = "image_mask", double opacity = 0.5);
748 
749  /** \brief Add a generic 2D planar polygon to an image
750  * \param[in] image the organized point cloud dataset containing the image data
751  * \param[in] polygon the point data representing the polygon that we want to draw.
752  * A line will be drawn from each point to the next in the dataset.
753  * \param[in] r the red channel of the color that the polygon should be rendered with
754  * \param[in] g the green channel of the color that the polygon should be rendered with
755  * \param[in] b the blue channel of the color that the polygon should be rendered with
756  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
757  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
758  */
759  template <typename T> bool
760  addPlanarPolygon (const typename pcl::PointCloud<T>::ConstPtr &image, const pcl::PlanarPolygon<T> &polygon,
761  double r, double g, double b,
762  const std::string &layer_id = "planar_polygon", double opacity = 1.0);
763 
764  /** \brief Add a generic 2D planar polygon to an image
765  * \param[in] image the organized point cloud dataset containing the image data
766  * \param[in] polygon the point data representing the polygon that we want to draw.
767  * A line will be drawn from each point to the next in the dataset.
768  * \param[in] layer_id the 2D layer ID where we want the extra information to be drawn.
769  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 1.0)
770  */
771  template <typename T> bool
772  addPlanarPolygon (const typename pcl::PointCloud<T>::ConstPtr &image, const pcl::PlanarPolygon<T> &polygon,
773  const std::string &layer_id = "planar_polygon", double opacity = 1.0);
774 
775  /** \brief Add a new 2D rendering layer to the viewer.
776  * \param[in] layer_id the name of the layer
777  * \param[in] width the width of the layer
778  * \param[in] height the height of the layer
779  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 0.5)
780  */
781  bool
782  addLayer (const std::string &layer_id, int width, int height, double opacity = 0.5);
783 
784  /** \brief Remove a 2D layer given by its ID.
785  * \param[in] layer_id the name of the layer
786  */
787  void
788  removeLayer (const std::string &layer_id);
789 
790  /** \brief Add the specified correspondences to the display.
791  * \param[in] source_img The source RGB image
792  * \param[in] target_img The target RGB image
793  * \param[in] correspondences The list of correspondences to display.
794  * \param[in] nth display only the Nth correspondence (e.g., skip the rest)
795  * \param[in] layer_id the layer id (default: "correspondences")
796  */
797  template <typename PointT> bool
798  showCorrespondences (const pcl::PointCloud<PointT> &source_img,
799  const pcl::PointCloud<PointT> &target_img,
800  const pcl::Correspondences &correspondences,
801  int nth = 1,
802  const std::string &layer_id = "correspondences");
803 
804  protected:
805  /** \brief Trigger a render call. */
806  void
807  render ();
808 
809  /** \brief Convert the Intensity information in a PointCloud<Intensity> to an unsigned char array
810  * \param[in] cloud the input cloud containing the grayscale intensity information
811  * \param[out] data a boost shared array of unsigned char type
812  * \note The method assumes that the data array has already been allocated and
813  * contains enough space to copy all the data from cloud!
814  */
815  void
816  convertIntensityCloudToUChar (const pcl::PointCloud<pcl::Intensity> &cloud,
817  boost::shared_array<unsigned char> data);
818 
819  /** \brief Convert the Intensity8u information in a PointCloud<Intensity8u> to an unsigned char array
820  * \param[in] cloud the input cloud containing the grayscale intensity information
821  * \param[out] data a boost shared array of unsigned char type
822  * \note The method assumes that the data array has already been allocated and
823  * contains enough space to copy all the data from cloud!
824  */
825  void
826  convertIntensityCloud8uToUChar (const pcl::PointCloud<pcl::Intensity8u> &cloud,
827  boost::shared_array<unsigned char> data);
828 
829  /** \brief Convert the RGB information in a PointCloud<T> to an unsigned char array
830  * \param[in] cloud the input cloud containing the RGB information
831  * \param[out] data a boost shared array of unsigned char type
832  * \note The method assumes that the data array has already been allocated and
833  * contains enough space to copy all the data from cloud!
834  */
835  template <typename T> void
836  convertRGBCloudToUChar (const pcl::PointCloud<T> &cloud,
837  boost::shared_array<unsigned char> &data);
838 
839  /** \brief Set the stopped flag back to false */
840  void
841  resetStoppedFlag () { stopped_ = false; }
842 
843  /** \brief Fire up a mouse event with a specified event ID
844  * \param[int] event_id the id of the event
845  */
846  void
847  emitMouseEvent (unsigned long event_id);
848 
849  /** \brief Fire up a keyboard event with a specified event ID
850  * \param[int] event_id the id of the event
851  */
852  void
853  emitKeyboardEvent (unsigned long event_id);
854 
855  // Callbacks used to register for vtk command
856  static void
857  MouseCallback (vtkObject*, unsigned long eid, void* clientdata, void *calldata);
858  static void
859  KeyboardCallback (vtkObject*, unsigned long eid, void* clientdata, void *calldata);
860 
861  protected: // types
862  struct ExitMainLoopTimerCallback : public vtkCommand
863  {
864  ExitMainLoopTimerCallback () : right_timer_id (), window () {}
865 
867  {
868  return (new ExitMainLoopTimerCallback);
869  }
870  virtual void
871  Execute (vtkObject* vtkNotUsed (caller), unsigned long event_id, void* call_data)
872  {
873  if (event_id != vtkCommand::TimerEvent)
874  return;
875  int timer_id = *static_cast<int*> (call_data);
876  if (timer_id != right_timer_id)
877  return;
878 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION <= 4))
879  window->interactor_->stopLoop ();
880 #else
881  window->interactor_->TerminateApp ();
882 #endif
883  }
886  };
887  struct ExitCallback : public vtkCommand
888  {
889  ExitCallback () : window () {}
890 
891  static ExitCallback* New ()
892  {
893  return (new ExitCallback);
894  }
895  virtual void
896  Execute (vtkObject*, unsigned long event_id, void*)
897  {
898  if (event_id != vtkCommand::ExitEvent)
899  return;
900  window->stopped_ = true;
901 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION <= 4))
902  window->interactor_->stopLoop ();
903 #else
904  window->interactor_->TerminateApp ();
905 #endif
906  }
908  };
909 
910  private:
911  /** \brief Internal structure describing a layer. */
912  struct Layer
913  {
914  Layer () : actor (), layer_name () {}
916  std::string layer_name;
917  };
918 
919  typedef std::vector<Layer> LayerMap;
920 
921  /** \brief Add a new 2D rendering layer to the viewer.
922  * \param[in] layer_id the name of the layer
923  * \param[in] width the width of the layer
924  * \param[in] height the height of the layer
925  * \param[in] opacity the opacity of the layer: 0 for invisible, 1 for opaque. (default: 0.5)
926  * \param[in] fill_box set to true to fill in the image with one black box before starting
927  */
928  LayerMap::iterator
929  createLayer (const std::string &layer_id, int width, int height, double opacity = 0.5, bool fill_box = true);
930 
931  boost::signals2::signal<void (const pcl::visualization::MouseEvent&)> mouse_signal_;
932  boost::signals2::signal<void (const pcl::visualization::KeyboardEvent&)> keyboard_signal_;
933 
934 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION <= 4))
936 #else
938 #endif
940  vtkSmartPointer<vtkCallbackCommand> keyboard_command_;
941 
942  /** \brief Callback object enabling us to leave the main loop, when a timer fires. */
943  vtkSmartPointer<ExitMainLoopTimerCallback> exit_main_loop_timer_callback_;
944  vtkSmartPointer<ExitCallback> exit_callback_;
945 
946  /** \brief The ImageViewer widget. */
947  vtkSmartPointer<vtkImageViewer> image_viewer_;
948 
949  /** \brief The render window. */
951 
952  /** \brief The renderer. */
954 
955 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION >= 10))
956  /** \brief Global prop. This is the actual "actor". */
958 #endif
959  /** \brief The interactor style. */
961 
962  /** \brief The data array representing the image. Used internally. */
963  boost::shared_array<unsigned char> data_;
964 
965  /** \brief The data array (representing the image) size. Used internally. */
966  size_t data_size_;
967 
968  /** \brief Set to false if the interaction loop is running. */
969  bool stopped_;
970 
971  /** \brief Global timer ID. Used in destructor only. */
972  int timer_id_;
973 
974  // /** \brief Internal blender used to overlay 2D geometry over the image. */
975  // vtkSmartPointer<vtkImageBlend> blend_;
976 
977  /** \brief Internal list with different 2D layers shapes. */
978  LayerMap layer_map_;
979 
980  /** \brief Image reslice, used for flipping the image. */
982 
983  /** \brief Internal data array. Used everytime add***Image is called.
984  * Cleared, everytime the render loop is executed.
985  */
986  std::vector<unsigned char*> image_data_;
987 
988  struct LayerComparator
989  {
990  LayerComparator (const std::string &str) : str_ (str) {}
991  const std::string &str_;
992 
993  bool
994  operator () (const Layer &layer)
995  {
996  return (layer.layer_name == str_);
997  }
998  };
999 
1000  public:
1001  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
1002  };
1003  }
1004 }
1005 
1006 #include <pcl/visualization/impl/image_viewer.hpp>
1007 
1008 #endif /* __IMAGE_VISUALIZER_H__ */
1009