ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
image_viewer.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #ifdef _MSC_VER
9 #pragma warning(disable : 4996) // Use of [[deprecated]] feature
10 #endif
11 
12 #include <pcl/common/time.h>
13 #include <pcl/visualization/common/float_image_utils.h>
14 #include <pcl/visualization/keyboard_event.h>
15 #include <pcl/visualization/mouse_event.h>
18 #include <vtkCallbackCommand.h>
19 #include <vtkCamera.h>
20 #include <vtkImageSlice.h>
21 #include <vtkImageSliceMapper.h>
22 #include <vtkImageViewer.h>
23 #include <vtkObjectFactory.h>
24 #include <vtkRenderer.h>
25 #include <vtkVersion.h>
26 
28 pcl::visualization::ImageViewer::ImageViewer(const std::string& window_title)
29  : mouse_command_(vtkSmartPointer<vtkCallbackCommand>::New()),
30  keyboard_command_(vtkSmartPointer<vtkCallbackCommand>::New()),
31  win_(vtkSmartPointer<vtkRenderWindow>::New()),
32  ren_(vtkSmartPointer<vtkRenderer>::New()),
33  slice_(vtkSmartPointer<vtkImageSlice>::New()),
34  interactor_style_(vtkSmartPointer<ImageViewerInteractorStyle>::New()),
35  data_size_(0),
36  stopped_(),
37  timer_id_(),
38  algo_(vtkSmartPointer<vtkImageFlip>::New()) {
41 
42  // Prepare for image flip
43  algo_->SetInterpolationModeToCubic();
44  algo_->PreserveImageExtentOn();
45  algo_->FlipAboutOriginOn();
46  algo_->SetFilteredAxis(1);
47 
48  // blend_->SetBlendModeToNormal ();
49  // blend_->SetNumberOfThreads (1);
50 
51  // Set the mouse/keyboard callbacks
52  mouse_command_->SetClientData(this);
54 
55  keyboard_command_->SetClientData(this);
57 
58  // Create our own interactor and set the window title
59  win_->SetSize(640, 480);
60  win_->AddRenderer(ren_);
61  win_->SetWindowName(window_title.c_str());
62  interactor_->SetRenderWindow(win_);
63 
64  vtkSmartPointer<vtkImageData> empty_image =
68  map->SetInputData(empty_image);
69  slice_->SetMapper(map);
70  ren_->AddViewProp(slice_);
71  ren_->GetActiveCamera()->ParallelProjectionOn();
72  interactor_->SetInteractorStyle(interactor_style_);
73 
74  // Initialize and create timer
75  // must comment this two lines to avoid crash on ubuntu2204
76  // interactor_->Initialize();
77  // timer_id_ = interactor_->CreateRepeatingTimer(0);
78 
79  // Set the exit callbacks
82  exit_main_loop_timer_callback_->window = this;
83  exit_main_loop_timer_callback_->right_timer_id = -1;
84  interactor_->AddObserver(vtkCommand::TimerEvent,
86 
88  exit_callback_->window = this;
89  interactor_->AddObserver(vtkCommand::ExitEvent, exit_callback_);
90 
91  // reset camera (flip it vertically)
93 
94  PCL_DEBUG("[pcl::visualization::ImageViewer] VTK version found: %d.%d\n",
95  VTK_MAJOR_VERSION, VTK_MINOR_VERSION);
96 }
97 
100  interactor_->DestroyTimer(timer_id_);
101 }
102 
104 void pcl::visualization::ImageViewer::addRGBImage(const unsigned char* rgb_data,
105  unsigned width,
106  unsigned height,
107  const std::string& layer_id,
108  double opacity,
109  bool autoresize) {
110  if (autoresize &&
111  (unsigned(getSize()[0]) != width || unsigned(getSize()[1]) != height))
112  setSize(width, height);
113 
114  // Check to see if this ID entry already exists (has it been already added
115  // to the visualizer?)
116  LayerMap::iterator am_it = std::find_if(
117  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
118  if (am_it == layer_map_.end()) {
119  PCL_DEBUG(
120  "[pcl::visualization::ImageViewer::addRGBImage] No layer with "
121  "ID='%s' found. Creating new one...\n",
122  layer_id.c_str());
123  am_it = createLayer(layer_id, width, height, opacity, false);
124  }
125 
126  void* data = const_cast<void*>(reinterpret_cast<const void*>(rgb_data));
127 
129  image->SetExtent(0, width - 1, 0, height - 1, 0, 0);
130  image->AllocateScalars(VTK_UNSIGNED_CHAR, 3);
131  image->GetPointData()->GetScalars()->SetVoidArray(data, 3 * width * height,
132  1);
133  algo_->SetInputData(image);
134  algo_->Update();
135  slice_->GetMapper()->SetInputConnection(algo_->GetOutputPort());
136  ren_->ResetCamera();
137  ren_->GetActiveCamera()->SetParallelScale(0.5 * win_->GetSize()[1]);
138 }
139 
142  const unsigned char* rgb_data,
143  unsigned width,
144  unsigned height,
145  const std::string& layer_id,
146  double opacity) {
147  addRGBImage(rgb_data, width, height, layer_id, opacity);
148  render();
149 }
150 
153  const unsigned char* rgb_data,
154  unsigned width,
155  unsigned height,
156  const std::string& layer_id,
157  double opacity) {
158  if (unsigned(getSize()[0]) != width || unsigned(getSize()[1]) != height)
159  setSize(width, height);
160 
161  // Check to see if this ID entry already exists (has it been already added
162  // to the visualizer?)
163  LayerMap::iterator am_it = std::find_if(
164  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
165  if (am_it == layer_map_.end()) {
166  PCL_DEBUG(
167  "[pcl::visualization::ImageViewer::showMonoImage] No layer "
168  "with ID='%s' found. Creating new one...\n",
169  layer_id.c_str());
170  am_it = createLayer(layer_id, width, height, opacity, false);
171  }
172 
173  void* data = const_cast<void*>(reinterpret_cast<const void*>(rgb_data));
174 
176  image->SetExtent(0, width - 1, 0, height - 1, 0, 0);
177  image->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
178  image->GetPointData()->GetScalars()->SetVoidArray(data, width * height, 1);
179 
180  algo_->SetInputData(image);
181  algo_->Update();
182  slice_->GetMapper()->SetInputConnection(algo_->GetOutputPort());
183  ren_->ResetCamera();
184  ren_->GetActiveCamera()->SetParallelScale(0.5 * win_->GetSize()[1]);
185 }
186 
189  const unsigned char* rgb_data,
190  unsigned width,
191  unsigned height,
192  const std::string& layer_id,
193  double opacity) {
194  addMonoImage(rgb_data, width, height, layer_id, opacity);
195  render();
196 }
197 
200  const pcl::PointCloud<pcl::Intensity>& cloud,
201  const std::string& layer_id,
202  double opacity) {
203  if (data_size_ < cloud.width * cloud.height) {
204  data_size_ = cloud.width * cloud.height * 3;
205  data_.reset(new unsigned char[data_size_]);
206  }
207 
208  convertIntensityCloudToUChar(cloud, data_);
209 
210  return (addMonoImage(data_.get(), cloud.width, cloud.height, layer_id,
211  opacity));
212 }
213 
216  const pcl::PointCloud<pcl::Intensity>& cloud,
217  const std::string& layer_id,
218  double opacity) {
219  addMonoImage(cloud, layer_id, opacity);
220  render();
221 }
222 
225  const pcl::PointCloud<pcl::Intensity8u>& cloud,
226  const std::string& layer_id,
227  double opacity) {
228  if (data_size_ < cloud.width * cloud.height) {
229  data_size_ = cloud.width * cloud.height * 3;
230  data_.reset(new unsigned char[data_size_]);
231  }
232 
233  convertIntensityCloud8uToUChar(cloud, data_);
234 
235  return (addMonoImage(data_.get(), cloud.width, cloud.height, layer_id,
236  opacity));
237 }
238 
241  const pcl::PointCloud<pcl::Intensity8u>& cloud,
242  const std::string& layer_id,
243  double opacity) {
244  addMonoImage(cloud, layer_id, opacity);
245  render();
246 }
247 
250  unsigned int width,
251  unsigned int height,
252  float min_value,
253  float max_value,
254  bool grayscale,
255  const std::string& layer_id,
256  double opacity) {
257  unsigned char* rgb_image = FloatImageUtils::getVisualImage(
258  float_image, width, height, min_value, max_value, grayscale);
259  addRGBImage(rgb_image, width, height, layer_id, opacity);
260  image_data_.push_back(rgb_image);
261 }
262 
265  const float* float_image,
266  unsigned int width,
267  unsigned int height,
268  float min_value,
269  float max_value,
270  bool grayscale,
271  const std::string& layer_id,
272  double opacity) {
273  addFloatImage(float_image, width, height, min_value, max_value, grayscale,
274  layer_id, opacity);
275  render();
276 }
277 
280  unsigned int width,
281  unsigned int height,
282  const std::string& layer_id,
283  double opacity) {
284  unsigned char* rgb_image =
285  FloatImageUtils::getVisualAngleImage(angle_image, width, height);
286  addRGBImage(rgb_image, width, height, layer_id, opacity);
287  image_data_.push_back(rgb_image);
288 }
289 
292  const float* angle_image,
293  unsigned int width,
294  unsigned int height,
295  const std::string& layer_id,
296  double opacity) {
297  addAngleImage(angle_image, width, height, layer_id, opacity);
298  render();
299 }
300 
303  const float* angle_image,
304  unsigned int width,
305  unsigned int height,
306  const std::string& layer_id,
307  double opacity) {
308  unsigned char* rgb_image = FloatImageUtils::getVisualHalfAngleImage(
309  angle_image, width, height);
310  addRGBImage(rgb_image, width, height, layer_id, opacity);
311  image_data_.push_back(rgb_image);
312 }
313 
316  const float* angle_image,
317  unsigned int width,
318  unsigned int height,
319  const std::string& layer_id,
320  double opacity) {
321  addHalfAngleImage(angle_image, width, height, layer_id, opacity);
322  render();
323 }
324 
327  const unsigned short* short_image,
328  unsigned int width,
329  unsigned int height,
330  unsigned short min_value,
331  unsigned short max_value,
332  bool grayscale,
333  const std::string& layer_id,
334  double opacity) {
335  unsigned char* rgb_image = FloatImageUtils::getVisualImage(
336  short_image, width, height, min_value, max_value, grayscale);
337  addRGBImage(rgb_image, width, height, layer_id, opacity);
338  image_data_.push_back(rgb_image);
339 }
340 
343  const unsigned short* short_image,
344  unsigned int width,
345  unsigned int height,
346  unsigned short min_value,
347  unsigned short max_value,
348  bool grayscale,
349  const std::string& layer_id,
350  double opacity) {
351  addShortImage(short_image, width, height, min_value, max_value, grayscale,
352  layer_id, opacity);
353  render();
354 }
355 
358  render();
359  resetStoppedFlag();
360  // Render the window before we start the interactor
361  // interactor_->Render ();
362  interactor_->Start();
363 }
364 
366 void pcl::visualization::ImageViewer::spinOnce(int time, bool force_redraw) {
367  if (force_redraw) {
368  render();
369  // interactor_->Render ();
370  }
371 
372  if (time <= 0) time = 1;
373 
374  DO_EVERY(1.0 / interactor_->GetDesiredUpdateRate(),
375  exit_main_loop_timer_callback_->right_timer_id =
376  interactor_->CreateRepeatingTimer(time);
377  interactor_->Start(); interactor_->DestroyTimer(
378  exit_main_loop_timer_callback_->right_timer_id););
379  for (auto& i : image_data_) delete[] i;
380  image_data_.clear();
381 }
382 
384 boost::signals2::connection
386  std::function<void(const pcl::visualization::MouseEvent&)> callback) {
387  // just add observer at first time when a callback is registered
388  if (mouse_signal_.empty()) {
389  interactor_->GetInteractorStyle()->AddObserver(
390  vtkCommand::MouseMoveEvent, mouse_command_);
391  interactor_->GetInteractorStyle()->AddObserver(
392  vtkCommand::MiddleButtonPressEvent, mouse_command_);
393  interactor_->GetInteractorStyle()->AddObserver(
394  vtkCommand::MiddleButtonReleaseEvent, mouse_command_);
395  interactor_->GetInteractorStyle()->AddObserver(
396  vtkCommand::MouseWheelBackwardEvent, mouse_command_);
397  interactor_->GetInteractorStyle()->AddObserver(
398  vtkCommand::MouseWheelForwardEvent, mouse_command_);
399  interactor_->GetInteractorStyle()->AddObserver(
400  vtkCommand::LeftButtonPressEvent, mouse_command_);
401  interactor_->GetInteractorStyle()->AddObserver(
402  vtkCommand::LeftButtonReleaseEvent, mouse_command_);
403  interactor_->GetInteractorStyle()->AddObserver(
404  vtkCommand::RightButtonPressEvent, mouse_command_);
405  interactor_->GetInteractorStyle()->AddObserver(
406  vtkCommand::RightButtonReleaseEvent, mouse_command_);
407  }
408  return (mouse_signal_.connect(callback));
409 }
410 
412 boost::signals2::connection
414  std::function<void(const pcl::visualization::KeyboardEvent&)>
415  callback) {
416  // just add observer at first time when a callback is registered
417  if (keyboard_signal_.empty()) {
418  interactor_->AddObserver(vtkCommand::KeyPressEvent, keyboard_command_);
419  interactor_->AddObserver(vtkCommand::KeyReleaseEvent,
420  keyboard_command_);
421  }
422 
423  return (keyboard_signal_.connect(callback));
424 }
425 
428  // interactor_->GetMousePosition (&x, &y);
429  int x = this->interactor_->GetEventPosition()[0];
430  int y = this->interactor_->GetEventPosition()[1];
431  MouseEvent event(MouseEvent::MouseMove, MouseEvent::NoButton, x, y,
432  interactor_->GetAltKey(), interactor_->GetControlKey(),
433  interactor_->GetShiftKey());
434  bool repeat = false;
435  switch (event_id) {
436  case vtkCommand::MouseMoveEvent:
437  event.setType(MouseEvent::MouseMove);
438  break;
439 
440  case vtkCommand::LeftButtonPressEvent:
441  event.setButton(MouseEvent::LeftButton);
442  if (interactor_->GetRepeatCount() == 0)
443  event.setType(MouseEvent::MouseButtonPress);
444  else
445  event.setType(MouseEvent::MouseDblClick);
446  break;
447 
448  case vtkCommand::LeftButtonReleaseEvent:
449  event.setButton(MouseEvent::LeftButton);
450  event.setType(MouseEvent::MouseButtonRelease);
451  break;
452 
453  case vtkCommand::RightButtonPressEvent:
454  event.setButton(MouseEvent::RightButton);
455  if (interactor_->GetRepeatCount() == 0)
456  event.setType(MouseEvent::MouseButtonPress);
457  else
458  event.setType(MouseEvent::MouseDblClick);
459  break;
460 
461  case vtkCommand::RightButtonReleaseEvent:
462  event.setButton(MouseEvent::RightButton);
463  event.setType(MouseEvent::MouseButtonRelease);
464  break;
465 
466  case vtkCommand::MiddleButtonPressEvent:
467  event.setButton(MouseEvent::MiddleButton);
468  if (interactor_->GetRepeatCount() == 0)
469  event.setType(MouseEvent::MouseButtonPress);
470  else
471  event.setType(MouseEvent::MouseDblClick);
472  break;
473 
474  case vtkCommand::MiddleButtonReleaseEvent:
475  event.setButton(MouseEvent::MiddleButton);
476  event.setType(MouseEvent::MouseButtonRelease);
477  break;
478 
479  case vtkCommand::MouseWheelBackwardEvent:
480  event.setButton(MouseEvent::VScroll);
481  event.setType(MouseEvent::MouseScrollDown);
482  if (interactor_->GetRepeatCount() != 0) repeat = true;
483  break;
484 
485  case vtkCommand::MouseWheelForwardEvent:
486  event.setButton(MouseEvent::VScroll);
487  event.setType(MouseEvent::MouseScrollUp);
488  if (interactor_->GetRepeatCount() != 0) repeat = true;
489  break;
490  default:
491  return;
492  }
493 
494  mouse_signal_(event);
495  if (repeat) mouse_signal_(event);
496 }
497 
500  unsigned long event_id) {
501  KeyboardEvent event(bool(event_id == vtkCommand::KeyPressEvent),
502  interactor_->GetKeySym(), interactor_->GetKeyCode(),
503  interactor_->GetAltKey(), interactor_->GetControlKey(),
504  interactor_->GetShiftKey());
505  keyboard_signal_(event);
506 }
507 
510  unsigned long eid,
511  void* clientdata,
512  void*) {
513  ImageViewer* window = reinterpret_cast<ImageViewer*>(clientdata);
514  window->emitMouseEvent(eid);
515 }
516 
519  unsigned long eid,
520  void* clientdata,
521  void*) {
522  ImageViewer* window = reinterpret_cast<ImageViewer*>(clientdata);
523  window->emitKeyboardEvent(eid);
524 }
525 
527 pcl::visualization::ImageViewer::LayerMap::iterator
529  int width,
530  int height,
531  double opacity,
532  bool fill_box) {
533  Layer l;
534  l.layer_name = layer_id;
535  // Create a new layer
537  l.actor->PickableOff();
538  l.actor->DragableOff();
539  if (fill_box) {
542  rect->setColors(0, 0, 0);
543  rect->setOpacity(opacity);
544  rect->set(0, 0, static_cast<float>(width), static_cast<float>(height));
545  l.actor->GetScene()->AddItem(rect);
546  }
547  ren_->AddActor(l.actor);
548  // Add another element
549  layer_map_.push_back(l);
550 
551  return (layer_map_.end() - 1);
552 }
553 
555 bool pcl::visualization::ImageViewer::addLayer(const std::string& layer_id,
556  int width,
557  int height,
558  double opacity) {
559  // Check to see if this ID entry already exists (has it been already added
560  // to the visualizer?)
561  LayerMap::iterator am_it = std::find_if(
562  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
563  if (am_it != layer_map_.end()) {
564  PCL_DEBUG(
565  "[pcl::visualization::ImageViewer::addLayer] Layer with "
566  "ID='%s' already exists!\n",
567  layer_id.c_str());
568  return (false);
569  }
570 
571  createLayer(layer_id, width, height, opacity, false);
572 
573  return (true);
574 }
575 
577 void pcl::visualization::ImageViewer::removeLayer(const std::string& layer_id) {
578  // Check to see if this ID entry already exists (has it been already added
579  // to the visualizer?)
580  LayerMap::iterator am_it = std::find_if(
581  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
582  if (am_it == layer_map_.end()) {
583  PCL_DEBUG(
584  "[pcl::visualization::ImageViewer::removeLayer] No layer with "
585  "ID='%s' found.\n",
586  layer_id.c_str());
587  return;
588  }
589  ren_->RemoveActor(am_it->actor);
590  layer_map_.erase(am_it);
591 }
592 
595  unsigned int y,
596  double radius,
597  double r,
598  double g,
599  double b,
600  const std::string& layer_id,
601  double opacity) {
602  // Check to see if this ID entry already exists (has it been already added
603  // to the visualizer?)
604  LayerMap::iterator am_it = std::find_if(
605  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
606  if (am_it == layer_map_.end()) {
607  PCL_DEBUG(
608  "[pcl::visualization::ImageViewer::addCircle] No layer with "
609  "ID='%s' found. Creating new one...\n",
610  layer_id.c_str());
611  am_it = createLayer(layer_id, getSize()[0] - 1, getSize()[1] - 1,
612  opacity, false);
613  }
614 
617  circle->setColors(static_cast<unsigned char>(255.0 * r),
618  static_cast<unsigned char>(255.0 * g),
619  static_cast<unsigned char>(255.0 * b));
620  circle->setOpacity(opacity);
621  circle->set(static_cast<float>(x), static_cast<float>(y),
622  static_cast<float>(radius));
623  am_it->actor->GetScene()->AddItem(circle);
624 
625  return (true);
626 }
627 
630  unsigned int y,
631  double radius,
632  const std::string& layer_id,
633  double opacity) {
634  return (addCircle(x, y, radius, 0.0, 1.0, 0.0, layer_id, opacity));
635 }
636 
639  unsigned int x_min,
640  unsigned int x_max,
641  unsigned int y_min,
642  unsigned int y_max,
643  double r,
644  double g,
645  double b,
646  const std::string& layer_id,
647  double opacity) {
648  // Check to see if this ID entry already exists (has it been already added
649  // to the visualizer?)
650  LayerMap::iterator am_it = std::find_if(
651  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
652  if (am_it == layer_map_.end()) {
653  PCL_DEBUG(
654  "[pcl::visualization::ImageViewer::addFilledRectangle] No "
655  "layer with ID='%s' found. Creating new one...\n",
656  layer_id.c_str());
657  am_it = createLayer(layer_id, getSize()[0] - 1, getSize()[1] - 1,
658  opacity, false);
659  }
660 
663  rect->setColors(static_cast<unsigned char>(255.0 * r),
664  static_cast<unsigned char>(255.0 * g),
665  static_cast<unsigned char>(255.0 * b));
666  rect->setOpacity(opacity);
667  rect->set(static_cast<float>(x_min), static_cast<float>(y_min),
668  static_cast<float>(x_max - x_min),
669  static_cast<float>(y_max - y_min));
670  am_it->actor->GetScene()->AddItem(rect);
671 
672  return (true);
673 }
674 
677  unsigned int x_min,
678  unsigned int x_max,
679  unsigned int y_min,
680  unsigned int y_max,
681  const std::string& layer_id,
682  double opacity) {
683  return (addFilledRectangle(x_min, x_max, y_min, y_max, 0.0, 1.0, 0.0,
684  layer_id, opacity));
685 }
686 
689  unsigned int x_max,
690  unsigned int y_min,
691  unsigned int y_max,
692  double r,
693  double g,
694  double b,
695  const std::string& layer_id,
696  double opacity) {
697  // Check to see if this ID entry already exists (has it been already added
698  // to the visualizer?)
699  LayerMap::iterator am_it = std::find_if(
700  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
701  if (am_it == layer_map_.end()) {
702  PCL_DEBUG(
703  "[pcl::visualization::ImageViewer::addRectangle] No layer with "
704  "ID='%s' found. Creating new one...\n",
705  layer_id.c_str());
706  am_it = createLayer(layer_id, getSize()[0] - 1, getSize()[1] - 1,
707  opacity, false);
708  }
709 
712  rect->setColors(static_cast<unsigned char>(255.0 * r),
713  static_cast<unsigned char>(255.0 * g),
714  static_cast<unsigned char>(255.0 * b));
715  rect->setOpacity(opacity);
716  rect->set(static_cast<float>(x_min), static_cast<float>(y_min),
717  static_cast<float>(x_max), static_cast<float>(y_max));
718  am_it->actor->GetScene()->AddItem(rect);
719 
720  return (true);
721 }
722 
725  unsigned int x_max,
726  unsigned int y_min,
727  unsigned int y_max,
728  const std::string& layer_id,
729  double opacity) {
730  return (addRectangle(x_min, x_max, y_min, y_max, 0.0, 1.0, 0.0, layer_id,
731  opacity));
732 }
733 
735 bool pcl::visualization::ImageViewer::addRectangle(const pcl::PointXY& min_pt,
736  const pcl::PointXY& max_pt,
737  double r,
738  double g,
739  double b,
740  const std::string& layer_id,
741  double opacity) {
742  // Check to see if this ID entry already exists (has it been already added
743  // to the visualizer?)
744  LayerMap::iterator am_it = std::find_if(
745  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
746  if (am_it == layer_map_.end()) {
747  PCL_DEBUG(
748  "[pcl::visualization::ImageViewer::addRectangle] No layer with "
749  "ID='%s' found. Creating new one...\n",
750  layer_id.c_str());
751  am_it = createLayer(layer_id, getSize()[0] - 1, getSize()[1] - 1,
752  opacity, false);
753  }
754 
757  rect->setColors(static_cast<unsigned char>(255.0 * r),
758  static_cast<unsigned char>(255.0 * g),
759  static_cast<unsigned char>(255.0 * b));
760  rect->setOpacity(opacity);
761  rect->set(min_pt.x, min_pt.y, max_pt.x, max_pt.y);
762  am_it->actor->GetScene()->AddItem(rect);
763 
764  return (true);
765 }
766 
768 bool pcl::visualization::ImageViewer::addRectangle(const pcl::PointXY& min_pt,
769  const pcl::PointXY& max_pt,
770  const std::string& layer_id,
771  double opacity) {
772  return (addRectangle(min_pt, max_pt, 0.0, 1.0, 0.0, layer_id, opacity));
773 }
774 
777  unsigned int y_min,
778  unsigned int x_max,
779  unsigned int y_max,
780  double r,
781  double g,
782  double b,
783  const std::string& layer_id,
784  double opacity) {
785  // Check to see if this ID entry already exists (has it been already added
786  // to the visualizer?)
787  LayerMap::iterator am_it = std::find_if(
788  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
789  if (am_it == layer_map_.end()) {
790  PCL_DEBUG(
791  "[pcl::visualization::ImageViewer::addLine] No layer with "
792  "ID='%s' found. Creating new one...\n",
793  layer_id.c_str());
794  am_it = createLayer(layer_id, getSize()[0] - 1, getSize()[1] - 1,
795  opacity, false);
796  }
797 
800  line->setColors(static_cast<unsigned char>(255.0 * r),
801  static_cast<unsigned char>(255.0 * g),
802  static_cast<unsigned char>(255.0 * b));
803  line->setOpacity(opacity);
804  line->set(static_cast<float>(x_min), static_cast<float>(y_min),
805  static_cast<float>(x_max), static_cast<float>(y_max));
806  am_it->actor->GetScene()->AddItem(line);
807 
808  return (true);
809 }
810 
813  unsigned int y_min,
814  unsigned int x_max,
815  unsigned int y_max,
816  const std::string& layer_id,
817  double opacity) {
818  return (addLine(x_min, y_min, x_max, y_max, 0.0, 1.0, 0.0, layer_id,
819  opacity));
820 }
821 
824  unsigned int y,
825  const std::string& text_string,
826  double r,
827  double g,
828  double b,
829  const std::string& layer_id,
830  double opacity) {
831  // Check to see if this ID entry already exists (has it been already added
832  // to the visualizer?)
833  LayerMap::iterator am_it = std::find_if(
834  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
835  if (am_it == layer_map_.end()) {
836  PCL_DEBUG(
837  "[pcl::visualization::ImageViewer::addText] No layer with "
838  "ID='%s' found. Creating new one...\n",
839  layer_id.c_str());
840  am_it = createLayer(layer_id, getSize()[0] - 1, getSize()[1] - 1,
841  opacity, false);
842  }
843 
846  text->setColors(static_cast<unsigned char>(255.0 * r),
847  static_cast<unsigned char>(255.0 * g),
848  static_cast<unsigned char>(255.0 * b));
849  text->setOpacity(opacity);
850  text->set(static_cast<float>(x), static_cast<float>(y), text_string);
851  am_it->actor->GetScene()->AddItem(text);
852 
853  return (true);
854 }
855 
858  unsigned int y,
859  const std::string& text,
860  const std::string& layer_id,
861  double opacity) {
862  return (addText(x, y, text, 0.0, 1.0, 0.0, layer_id, opacity));
863 }
864 
867  std::size_t v,
868  Vector3ub fg_color,
869  Vector3ub bg_color,
870  double radius,
871  const std::string& layer_id,
872  double opacity) {
873  // Check to see if this ID entry already exists (has it been already added
874  // to the visualizer?)
875  LayerMap::iterator am_it = std::find_if(
876  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
877  if (am_it == layer_map_.end()) {
878  PCL_DEBUG(
879  "[pcl::visualization::ImageViewer::markPoint] No layer with "
880  "ID='%s' found. Creating new one...\n",
881  layer_id.c_str());
882  am_it = createLayer(layer_id, getSize()[0] - 1, getSize()[1] - 1,
883  opacity, false);
884  }
885 
888  point->setColors(fg_color[0], fg_color[1], fg_color[2]);
889  point->setOpacity(opacity);
890 
893  disk->setColors(bg_color[0], bg_color[1], bg_color[2]);
894  disk->setOpacity(opacity);
895 
896  point->set(static_cast<float>(u), static_cast<float>(v));
897  disk->set(static_cast<float>(u), static_cast<float>(v),
898  static_cast<float>(radius));
899 
900  am_it->actor->GetScene()->AddItem(disk);
901  am_it->actor->GetScene()->AddItem(point);
902 }
903 
905 void pcl::visualization::ImageViewer::markPoints(const std::vector<int>& uv,
906  Vector3ub fg_color,
907  Vector3ub bg_color,
908  double size,
909  const std::string& layer_id,
910  double opacity) {
911  if (uv.empty()) return;
912 
913  std::vector<float> float_uv(uv.size());
914  for (std::size_t i = 0; i < uv.size(); ++i)
915  float_uv[i] = static_cast<float>(uv[i]);
916  return (markPoints(float_uv, fg_color, bg_color, size, layer_id, opacity));
917 }
918 
920 void pcl::visualization::ImageViewer::markPoints(const std::vector<float>& uv,
921  Vector3ub fg_color,
922  Vector3ub bg_color,
923  double size,
924  const std::string& layer_id,
925  double opacity) {
926  if (uv.empty()) return;
927 
928  // Check to see if this ID entry already exists (has it been already added
929  // to the visualizer?)
930  LayerMap::iterator am_it = std::find_if(
931  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
932  if (am_it == layer_map_.end()) {
933  PCL_DEBUG(
934  "[pcl::visualization::ImageViewer::markPoint] No layer with "
935  "ID='%s' found. Creating new one...\n",
936  layer_id.c_str());
937  am_it = createLayer(layer_id, getSize()[0] - 1, getSize()[1] - 1,
938  opacity, false);
939  }
940 
943  markers->setOpacity(opacity);
944  markers->set(uv);
945  markers->setSize(size);
946  markers->setColors(bg_color[0], bg_color[1], bg_color[2]);
947  markers->setPointColors(fg_color[0], fg_color[1], fg_color[2]);
948  am_it->actor->GetScene()->AddItem(markers);
949 }
950 
953  win_->Render();
954  for (auto& i : image_data_) delete[] i;
955  image_data_.clear();
956 }
957 
960  const pcl::PointCloud<pcl::Intensity>& cloud,
961  boost::shared_array<unsigned char> data) {
962  int j = 0;
963  for (const auto& point : cloud.points) {
964  data[j++] = static_cast<unsigned char>(point.intensity * 255);
965  }
966 }
967 
970  const pcl::PointCloud<pcl::Intensity8u>& cloud,
971  boost::shared_array<unsigned char> data) {
972  int j = 0;
973  for (const auto& point : cloud.points)
974  data[j++] = static_cast<unsigned char>(point.intensity);
975 }
976 
981 
984  FindPokedRenderer(Interactor->GetEventPosition()[0],
985  Interactor->GetEventPosition()[1]);
986 
987  Superclass::OnChar();
988 }
989 
992  vtkImageData* image, vtkRenderer* ren) {
993  // Set up the background camera to fill the renderer with the image
994  double origin[3], spacing[3];
995  int extent[6];
996  image->GetOrigin(origin);
997  image->GetSpacing(spacing);
998  image->GetExtent(extent);
999 
1000  vtkCamera* camera = ren->GetActiveCamera();
1001  double xc = origin[0] + 0.5 * (extent[0] + extent[1]) * spacing[0];
1002  double yc = origin[1] + 0.5 * (extent[2] + extent[3]) * spacing[1];
1003  double yd = (extent[3] - extent[2] + 1) * spacing[1];
1004  double d = camera->GetDistance();
1005  camera->SetParallelScale(0.5 * yd);
1006  camera->SetFocalPoint(xc, yc, 0.0);
1007  camera->SetPosition(xc, yc, d);
1008 }
1009 
1012  vtkRenderer* ren) {
1013  // Set up the background camera to fill the renderer with the image
1014  vtkCamera* camera = ren->GetActiveCamera();
1015  int* wh = ren->GetRenderWindow()->GetSize();
1016  double xc = static_cast<double>(wh[0]) / 2.0,
1017  yc = static_cast<double>(wh[1]) / 2.0,
1018  yd = static_cast<double>(wh[1]), d = 3.346065;
1019  camera->SetParallelScale(0.5 * yd);
1020  camera->SetFocalPoint(xc, yc, 0.0);
1021  camera->SetPosition(xc, yc, d);
1022 }
1023 
1026  int x = Interactor->GetEventPosition()[0];
1027  int y = Interactor->GetEventPosition()[1];
1028 
1029  FindPokedRenderer(x, y);
1030  if (!CurrentRenderer) return;
1031 
1032  // Redefine this button to handle window/level
1033  GrabFocus(this->EventCallbackCommand);
1034  // If shift is held down, do nothing
1035  if (!this->Interactor->GetShiftKey() &&
1036  !this->Interactor->GetControlKey()) {
1037  WindowLevelStartPosition[0] = x;
1038  WindowLevelStartPosition[1] = y;
1039  StartWindowLevel();
1040  } else if (Interactor->GetShiftKey())
1041  return;
1042  // If ctrl is held down in slicing mode, do nothing
1043  else if (Interactor->GetControlKey())
1044  return;
1045  // The rest of the button + key combinations remain the same
1046  else
1047  Superclass::OnLeftButtonDown();
1048 }
1049 
1052  win_->SetWindowName(name.c_str());
1053 }
1054 
1057  win_->SetPosition(x, y);
1058 }
1059 
1061 int* pcl::visualization::ImageViewer::getSize() { return (win_->GetSize()); }
1062 
1065  win_->SetSize(xw, yw);
1066 }
1067 
1069 namespace pcl {
1070 namespace visualization {
1072 }
1073 } // namespace pcl
MouseEvent event
std::shared_ptr< core::Tensor > image
std::function< void(std::shared_ptr< core::Tensor >)> callback
int width
int size
std::string name
int height
math::float2 uv
Eigen::Vector3d origin
Definition: VoxelGridIO.cpp:26
An image viewer interactor style, tailored for ImageViewer.
Definition: image_viewer.h:41
void adjustCamera(vtkImageData *image, vtkRenderer *ren)
ImageViewer is a class for 2D image visualization.
Definition: image_viewer.h:83
vtkSmartPointer< vtkRenderWindow > win_
The render window.
void setWindowTitle(const std::string &name)
Set the window title name.
static void MouseCallback(vtkObject *, unsigned long eid, void *clientdata, void *calldata)
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.
vtkSmartPointer< vtkCallbackCommand > keyboard_command_
void resetStoppedFlag()
Set the stopped flag back to false.
virtual ~ImageViewer()
Destructor.
int * getSize()
Return the window size in pixels.
void showAngleImage(const float *data, unsigned width, unsigned height, const std::string &layer_id="angle_image", double opacity=1.0)
Show a 2D image on screen representing angle data.
boost::signals2::connection registerMouseCallback(void(*callback)(const pcl::visualization::MouseEvent &, void *), void *cookie=nullptr)
Register a callback std::function for mouse events.
Definition: image_viewer.h:530
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.
void convertIntensityCloudToUChar(const pcl::PointCloud< pcl::Intensity > &cloud, boost::shared_array< unsigned char > data)
Convert the Intensity information in a PointCloud<Intensity> to an unsigned char array.
bool addFilledRectangle(unsigned int x_min, unsigned int x_max, unsigned int y_min, unsigned int y_max, const std::string &layer_id="boxes", double opacity=0.5)
Add a 2D box and fill it in with a given color.
void spinOnce(int time=1, bool force_redraw=true)
Spin once method. Calls the interactor and updates the screen once.
bool addLayer(const std::string &layer_id, int width, int height, double opacity=0.5)
Add a new 2D rendering layer to the viewer.
void removeLayer(const std::string &layer_id)
Remove a 2D layer given by its ID.
void addHalfAngleImage(const float *data, unsigned width, unsigned height, const std::string &layer_id="half_angle_image", double opacity=1.0)
Add a half angle 2D image layer, but do not render it (use spin/spinOnce to update).
boost::signals2::connection registerKeyboardCallback(void(*callback)(const pcl::visualization::KeyboardEvent &, void *), void *cookie=nullptr)
Register a callback function for keyboard events.
Definition: image_viewer.h:488
vtkSmartPointer< vtkImageSlice > slice_
Global prop. This is the actual "actor".
bool addText(unsigned int x, unsigned int y, const std::string &text, double r, double g, double b, const std::string &layer_id="line", double opacity=1.0)
Add a 2D text with a given color.
void addMonoImage(const unsigned char *data, unsigned width, unsigned height, const std::string &layer_id="mono_image", double opacity=1.0)
Add a monochrome 2D image layer, but do not render it (use spin/spinOnce to update).
void showFloatImage(const float *data, unsigned int width, unsigned int height, float min_value=std::numeric_limits< float >::min(), float max_value=std::numeric_limits< float >::max(), bool grayscale=false, const std::string &layer_id="float_image", double opacity=1.0)
Show a 2D image (float) on screen.
void spin()
Spin method. Calls the interactor and runs an internal loop.
void markPoints(const std::vector< int > &uv, Vector3ub fg_color, Vector3ub bg_color=red_color, double size=3.0, const std::string &layer_id="markers", double opacity=1.0)
Sets the pixel at coordinates(u,v) to color while setting the neighborhood to another.
void showHalfAngleImage(const float *data, unsigned width, unsigned height, const std::string &layer_id="half_angle_image", double opacity=1.0)
Show a 2D image on screen representing half angle data.
bool addLine(unsigned int x_min, unsigned int y_min, unsigned int x_max, unsigned int y_max, double r, double g, double b, const std::string &layer_id="line", double opacity=1.0)
Add a 2D line with a given color.
void showShortImage(const unsigned short *short_image, unsigned int width, unsigned int height, unsigned short min_value=std::numeric_limits< unsigned short >::min(), unsigned short max_value=std::numeric_limits< unsigned short >::max(), bool grayscale=false, const std::string &layer_id="short_image", double opacity=1.0)
Show a 2D image (unsigned short) on screen.
void emitMouseEvent(unsigned long event_id)
Fire up a mouse event with a specified event ID.
void addShortImage(const unsigned short *short_image, unsigned int width, unsigned int height, unsigned short min_value=std::numeric_limits< unsigned short >::min(), unsigned short max_value=std::numeric_limits< unsigned short >::max(), bool grayscale=false, const std::string &layer_id="short_image", double opacity=1.0)
Add a short 2D image layer, but do not render it (use spin/spinOnce to update).
vtkSmartPointer< vtkRenderer > ren_
The renderer.
vtkSmartPointer< ExitMainLoopTimerCallback > exit_main_loop_timer_callback_
Callback object enabling us to leave the main loop, when a timer fires.
void showMonoImage(const unsigned char *data, unsigned width, unsigned height, const std::string &layer_id="mono_image", double opacity=1.0)
Show a monochrome 2D image on screen.
void emitKeyboardEvent(unsigned long event_id)
Fire up a keyboard event with a specified event ID.
ImageViewer(const std::string &window_title="")
Constructor.
void setSize(int xw, int yw)
Set the window size in screen coordinates.
vtkSmartPointer< vtkRenderWindowInteractor > interactor_
void addFloatImage(const float *data, unsigned int width, unsigned int height, float min_value=std::numeric_limits< float >::min(), float max_value=std::numeric_limits< float >::max(), bool grayscale=false, const std::string &layer_id="float_image", double opacity=1.0)
Add a float 2D image layer, but do not render it (use spin/spinOnce to update).
static void KeyboardCallback(vtkObject *, unsigned long eid, void *clientdata, void *calldata)
void setPosition(int x, int y)
Set the position in screen coordinates.
void markPoint(std::size_t u, std::size_t v, Vector3ub fg_color, Vector3ub bg_color=red_color, double radius=3.0, const std::string &layer_id="points", double opacity=1.0)
Sets the pixel at coordinates(u,v) to color while setting the neighborhood to another.
vtkSmartPointer< ImageViewerInteractorStyle > interactor_style_
The interactor style.
void addAngleImage(const float *data, unsigned width, unsigned height, const std::string &layer_id="angle_image", double opacity=1.0)
Add an angle 2D image layer, but do not render it (use spin/spinOnce to update).
vtkSmartPointer< vtkCallbackCommand > mouse_command_
vtkSmartPointer< ExitCallback > exit_callback_
void render()
Trigger a render call.
void convertIntensityCloud8uToUChar(const pcl::PointCloud< pcl::Intensity8u > &cloud, boost::shared_array< unsigned char > data)
Convert the Intensity8u information in a PointCloud<Intensity8u> to an unsigned char array.
LayerMap::iterator createLayer(const std::string &layer_id, int width, int height, double opacity=0.5, bool fill_box=true)
Add a new 2D rendering layer to the viewer.
bool addCircle(unsigned int x, unsigned int y, double radius, const std::string &layer_id="circles", double opacity=1.0)
Add a circle shape from a point and a radius.
void addRGBImage(const unsigned char *data, unsigned width, unsigned height, const std::string &layer_id="rgb_image", double opacity=1.0, bool autoresize=true)
Add an RGB 2D image layer, but do not render it (use spin/spinOnce to update).
vtkSmartPointer< vtkImageFlip > algo_
Image reslice, used for flipping the image.
GraphType data
Definition: graph_cut.cc:138
normal_z y
normal_z x
Eigen::Array< unsigned char, 3, 1 > Vector3ub
Definition: image_viewer.h:32
vtkStandardNewMacro(ImageViewerInteractorStyle)
Internal structure describing a layer.
vtkSmartPointer< vtkContextActor > actor
vtkRenderWindowInteractor * vtkRenderWindowInteractorFixNew()