Point Cloud Library (PCL)  1.9.0-dev
image_viewer.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2009-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_HPP_
40 #define PCL_VISUALIZATION_IMAGE_VISUALIZER_HPP_
41 
42 #include <vtkVersion.h>
43 #include <vtkContextActor.h>
44 #include <vtkContextScene.h>
45 #include <vtkImageData.h>
46 #include <vtkImageFlip.h>
47 #include <vtkPointData.h>
48 #include <vtkImageViewer.h>
49 
50 #include <pcl/visualization/common/common.h>
51 #include <pcl/search/organized.h>
52 
53 ///////////////////////////////////////////////////////////////////////////////////////////
54 template <typename T> void
56  const pcl::PointCloud<T> &cloud,
57  boost::shared_array<unsigned char> &data)
58 {
59  int j = 0;
60  for (size_t i = 0; i < cloud.points.size (); ++i)
61  {
62  data[j++] = cloud.points[i].r;
63  data[j++] = cloud.points[i].g;
64  data[j++] = cloud.points[i].b;
65  }
66 }
67 
68 ///////////////////////////////////////////////////////////////////////////////////////////
69 template <typename T> void
71  const std::string &layer_id,
72  double opacity)
73 {
74  if (data_size_ < cloud.width * cloud.height)
75  {
76  data_size_ = cloud.width * cloud.height * 3;
77  data_.reset (new unsigned char[data_size_]);
78  }
79 
80  convertRGBCloudToUChar (cloud, data_);
81 
82  return (addRGBImage (data_.get (), cloud.width, cloud.height, layer_id, opacity));
83 }
84 
85 ///////////////////////////////////////////////////////////////////////////////////////////
86 template <typename T> void
88  const std::string &layer_id,
89  double opacity)
90 {
91  addRGBImage<T> (cloud, layer_id, opacity);
92  render ();
93 }
94 
95 ///////////////////////////////////////////////////////////////////////////////////////////
96 template <typename T> bool
98  const typename pcl::PointCloud<T>::ConstPtr &image,
99  const pcl::PointCloud<T> &mask,
100  double r, double g, double b,
101  const std::string &layer_id, double opacity)
102 {
103  // We assume that the data passed into image is organized, otherwise this doesn't make sense
104  if (!image->isOrganized ())
105  return (false);
106 
107  // Check to see if this ID entry already exists (has it been already added to the visualizer?)
108  LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
109  if (am_it == layer_map_.end ())
110  {
111  PCL_DEBUG ("[pcl::visualization::ImageViewer::addMask] No layer with ID'=%s' found. Creating new one...\n", layer_id.c_str ());
112  am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
113  }
114 
115  // Construct a search object to get the camera parameters
117  search.setInputCloud (image);
118  std::vector<float> xy;
119  xy.reserve (mask.size () * 2);
120  for (size_t i = 0; i < mask.size (); ++i)
121  {
122  pcl::PointXY p_projected;
123  search.projectPoint (mask[i], p_projected);
124 
125  xy.push_back (p_projected.x);
126  #if ((VTK_MAJOR_VERSION >= 6) || ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION > 7)))
127  xy.push_back (static_cast<float> (image->height) - p_projected.y);
128  #else
129  xy.push_back (p_projected.y);
130  #endif
131  }
132 
134  points->setColors (static_cast<unsigned char> (r*255.0),
135  static_cast<unsigned char> (g*255.0),
136  static_cast<unsigned char> (b*255.0));
137  points->setOpacity (opacity);
138  points->set (xy);
139  am_it->actor->GetScene ()->AddItem (points);
140  return (true);
141 }
142 
143 ///////////////////////////////////////////////////////////////////////////////////////////
144 template <typename T> bool
146  const typename pcl::PointCloud<T>::ConstPtr &image,
147  const pcl::PointCloud<T> &mask,
148  const std::string &layer_id, double opacity)
149 {
150  return (addMask (image, mask, 1.0, 0.0, 0.0, layer_id, opacity));
151 }
152 
153 ///////////////////////////////////////////////////////////////////////////////////////////
154 template <typename T> bool
156  const typename pcl::PointCloud<T>::ConstPtr &image,
157  const pcl::PlanarPolygon<T> &polygon,
158  double r, double g, double b,
159  const std::string &layer_id, double opacity)
160 {
161  // We assume that the data passed into image is organized, otherwise this doesn't make sense
162  if (!image->isOrganized ())
163  return (false);
164 
165  // Check to see if this ID entry already exists (has it been already added to the visualizer?)
166  LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
167  if (am_it == layer_map_.end ())
168  {
169  PCL_DEBUG ("[pcl::visualization::ImageViewer::addPlanarPolygon] No layer with ID'=%s' found. Creating new one...\n", layer_id.c_str ());
170  am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
171  }
172 
173  // Construct a search object to get the camera parameters and fill points
175  search.setInputCloud (image);
176  std::vector<float> xy;
177  xy.reserve ((polygon.getContour ().size () + 1) * 2);
178  for (size_t i = 0; i < polygon.getContour ().size (); ++i)
179  {
180  pcl::PointXY p;
181  search.projectPoint (polygon.getContour ()[i], p);
182  xy.push_back (p.x);
183  #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION <= 7))
184  xy.push_back (static_cast<float> (image->height) - p.y);
185  #else
186  xy.push_back (p.y);
187  #endif
188  }
189 
190  // Close the polygon
191  xy[xy.size () - 2] = xy[0];
192  xy[xy.size () - 1] = xy[1];
193 
195  poly->setColors (static_cast<unsigned char> (r * 255.0),
196  static_cast<unsigned char> (g * 255.0),
197  static_cast<unsigned char> (b * 255.0));
198  poly->setOpacity (opacity);
199  poly->set (xy);
200  am_it->actor->GetScene ()->AddItem (poly);
201 
202  return (true);
203 }
204 
205 ///////////////////////////////////////////////////////////////////////////////////////////
206 template <typename T> bool
208  const typename pcl::PointCloud<T>::ConstPtr &image,
209  const pcl::PlanarPolygon<T> &polygon,
210  const std::string &layer_id, double opacity)
211 {
212  return (addPlanarPolygon (image, polygon, 1.0, 0.0, 0.0, layer_id, opacity));
213 }
214 
215 ///////////////////////////////////////////////////////////////////////////////////////////
216 template <typename T> bool
218  const typename pcl::PointCloud<T>::ConstPtr &image,
219  const T &min_pt,
220  const T &max_pt,
221  double r, double g, double b,
222  const std::string &layer_id, double opacity)
223 {
224  // We assume that the data passed into image is organized, otherwise this doesn't make sense
225  if (!image->isOrganized ())
226  return (false);
227 
228  // Check to see if this ID entry already exists (has it been already added to the visualizer?)
229  LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
230  if (am_it == layer_map_.end ())
231  {
232  PCL_DEBUG ("[pcl::visualization::ImageViewer::addRectangle] No layer with ID'=%s' found. Creating new one...\n", layer_id.c_str ());
233  am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
234  }
235 
236  // Construct a search object to get the camera parameters
238  search.setInputCloud (image);
239  // Project the 8 corners
240  T p1, p2, p3, p4, p5, p6, p7, p8;
241  p1.x = min_pt.x; p1.y = min_pt.y; p1.z = min_pt.z;
242  p2.x = min_pt.x; p2.y = min_pt.y; p2.z = max_pt.z;
243  p3.x = min_pt.x; p3.y = max_pt.y; p3.z = min_pt.z;
244  p4.x = min_pt.x; p4.y = max_pt.y; p4.z = max_pt.z;
245  p5.x = max_pt.x; p5.y = min_pt.y; p5.z = min_pt.z;
246  p6.x = max_pt.x; p6.y = min_pt.y; p6.z = max_pt.z;
247  p7.x = max_pt.x; p7.y = max_pt.y; p7.z = min_pt.z;
248  p8.x = max_pt.x; p8.y = max_pt.y; p8.z = max_pt.z;
249 
250  std::vector<pcl::PointXY> pp_2d (8);
251  search.projectPoint (p1, pp_2d[0]);
252  search.projectPoint (p2, pp_2d[1]);
253  search.projectPoint (p3, pp_2d[2]);
254  search.projectPoint (p4, pp_2d[3]);
255  search.projectPoint (p5, pp_2d[4]);
256  search.projectPoint (p6, pp_2d[5]);
257  search.projectPoint (p7, pp_2d[6]);
258  search.projectPoint (p8, pp_2d[7]);
259 
260  pcl::PointXY min_pt_2d, max_pt_2d;
261  min_pt_2d.x = min_pt_2d.y = std::numeric_limits<float>::max ();
262  max_pt_2d.x = max_pt_2d.y = -std::numeric_limits<float>::max ();
263  // Search for the two extrema
264  for (size_t i = 0; i < pp_2d.size (); ++i)
265  {
266  if (pp_2d[i].x < min_pt_2d.x) min_pt_2d.x = pp_2d[i].x;
267  if (pp_2d[i].y < min_pt_2d.y) min_pt_2d.y = pp_2d[i].y;
268  if (pp_2d[i].x > max_pt_2d.x) max_pt_2d.x = pp_2d[i].x;
269  if (pp_2d[i].y > max_pt_2d.y) max_pt_2d.y = pp_2d[i].y;
270  }
271 #if ((VTK_MAJOR_VERSION >= 6) || ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION > 7)))
272  min_pt_2d.y = float (image->height) - min_pt_2d.y;
273  max_pt_2d.y = float (image->height) - max_pt_2d.y;
274 #endif
275 
277  rect->setColors (static_cast<unsigned char> (255.0 * r),
278  static_cast<unsigned char> (255.0 * g),
279  static_cast<unsigned char> (255.0 * b));
280  rect->setOpacity (opacity);
281  rect->set (min_pt_2d.x, min_pt_2d.y, max_pt_2d.x, max_pt_2d.y);
282  am_it->actor->GetScene ()->AddItem (rect);
283 
284  return (true);
285 }
286 
287 ///////////////////////////////////////////////////////////////////////////////////////////
288 template <typename T> bool
290  const typename pcl::PointCloud<T>::ConstPtr &image,
291  const T &min_pt,
292  const T &max_pt,
293  const std::string &layer_id, double opacity)
294 {
295  return (addRectangle<T> (image, min_pt, max_pt, 0.0, 1.0, 0.0, layer_id, opacity));
296 }
297 
298 ///////////////////////////////////////////////////////////////////////////////////////////
299 template <typename T> bool
301  const typename pcl::PointCloud<T>::ConstPtr &image,
302  const pcl::PointCloud<T> &mask,
303  double r, double g, double b,
304  const std::string &layer_id, double opacity)
305 {
306  // We assume that the data passed into image is organized, otherwise this doesn't make sense
307  if (!image->isOrganized ())
308  return (false);
309 
310  // Check to see if this ID entry already exists (has it been already added to the visualizer?)
311  LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
312  if (am_it == layer_map_.end ())
313  {
314  PCL_DEBUG ("[pcl::visualization::ImageViewer::addRectangle] No layer with ID'=%s' found. Creating new one...\n", layer_id.c_str ());
315  am_it = createLayer (layer_id, getSize ()[0] - 1, getSize ()[1] - 1, opacity, false);
316  }
317 
318  // Construct a search object to get the camera parameters
320  search.setInputCloud (image);
321  std::vector<pcl::PointXY> pp_2d (mask.points.size ());
322  for (size_t i = 0; i < mask.points.size (); ++i)
323  search.projectPoint (mask.points[i], pp_2d[i]);
324 
325  pcl::PointXY min_pt_2d, max_pt_2d;
326  min_pt_2d.x = min_pt_2d.y = std::numeric_limits<float>::max ();
327  max_pt_2d.x = max_pt_2d.y = -std::numeric_limits<float>::max ();
328  // Search for the two extrema
329  for (size_t i = 0; i < pp_2d.size (); ++i)
330  {
331  if (pp_2d[i].x < min_pt_2d.x) min_pt_2d.x = pp_2d[i].x;
332  if (pp_2d[i].y < min_pt_2d.y) min_pt_2d.y = pp_2d[i].y;
333  if (pp_2d[i].x > max_pt_2d.x) max_pt_2d.x = pp_2d[i].x;
334  if (pp_2d[i].y > max_pt_2d.y) max_pt_2d.y = pp_2d[i].y;
335  }
336 #if ((VTK_MAJOR_VERSION >= 6) ||((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION > 7)))
337  min_pt_2d.y = float (image->height) - min_pt_2d.y;
338  max_pt_2d.y = float (image->height) - max_pt_2d.y;
339 #endif
340 
342  rect->setColors (static_cast<unsigned char> (255.0 * r),
343  static_cast<unsigned char> (255.0 * g),
344  static_cast<unsigned char> (255.0 * b));
345  rect->setOpacity (opacity);
346  rect->set (min_pt_2d.x, min_pt_2d.y, max_pt_2d.x, max_pt_2d.y);
347  am_it->actor->GetScene ()->AddItem (rect);
348 
349  return (true);
350 }
351 
352 ///////////////////////////////////////////////////////////////////////////////////////////
353 template <typename T> bool
355  const typename pcl::PointCloud<T>::ConstPtr &image,
356  const pcl::PointCloud<T> &mask,
357  const std::string &layer_id, double opacity)
358 {
359  return (addRectangle (image, mask, 0.0, 1.0, 0.0, layer_id, opacity));
360 }
361 
362 ///////////////////////////////////////////////////////////////////////////////////////////
363 template <typename PointT> bool
365  const pcl::PointCloud<PointT> &source_img,
366  const pcl::PointCloud<PointT> &target_img,
367  const pcl::Correspondences &correspondences,
368  int nth,
369  const std::string &layer_id)
370 {
371  if (correspondences.empty ())
372  {
373  PCL_DEBUG ("[pcl::visualization::ImageViewer::addCorrespondences] An empty set of correspondences given! Nothing to display.\n");
374  return (false);
375  }
376 
377  // Check to see if this ID entry already exists (has it been already added to the visualizer?)
378  LayerMap::iterator am_it = std::find_if (layer_map_.begin (), layer_map_.end (), LayerComparator (layer_id));
379  if (am_it == layer_map_.end ())
380  {
381  PCL_DEBUG ("[pcl::visualization::ImageViewer::addCorrespondences] No layer with ID='%s' found. Creating new one...\n", layer_id.c_str ());
382  am_it = createLayer (layer_id, source_img.width + target_img.width, std::max (source_img.height, target_img.height), 1.0, false);
383  }
384 
385  int src_size = source_img.width * source_img.height * 3;
386  int tgt_size = target_img.width * target_img.height * 3;
387 
388  // Set window size
389  setSize (source_img.width + target_img.width , std::max (source_img.height, target_img.height));
390 
391  // Set data size
392  if (data_size_ < static_cast<size_t> (src_size + tgt_size))
393  {
394  data_size_ = src_size + tgt_size;
395  data_.reset (new unsigned char[data_size_]);
396  }
397 
398  // Copy data in VTK format
399  int j = 0;
400  for (size_t i = 0; i < std::max (source_img.height, target_img.height); ++i)
401  {
402  // Still need to copy the source?
403  if (i < source_img.height)
404  {
405  for (size_t k = 0; k < source_img.width; ++k)
406  {
407  data_[j++] = source_img[i * source_img.width + k].r;
408  data_[j++] = source_img[i * source_img.width + k].g;
409  data_[j++] = source_img[i * source_img.width + k].b;
410  }
411  }
412  else
413  {
414  memcpy (&data_[j], 0, source_img.width * 3);
415  j += source_img.width * 3;
416  }
417 
418  // Still need to copy the target?
419  if (i < source_img.height)
420  {
421  for (size_t k = 0; k < target_img.width; ++k)
422  {
423  data_[j++] = target_img[i * source_img.width + k].r;
424  data_[j++] = target_img[i * source_img.width + k].g;
425  data_[j++] = target_img[i * source_img.width + k].b;
426  }
427  }
428  else
429  {
430  memcpy (&data_[j], 0, target_img.width * 3);
431  j += target_img.width * 3;
432  }
433  }
434 
435  void* data = const_cast<void*> (reinterpret_cast<const void*> (data_.get ()));
436 
438  image->SetDimensions (source_img.width + target_img.width, std::max (source_img.height, target_img.height), 1);
439 #if VTK_MAJOR_VERSION < 6
440  image->SetScalarTypeToUnsignedChar ();
441  image->SetNumberOfScalarComponents (3);
442  image->AllocateScalars ();
443 #else
444  image->AllocateScalars (VTK_UNSIGNED_CHAR, 3);
445 #endif
446  image->GetPointData ()->GetScalars ()->SetVoidArray (data, data_size_, 1);
448 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION <= 10))
449  // Now create filter and set previously created transformation
450  algo_->SetInput (image);
451  algo_->Update ();
452  image_item->set (0, 0, algo_->GetOutput ());
453 #else
454  image_item->set (0, 0, image);
455  interactor_style_->adjustCamera (image, ren_);
456 #endif
457  am_it->actor->GetScene ()->AddItem (image_item);
458  image_viewer_->SetSize (image->GetDimensions ()[0], image->GetDimensions ()[1]);
459 
460  // Draw lines between the best corresponding points
461  for (size_t i = 0; i < correspondences.size (); i += nth)
462  {
463  double r, g, b;
464  getRandomColors (r, g, b);
465  unsigned char u_r = static_cast<unsigned char> (255.0 * r);
466  unsigned char u_g = static_cast<unsigned char> (255.0 * g);
467  unsigned char u_b = static_cast<unsigned char> (255.0 * b);
469  query_circle->setColors (u_r, u_g, u_b);
471  match_circle->setColors (u_r, u_g, u_b);
473  line->setColors (u_r, u_g, u_b);
474 
475  float query_x = correspondences[i].index_query % source_img.width;
476  float match_x = correspondences[i].index_match % target_img.width + source_img.width;
477 #if ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION > 10))
478  float query_y = correspondences[i].index_query / source_img.width;
479  float match_y = correspondences[i].index_match / target_img.width;
480 #else
481  float query_y = getSize ()[1] - correspondences[i].index_query / source_img.width;
482  float match_y = getSize ()[1] - correspondences[i].index_match / target_img.width;
483 #endif
484 
485  query_circle->set (query_x, query_y, 3.0);
486  match_circle->set (match_x, match_y, 3.0);
487  line->set (query_x, query_y, match_x, match_y);
488 
489  am_it->actor->GetScene ()->AddItem (query_circle);
490  am_it->actor->GetScene ()->AddItem (match_circle);
491  am_it->actor->GetScene ()->AddItem (line);
492  }
493 
494  return (true);
495 }
496 
497 #endif // PCL_VISUALIZATION_IMAGE_VISUALIZER_HPP_
size_t size() const
Definition: point_cloud.h:448
std::vector< PointT, Eigen::aligned_allocator< PointT > > points
The point data.
Definition: point_cloud.h:410
bool projectPoint(const PointT &p, pcl::PointXY &q) const
projects a point into the image
Definition: organized.hpp:382
pcl::PointCloud< PointT >::VectorType & getContour()
Getter for the contour / boundary.
bool addMask(const typename pcl::PointCloud< T >::ConstPtr &image, const pcl::PointCloud< T > &mask, double r, double g, double b, const std::string &layer_id="image_mask", double opacity=0.5)
Add a generic 2D mask to an image.
void setSize(int xw, int yw)
Set the window size in screen coordinates.
void render()
Trigger a render call.
void showRGBImage(const unsigned char *data, unsigned width, unsigned height, const std::string &layer_id="rgb_image", double opacity=1.0)
Show a 2D RGB image on screen.
A 2D point structure representing Euclidean xy coordinates.
uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:415
PCL_EXPORTS void getRandomColors(double &r, double &g, double &b, double min=0.2, double max=2.8)
Get (good) random values for R/G/B.
uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:413
bool addRectangle(const pcl::PointXY &min_pt, const pcl::PointXY &max_pt, const std::string &layer_id="rectangles", double opacity=1.0)
Add a 2D box and color its edges with a given color.
PlanarPolygon represents a planar (2D) polygon, potentially in a 3D space.
void convertRGBCloudToUChar(const pcl::PointCloud< T > &cloud, boost::shared_array< unsigned char > &data)
Convert the RGB information in a PointCloud<T> to an unsigned char array.
std::vector< pcl::Correspondence, Eigen::aligned_allocator< pcl::Correspondence > > Correspondences
boost::shared_ptr< const PointCloud< PointT > > ConstPtr
Definition: point_cloud.h:429
bool addPlanarPolygon(const typename pcl::PointCloud< T >::ConstPtr &image, const pcl::PlanarPolygon< T > &polygon, double r, double g, double b, const std::string &layer_id="planar_polygon", double opacity=1.0)
Add a generic 2D planar polygon to an image.
bool showCorrespondences(const pcl::PointCloud< PointT > &source_img, const pcl::PointCloud< PointT > &target_img, const pcl::Correspondences &correspondences, int nth=1, const std::string &layer_id="correspondences")
Add the specified correspondences to the display.
int * getSize()
Return the window size in pixels.
void addRGBImage(const unsigned char *data, unsigned width, unsigned height, const std::string &layer_id="rgb_image", double opacity=1.0)
Add an RGB 2D image layer, but do not render it (use spin/spinOnce to update).
virtual void setInputCloud(const PointCloudConstPtr &cloud, const IndicesConstPtr &indices=IndicesConstPtr())
Provide a pointer to the input data set, if user has focal length he must set it before calling this...
Definition: organized.h:129
bool isOrganized() const
Return whether a dataset is organized (e.g., arranged in a structured grid).
Definition: point_cloud.h:331
OrganizedNeighbor is a class for optimized nearest neigbhor search in organized point clouds...
Definition: organized.h:62