ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ImageVis.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 // Local
13 #include "ImageVis.h"
14 
15 #include <Utils/PCLConv.h>
16 
18 #include "Tools/Common/PclTools.h"
19 #include "Tools/Common/ecvTools.h"
20 
21 // CV_CORE_LIB
22 #include <CVPlatform.h>
23 #include <CVTools.h>
24 #include <Parallel.h>
25 #include <ecvGLMatrix.h>
26 
27 #ifdef _OPENMP
28 #include <omp.h>
29 #endif
30 
31 // Qt
32 #include <QImage>
33 
34 // CV_DB_LIB
35 #include <ecvBBox.h>
36 
37 // VTK
38 #include <vtkAxes.h>
39 #include <vtkAxesActor.h>
40 #include <vtkBMPReader.h>
41 #include <vtkCallbackCommand.h>
42 #include <vtkCamera.h>
43 #include <vtkCaptionActor2D.h>
44 #include <vtkCommand.h>
45 #include <vtkContext2D.h>
46 #include <vtkInteractorObserver.h>
47 #include <vtkInteractorStyleImage.h>
48 #include <vtkJPEGReader.h>
49 #include <vtkLookupTable.h>
50 #include <vtkMath.h>
51 #include <vtkOpenGLRenderWindow.h>
52 #include <vtkPNGReader.h>
53 #include <vtkPNMReader.h>
54 #include <vtkPropAssembly.h>
55 #include <vtkProperty.h>
56 #include <vtkQImageToImageSource.h>
57 #include <vtkRenderWindow.h>
58 #include <vtkRenderWindowInteractor.h>
59 #include <vtkRenderer.h>
60 #include <vtkRendererCollection.h>
61 #include <vtkTIFFReader.h>
62 #include <vtkTextProperty.h>
63 #include <vtkTextureUnitManager.h>
64 #include <vtkTransform.h>
65 #include <vtkUnsignedCharArray.h>
66 
67 #if VTK_MAJOR_VERSION >= 6
69 #include <vtkImageProperty.h>
70 #include <vtkImageSlice.h>
71 #include <vtkImageSliceMapper.h>
72 #endif
73 
74 // PCL
75 #include <pcl/common/transforms.h>
76 #include <pcl/visualization/common/float_image_utils.h>
79 
80 // Support for VTK 7.1 upwards
81 #ifdef vtkGenericDataArray_h
82 #define SetTupleValue SetTypedTuple
83 #define InsertNextTupleValue InsertNextTypedTuple
84 #define GetTupleValue GetTypedTuple
85 #endif
86 
87 // SYSTEM
88 #include <algorithm>
89 #include <cstring>
90 #include <map>
91 
92 using namespace std;
93 
94 namespace PclUtils {
95 ImageVis::ImageVis(const string& viewerName, bool initIterator)
96  : pcl::visualization::ImageViewer(viewerName), m_cameraParamsSaved(false) {
97  // Initialize camera params
98  m_originalCameraParams.parallelProjection = false;
99  m_originalCameraParams.focalPoint[0] =
100  m_originalCameraParams.focalPoint[1] =
101  m_originalCameraParams.focalPoint[2] = 0.0;
102  m_originalCameraParams.position[0] = m_originalCameraParams.position[1] =
103  m_originalCameraParams.position[2] = 0.0;
104  m_originalCameraParams.viewUp[0] = m_originalCameraParams.viewUp[1] =
105  m_originalCameraParams.viewUp[2] = 0.0;
106  m_originalCameraParams.viewAngle = 30.0;
107  m_originalCameraParams.parallelScale = 1.0;
108  m_originalCameraParams.clippingRange[0] = 0.01;
109  m_originalCameraParams.clippingRange[1] = 1000.0;
110 }
111 
113  return this->win_;
114 }
115 
119  if (!win || !interactor) {
120  return;
121  }
122 
123  setRenderWindow(win);
124  setRenderWindowInteractor(interactor);
125  getRenderWindow()->Render();
126 }
127 
128 void ImageVis::enable2Dviewer(bool state) {
129 #ifdef CV_LINUX
131  "[ImageVis::enable2Dviewer] Do not support 2D viewer on Linux or "
132  "Mac platform now!");
133  return;
134 #endif
135  if (state) {
136  m_mainInteractor = getRenderWindowInteractor();
140  getRenderWindow()->SetInteractor(getRenderWindowInteractor());
141  getRenderWindowInteractor()->SetRenderWindow(getRenderWindow());
142  m_mouseConnection =
143  registerMouseCallback(&ImageVis::mouseEventProcess, *this);
144  } else {
145  setupInteractor(m_mainInteractor, getRenderWindow());
146  getRenderWindow()->SetInteractor(getRenderWindowInteractor());
147  getRenderWindowInteractor()->SetRenderWindow(getRenderWindow());
148  m_mouseConnection.disconnect();
149  }
150 }
151 
152 void ImageVis::mouseEventProcess(const pcl::visualization::MouseEvent& event,
153  void* args) {
154  if (event.getButton() == pcl::visualization::MouseEvent::RightButton &&
155  event.getType() == pcl::visualization::MouseEvent::MouseMove) {
156  std::string id = pickItem(event);
157  if (id != "") {
158  CVLog::Print(QString("Picked item id : %1").arg(id.c_str()));
159  }
160  }
161 }
162 
163 std::string ImageVis::pickItem(const pcl::visualization::MouseEvent& event) {
164  int x = event.getX();
165  int y = event.getY();
166 
167  return pickItem(x, y);
168 }
169 
170 std::string ImageVis::pickItem(int x, int y) {
171  for (int i = 0; i < layer_map_.size(); ++i) {
172  Layer* layer = &layer_map_[i];
173  int index = 0;
174  while (layer->actor->GetScene()->GetItem(index)) {
176  reinterpret_cast<
178  layer->actor->GetScene()->GetItem(index));
179  if (context && context->params.size() == 4) {
180  bool containFlag =
181  (x >= context->params[0] &&
182  x <= context->params[0] + context->params[2] &&
183  y >= context->params[1] &&
184  y <= context->params[1] + context->params[3]);
185  if (containFlag) {
186  return layer->layer_name;
187  }
188  }
189  index++;
190  }
191  }
192  return std::string("");
193 }
194 
196  this->win_ = win;
197 
198  // Add window resize observer
199  if (win && !m_windowResizeCallback) {
200  m_windowResizeCallback = vtkSmartPointer<vtkCallbackCommand>::New();
201  m_windowResizeCallback->SetCallback(WindowResizeCallback);
202  m_windowResizeCallback->SetClientData(this);
203  win->AddObserver(vtkCommand::WindowResizeEvent, m_windowResizeCallback);
204  }
205 }
206 
209  return this->interactor_;
210 }
211 
214  this->interactor_ = interactor;
215 
216  // Save original interactor style if not already saved
217  // This is needed to prevent crashes when getCamera is called
218  if (interactor && !m_originalInteractorStyle) {
219  m_originalInteractorStyle = interactor->GetInteractorStyle();
220  }
221 
222  timer_id_ = this->interactor_->CreateRepeatingTimer(5000L);
223 
224  // Set the exit callbacks
227  exit_main_loop_timer_callback_->window = this;
228  exit_main_loop_timer_callback_->right_timer_id = -1;
229  this->interactor_->AddObserver(vtkCommand::TimerEvent,
231 
233  exit_callback_->window = this;
234  this->interactor_->AddObserver(vtkCommand::ExitEvent, exit_callback_);
235 
237 }
238 
240 
242  this->ren_ = render;
243  this->ren_->AddViewProp(slice_);
244 }
245 
246 bool ImageVis::contains(const std::string& id) const {
247  // Check layer_map_ first
248  LayerMap::const_iterator am_it = std::find_if(
249  layer_map_.begin(), layer_map_.end(), LayerComparator(id));
250  if (am_it != layer_map_.end()) {
251  return true;
252  }
253 
254  // Also check m_imageInfoMap for image layers
255 #if VTK_MAJOR_VERSION >= 6
256  auto it = m_imageInfoMap.find(id);
257  if (it != m_imageInfoMap.end() && it->second.imageSlice) {
258  return true;
259  }
260 #endif
261 
262  return false;
263 }
264 
266  const std::string& id) {
267  for (auto& l : layer_map_) {
268  if (l.layer_name == id) {
269  return &l;
270  }
271  }
272  return nullptr;
273 }
274 
275 void ImageVis::hideShowActors(bool visibility, const std::string& viewID) {
276  double opacity = visibility ? 1.0 : 0.0;
277 
278  // Handle regular layers in layer_map_
279  Layer* layer = getLayer(viewID);
280  if (layer) {
281  int index = 0;
282  while (layer->actor->GetScene()->GetItem(index)) {
283  layer->actor->GetScene()->GetItem(index)->SetVisible(visibility);
284  index++;
285  }
286  layer->actor->SetVisibility(opacity);
287  layer->actor->Modified();
288  }
289 
290  // Handle image layers in m_imageInfoMap
291 #if VTK_MAJOR_VERSION >= 6
292  auto it = m_imageInfoMap.find(viewID);
293  if (it != m_imageInfoMap.end() && it->second.imageSlice) {
294  vtkImageSlice* imageSlice = it->second.imageSlice;
295  imageSlice->SetVisibility(visibility ? 1 : 0);
296  imageSlice->Modified();
297  }
298 #endif
299 }
300 
301 void ImageVis::changeOpacity(double opacity, const std::string& viewID) {
302 #if VTK_MAJOR_VERSION >= 6
303  // ParaView-style: Use vtkImageSlice::GetProperty()->SetOpacity()
304  // This is much more efficient - no image data modification needed
305  auto it = m_imageInfoMap.find(viewID);
306  if (it != m_imageInfoMap.end() && it->second.imageSlice) {
307  vtkImageSlice* imageSlice = it->second.imageSlice;
308  imageSlice->SetVisibility(opacity > 0.0 ? 1 : 0);
309  imageSlice->GetProperty()->SetOpacity(opacity);
310 
312  "[ImageVis::changeOpacity] Set opacity to %f using "
313  "vtkImageSlice::GetProperty()->SetOpacity()",
314  opacity);
315 
316  // Trigger render to update display
317  if (win_) {
318  win_->Render();
319  }
320  return; // Image layer handled
321  }
322 #endif
323 
324  // Fallback: Handle regular layers in layer_map_
325  Layer* layer = getLayer(viewID);
326  if (layer) {
327  layer->actor->SetVisibility(opacity > 0.0 ? 1 : 0);
328  layer->actor->Modified();
329  if (win_) {
330  win_->Render();
331  }
332  }
333 }
334 
335 void ImageVis::removeLayer(const std::string& layer_id) {
336 #if VTK_MAJOR_VERSION >= 6
337  // Check if this is an image layer
338  bool isImageLayer = m_imageInfoMap.find(layer_id) != m_imageInfoMap.end();
339 
340  // Remove image slice from renderer if it exists
341  auto it = m_imageInfoMap.find(layer_id);
342  if (it != m_imageInfoMap.end() && it->second.imageSlice && ren_) {
343  ren_->RemoveViewProp(it->second.imageSlice);
344  }
345 
346  // Remove from image info map
347  m_imageInfoMap.erase(layer_id);
348 
349  // If this was an image layer and no more image layers exist, restore
350  // original interactor style This allows 3D objects to rotate normally again
351  if (isImageLayer && m_imageInfoMap.empty() && interactor_ &&
352  m_originalInteractorStyle) {
353  interactor_->SetInteractorStyle(m_originalInteractorStyle);
354  // Clear saved style so it can be saved again if needed
355  m_originalInteractorStyle = nullptr;
356 
357  // Restore original camera parameters
358  if (m_cameraParamsSaved && ren_ && ren_->GetActiveCamera()) {
359  vtkCamera* camera = ren_->GetActiveCamera();
360  camera->SetFocalPoint(m_originalCameraParams.focalPoint);
361  camera->SetPosition(m_originalCameraParams.position);
362  camera->SetViewUp(m_originalCameraParams.viewUp);
363  camera->SetViewAngle(m_originalCameraParams.viewAngle);
364  camera->SetParallelScale(m_originalCameraParams.parallelScale);
365  camera->SetClippingRange(m_originalCameraParams.clippingRange);
366  if (m_originalCameraParams.parallelProjection) {
367  camera->ParallelProjectionOn();
368  } else {
369  camera->ParallelProjectionOff();
370  }
371  m_cameraParamsSaved = false;
372  }
373  }
374 #endif
375 
376  // Call base class implementation
378 }
379 
381 pcl::visualization::ImageViewer::LayerMap::iterator ImageVis::createLayer(
382  const std::string& layer_id,
383  int x,
384  int y,
385  int width,
386  int height,
387  double opacity,
388  bool fill_box) {
389  Layer l;
390  l.layer_name = layer_id;
391  // Create a new layer
393  l.actor->PickableOff();
394  l.actor->DragableOff();
395  if (fill_box) {
397  rect = vtkSmartPointer<pcl::visualization::context_items::
398  FilledRectangle>::New();
399  rect->setColors(0, 0, 0);
400  rect->setOpacity(opacity);
401  rect->set(x, y, static_cast<float>(width), static_cast<float>(height));
402  l.actor->GetScene()->AddItem(rect);
403  }
404 #if VTK_MAJOR_VERSION < 6
405  image_viewer_->GetRenderer()->AddActor(l.actor);
406 #else
407  ren_->AddActor(l.actor);
408 #endif
409  // Add another element
410  layer_map_.push_back(l);
411 
412  return (layer_map_.end() - 1);
413 }
414 
415 void ImageVis::addRGBImage(const QImage& qimage,
416  unsigned x,
417  unsigned y,
418  const std::string& layer_id,
419  double opacity) {
420  if (qimage.isNull()) {
421  CVLog::Warning("[ImageVis::addRGBImage] QImage is null!");
422  return;
423  }
424 
425 #if VTK_MAJOR_VERSION >= 6
426  unsigned width = qimage.width();
427  unsigned height = qimage.height();
428 
429  // Convert QImage to RGBA8888 format for transparency support
430  QImage rgbaImage = qimage;
431  if (rgbaImage.format() != QImage::Format_RGBA8888) {
432  rgbaImage = rgbaImage.convertToFormat(QImage::Format_RGBA8888);
433  }
434 
435  // Use vtkQImageToImageSource for efficient conversion (ParaView-style)
436  vtkSmartPointer<vtkQImageToImageSource> qimageToImageSource =
438  qimageToImageSource->SetQImage(&rgbaImage);
439  qimageToImageSource->Update();
440  vtkSmartPointer<vtkImageData> imageData = qimageToImageSource->GetOutput();
441 
442  // Ensure image data has correct origin and spacing for proper camera setup
443  if (imageData) {
444  imageData->SetOrigin(0.0, 0.0, 0.0);
445  imageData->SetSpacing(1.0, 1.0, 1.0);
446  }
447 
448  // Check if layer already exists, remove old image slice if needed
449  auto it = m_imageInfoMap.find(layer_id);
450  if (it != m_imageInfoMap.end() && it->second.imageSlice && ren_) {
451  ren_->RemoveViewProp(it->second.imageSlice);
452  }
453 
454  // Create vtkImageSliceMapper (ParaView-style)
457  mapper->SetInputData(imageData);
458  mapper->SetSliceNumber(0); // 2D image, use slice 0
459  mapper->Update(); // Ensure mapper is updated
460 
461  // Create vtkImageSlice (ParaView-style)
462  vtkSmartPointer<vtkImageSlice> imageSlice =
464  imageSlice->SetMapper(mapper);
465  imageSlice->GetProperty()->SetOpacity(opacity);
466  imageSlice->GetProperty()->SetInterpolationTypeToLinear();
467 
468  // Set Position as requested
469  imageSlice->SetPosition(x, y, 0);
470 
471  // Enable transparency rendering support
472  if (opacity < 1.0 && ren_) {
473  vtkRenderWindow* renderWindow = ren_->GetRenderWindow();
474  if (renderWindow) {
475  renderWindow->SetAlphaBitPlanes(1);
476  }
477  }
478 
479  // Hide base class slice_ if it exists to avoid conflict with new imageSlice
480  // Base class slice_ is added in setRender(), but we use our own imageSlice
481  // for each layer
482  if (ren_ && slice_) {
483  slice_->SetVisibility(0); // Hide base class slice_
484  }
485 
486  // Set interactor style to image style (pan/drag instead of rotate)
487  // This saves original style to prevent crashes when getCamera is called
488  setImageInteractorStyle();
489 
490  // Add image slice to renderer first (before calling
491  // updateImageSliceTransform)
492  if (ren_) {
493  ren_->AddViewProp(imageSlice);
494  }
495 
496  // Calculate scale and position to fit window while maintaining aspect ratio
497  // This must be called after adding to renderer so ResetCamera() works
498  // correctly
499  updateImageSliceTransform(imageSlice, width, height);
500 
501  // Trigger render to update display
502  if (win_) {
503  win_->Render();
504  }
505 
506  // Store image info for later updates
507  ImageInfo info;
508  info.originalWidth = width;
509  info.originalHeight = height;
510  info.imageSlice = imageSlice;
511  info.imageMapper = mapper;
512  m_imageInfoMap[layer_id] = info;
513 #else
514  // Fallback for older VTK versions - use old method
515  CVLog::Warning("[ImageVis::addRGBImage] vtkImageSlice requires VTK >= 6.0");
516 #endif
517 }
518 
520 // ParaView-style: Use vtkImageSlice + vtkImageSliceMapper for efficient image
521 // rendering
522 void ImageVis::addQImage(const QImage& qimage,
523  const std::string& layer_id,
524  double opacity) {
525  addRGBImage(qimage, 0, 0, layer_id, opacity);
526 }
527 
528 bool ImageVis::addText(unsigned int x,
529  unsigned int y,
530  const std::string& text_string,
531  double r,
532  double g,
533  double b,
534  const std::string& layer_id,
535  double opacity,
536  int fontSize,
537  bool bold) {
538  // bool sucess = pcl::visualization::ImageViewer::addText(x, y, text_string,
539  // r, g, b, layer_id, opacity);
540 
541  // Check to see if this ID entry already exists (has it been already added
542  // to the visualizer?)
543  LayerMap::iterator am_it = std::find_if(
544  layer_map_.begin(), layer_map_.end(), LayerComparator(layer_id));
545  if (am_it == layer_map_.end()) {
546  PCL_DEBUG(
547  "[pcl::visualization::ImageViewer::addText] No layer with "
548  "ID='%s' found. Creating new one...\n",
549  layer_id.c_str());
550  am_it = createLayer(layer_id, getSize()[0] - 1, getSize()[1] - 1,
551  opacity, false);
552 #if ((VTK_MAJOR_VERSION == 5) && (VTKOR_VERSION > 10))
553  interactor_style_->adjustCamera(ren_);
554 #endif
555  }
556 
559  text->setColors(static_cast<unsigned char>(255.0 * r),
560  static_cast<unsigned char>(255.0 * g),
561  static_cast<unsigned char>(255.0 * b));
562  text->setOpacity(opacity);
563  text->setBold(bold);
564  text->setFontSize(fontSize);
565 #if ((VTK_MAJOR_VERSION >= 6) || \
566  ((VTK_MAJOR_VERSION == 5) && (VTK_MINOR_VERSION > 7)))
567  text->set(static_cast<float>(x), static_cast<float>(y), text_string);
568 #else
569  text->set(static_cast<float>(x), static_cast<float>(getSize()[1] - y),
570  text_string);
571 #endif
572  am_it->actor->GetScene()->AddItem(text);
573 
574  return true;
575 }
576 
577 void ImageVis::WindowResizeCallback(vtkObject* caller,
578  unsigned long eventId,
579  void* clientData,
580  void* callData) {
581  Q_UNUSED(callData);
582  Q_UNUSED(eventId);
583 
584  ImageVis* self = static_cast<ImageVis*>(clientData);
585  if (self) {
586  self->onWindowResize();
587  }
588 }
589 
590 void ImageVis::onWindowResize() {
591  updateImageScales();
592  if (win_) {
593  win_->Render();
594  }
595 }
596 
597 void ImageVis::updateImageScales() {
598  if (!win_) {
599  return;
600  }
601 
602  int* winSize = win_->GetSize();
603  if (!winSize || winSize[0] <= 0 || winSize[1] <= 0) {
604  return;
605  }
606 
607 #if VTK_MAJOR_VERSION >= 6
608  // Update scale and position for all image slices (ParaView-style)
609  for (auto& pair : m_imageInfoMap) {
610  if (pair.second.imageSlice && pair.second.originalWidth > 0 &&
611  pair.second.originalHeight > 0) {
612  updateImageSliceTransform(pair.second.imageSlice,
613  pair.second.originalWidth,
614  pair.second.originalHeight);
615  }
616  }
617 #else
618  // Fallback for older VTK versions
619  for (auto& pair : m_imageInfoMap) {
620  if (pair.second.imageItem) {
621  pair.second.imageItem->updateScale(winSize[0], winSize[1]);
622  }
623  }
624 #endif
625 }
626 
627 #if VTK_MAJOR_VERSION >= 6
628 void ImageVis::updateImageSliceTransform(vtkImageSlice* imageSlice,
629  unsigned width,
630  unsigned height) {
631  if (!imageSlice || !win_ || !ren_ || width == 0 || height == 0) {
632  return;
633  }
634 
635  int* winSize = win_->GetSize();
636  if (!winSize || winSize[0] <= 0 || winSize[1] <= 0) {
637  return;
638  }
639 
640  // Set display extent to show the full image
641  vtkImageSliceMapper* mapper =
642  vtkImageSliceMapper::SafeDownCast(imageSlice->GetMapper());
643  if (mapper) {
644  int extent[6] = {0, static_cast<int>(width) - 1,
645  0, static_cast<int>(height) - 1,
646  0, 0};
647  mapper->SetDisplayExtent(extent);
648  mapper->SetBorder(1); // Enable border to ensure image is visible
649  mapper->Update(); // Ensure mapper updates after setting extent
650  }
651 
652  // Set up camera similar to base class ImageViewer::addRGBImage
653  // The image slice position is at origin (0,0,0) by default
654  // We use camera to view the image properly
655  vtkCamera* camera = ren_->GetActiveCamera();
656  if (camera) {
657  // Get image slice position
658  double pos[3] = {0.0, 0.0, 0.0};
659  if (imageSlice) {
660  imageSlice->GetPosition(pos);
661  }
662 
663  // Set camera to view the image centered
664  // Image extent is [0, width-1, 0, height-1, 0, 0]
665  double xc = pos[0] + (width - 1) * 0.5;
666  double yc = pos[1] + (height - 1) * 0.5;
667  double zd = 3.346065; // Default distance used in base class
668 
669  camera->SetFocalPoint(xc, yc, 0.0);
670  camera->SetPosition(xc, yc, zd);
671  // Use parallel scale based on image height (similar to base class)
672  camera->SetParallelScale(0.5 * height);
673  camera->ParallelProjectionOn();
674 
675  // Reset camera to ensure proper view
676  ren_->ResetCamera();
677  }
678 
679  // Mark image slice as modified to trigger rendering update
680  if (imageSlice) {
681  imageSlice->Modified();
682  }
683 }
684 
685 void ImageVis::setImageInteractorStyle() {
686  // Set interactor style to image style (pan/drag instead of rotate) when
687  // image is loaded vtkInteractorStyleImage supports pan (middle button) and
688  // zoom (wheel) but not rotate This prevents crashes by saving original
689  // style and checking before setting
690  if (!interactor_) {
691  return;
692  }
693 
694  // Save original style if not already saved
695  // This is critical to prevent crashes when PCLVis::getCamera tries to
696  // access PCLVisualizerInteractorStyle methods that don't exist in
697  // vtkInteractorStyleImage
698  if (!m_originalInteractorStyle) {
699  m_originalInteractorStyle = interactor_->GetInteractorStyle();
700  }
701 
702  // Save original camera parameters if not already saved
703  // This allows restoring all camera parameters when exiting image mode
704  if (!m_cameraParamsSaved && ren_ && ren_->GetActiveCamera()) {
705  vtkCamera* camera = ren_->GetActiveCamera();
706  m_originalCameraParams.parallelProjection =
707  camera->GetParallelProjection();
708  camera->GetFocalPoint(m_originalCameraParams.focalPoint);
709  camera->GetPosition(m_originalCameraParams.position);
710  camera->GetViewUp(m_originalCameraParams.viewUp);
711  m_originalCameraParams.viewAngle = camera->GetViewAngle();
712  m_originalCameraParams.parallelScale = camera->GetParallelScale();
713  camera->GetClippingRange(m_originalCameraParams.clippingRange);
714  m_cameraParamsSaved = true;
715 
716  // Set parallel projection for image viewing
717  camera->ParallelProjectionOn();
718  }
719 
720  // Only set image style if current style is not already an image style
721  // This avoids unnecessary style changes and potential issues
722  vtkInteractorStyleImage* currentImageStyle =
723  vtkInteractorStyleImage::SafeDownCast(
724  interactor_->GetInteractorStyle());
725  if (!currentImageStyle) {
726  // Use ParaView-style image interactor: left button pan, middle button
727  // rotate
730  imageStyle->SetDefaultRenderer(ren_);
731  interactor_->SetInteractorStyle(imageStyle);
732  }
733 }
734 #endif
735 } // namespace PclUtils
MouseEvent event
int width
int height
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Print(const char *format,...)
Prints out a formatted message in console.
Definition: CVLog.cpp:113
static bool PrintVerbose(const char *format,...)
Prints out a verbose formatted message in console.
Definition: CVLog.cpp:103
void addQImage(const QImage &qimage, const std::string &layer_id="image", double opacity=1.0)
Add a QImage directly (ParaView-style, using vtkQImageToImageSource).
Definition: ImageVis.cpp:522
Layer * getLayer(const std::string &id)
Definition: ImageVis.cpp:265
void setRender(vtkSmartPointer< vtkRenderer > render)
Definition: ImageVis.cpp:241
void removeLayer(const std::string &layer_id)
Remove a layer from the viewer.
Definition: ImageVis.cpp:335
vtkSmartPointer< vtkRenderWindowInteractor > getRenderWindowInteractor()
Definition: ImageVis.cpp:208
bool addText(unsigned int x, unsigned int y, const std::string &text_string, double r, double g, double b, const std::string &layer_id="line", double opacity=1.0, int fontSize=10, bool bold=false)
Definition: ImageVis.cpp:528
std::string pickItem(int x, int y)
Definition: ImageVis.cpp:170
void enable2Dviewer(bool state)
Definition: ImageVis.cpp:128
void setRenderWindow(vtkSmartPointer< vtkRenderWindow > win)
Definition: ImageVis.cpp:195
void hideShowActors(bool visibility, const std::string &viewID)
Definition: ImageVis.cpp:275
void changeOpacity(double opacity, const std::string &viewID)
Definition: ImageVis.cpp:301
bool contains(const std::string &id) const
Check if the image with the given id was already added to this visualizer.
Definition: ImageVis.cpp:246
void setupInteractor(vtkSmartPointer< vtkRenderWindowInteractor > interactor, vtkSmartPointer< vtkRenderWindow > win)
Set up our unique PCL interactor style for a given vtkRenderWindowInteractor object attached to a giv...
Definition: ImageVis.cpp:116
void setRenderWindowInteractor(vtkSmartPointer< vtkRenderWindowInteractor > interactor)
Definition: ImageVis.cpp:212
void addRGBImage(const QImage &qimage, unsigned x, unsigned y, const std::string &layer_id, double opacity=1.0)
Definition: ImageVis.cpp:415
vtkSmartPointer< vtkRenderWindow > getRenderWindow()
Definition: ImageVis.cpp:112
vtkSmartPointer< vtkRenderer > getRender()
The renderer.
Definition: ImageVis.cpp:239
LayerMap::iterator createLayer(const std::string &layer_id, int x, int y, int width, int height, double opacity=0.5, bool fill_box=true)
Add a new 2D rendering layer to the viewer.
Definition: ImageVis.cpp:381
vtkSmartPointer< vtkRenderWindow > win_
The render window.
vtkSmartPointer< vtkImageViewer > image_viewer_
The ImageViewer widget.
void resetStoppedFlag()
Set the stopped flag back to false.
int * getSize()
Return the window size in pixels.
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 removeLayer(const std::string &layer_id)
Remove a 2D layer given by its ID.
vtkSmartPointer< vtkImageSlice > slice_
Global prop. This is the actual "actor".
int timer_id_
Global timer ID. Used in destructor only.
LayerMap layer_map_
Internal list with different 2D layers shapes.
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.
vtkSmartPointer< vtkRenderWindowInteractor > interactor_
vtkSmartPointer< ImageViewerInteractorStyle > interactor_style_
The interactor style.
vtkSmartPointer< ExitCallback > exit_callback_
void render()
Trigger a render call.
ImGuiContext * context
Definition: Window.cpp:76
normal_z y
normal_z x
Definition: Eigen.h:85
Internal structure describing a layer.
vtkSmartPointer< vtkContextActor > actor
vtkRenderWindowInteractor * vtkRenderWindowInteractorFixNew()