UsTK : Ultrasound ToolKit  version 2.0.1 under development (2023-12-07)
usMedicalImageViewer.cpp
1 /****************************************************************************
2  *
3  * This file is part of the ustk software.
4  * Copyright (C) 2016 - 2017 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * ("GPL") version 2 as published by the Free Software Foundation.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ustk with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * This software was developed at:
17  * Inria Rennes - Bretagne Atlantique
18  * Campus Universitaire de Beaulieu
19  * 35042 Rennes Cedex
20  * France
21  *
22  * If you have questions regarding the use of this file, please contact
23  * Inria at ustk@inria.fr
24  *
25  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27  *
28  * Authors:
29  * Marc Pouliquen
30  *
31  *****************************************************************************/
32 
38 #include <visp3/ustk_core/usImagePostScan3D.h>
39 #include <visp3/ustk_gui/usMedicalImageViewer.h>
40 #include <visp3/ustk_gui/usVTKConverter.h>
41 
42 #ifdef USTK_HAVE_VTK_QT
43 
44 #include <vtkAbstractTransform.h>
45 #include <vtkActor.h>
46 #include <vtkActor2D.h>
47 #include <vtkBoundedPlanePointPlacer.h>
48 #include <vtkCamera.h>
49 #include <vtkCellPicker.h>
50 #include <vtkCommand.h>
51 #include <vtkDistanceRepresentation.h>
52 #include <vtkDistanceRepresentation2D.h>
53 #include <vtkDistanceWidget.h>
54 #include <vtkHandleRepresentation.h>
55 #include <vtkImageActor.h>
56 #include <vtkImageData.h>
57 #include <vtkImageMapToWindowLevelColors.h>
58 #include <vtkImageSlabReslice.h>
59 #include <vtkInteractorStyleImage.h>
60 #include <vtkLookupTable.h>
61 #include <vtkMapper.h>
62 #include <vtkMatrix4x4.h>
63 #include <vtkMetaImageReader.h>
64 #include <vtkPlane.h>
65 #include <vtkPlaneSource.h>
66 #include <vtkPointHandleRepresentation2D.h>
67 #include <vtkPointHandleRepresentation3D.h>
68 #include <vtkProperty.h>
69 #include <vtkRenderWindow.h>
70 #include <vtkRenderer.h>
71 #include <vtkRendererCollection.h>
72 #include <vtkResliceCursor.h>
73 #include <vtkResliceCursorActor.h>
74 #include <vtkResliceCursorLineRepresentation.h>
75 #include <vtkResliceCursorPolyDataAlgorithm.h>
76 #include <vtkResliceCursorThickLineRepresentation.h>
77 #include <vtkResliceCursorWidget.h>
78 #include <vtkResliceImageViewer.h>
79 #include <vtkResliceImageViewerMeasurements.h>
80 
81 #include <QDesktopWidget>
82 #include <QResizeEvent>
83 
84 #if !(USTK_HAVE_VTK_VERSION < 0x090000)
85 #include <QScreen>
86 #endif
87 
88 #ifndef DOXYGEN_SHOULD_SKIP_THIS
89 //----------------------------------------------------------------------------
90 class vtkResliceCursorCallback : public vtkCommand
91 {
92 public:
93  static vtkResliceCursorCallback *New() { return new vtkResliceCursorCallback; }
94 
95  // implementing virtual method of parent class but we don't need arguments, so they've been remove to avoid warings at
96  // compilation
97  void Execute(vtkObject *, unsigned long, void *)
98  {
99  // Render everything
100  for (int i = 0; i < 3; i++) {
101  this->RIW[i]->Render();
102  }
103  widget3D->update();
104  }
105 
106  vtkResliceCursorCallback() : widget3D(), RIW() {}
107  us3DSceneWidget *widget3D;
108  vtkResliceImageViewer *RIW[3];
109 };
110 #endif
111 
117 {
118  this->setupUi();
119  usImageIo::read(postScanImage, imageFileName);
120  usVTKConverter::convert(postScanImage, vtkImage);
121 
122  int imageDims[3];
123  double spacing[3];
124  vtkImage->GetDimensions(imageDims);
125  vtkImage->GetSpacing(spacing);
126 
127  for (int i = 0; i < 3; i++) {
128  riw[i] = vtkSmartPointer<vtkResliceImageViewer>::New();
129  }
130 
131 #if USTK_HAVE_VTK_VERSION < 0x090000
132  this->view1->SetRenderWindow(riw[0]->GetRenderWindow());
133  riw[0]->SetupInteractor(this->view1->GetRenderWindow()->GetInteractor());
134 
135  this->view2->SetRenderWindow(riw[1]->GetRenderWindow());
136  riw[1]->SetupInteractor(this->view2->GetRenderWindow()->GetInteractor());
137 
138  this->view3->SetRenderWindow(riw[2]->GetRenderWindow());
139  riw[2]->SetupInteractor(this->view3->GetRenderWindow()->GetInteractor());
140 #else
141  this->view1->setRenderWindow(riw[0]->GetRenderWindow());
142  riw[0]->SetupInteractor(this->view1->renderWindow()->GetInteractor());
143 
144  this->view2->setRenderWindow(riw[1]->GetRenderWindow());
145  riw[1]->SetupInteractor(this->view2->renderWindow()->GetInteractor());
146 
147  this->view3->setRenderWindow(riw[2]->GetRenderWindow());
148  riw[2]->SetupInteractor(this->view3->renderWindow()->GetInteractor());
149 #endif
150 
151  for (int i = 0; i < 3; i++) {
152  // make them all share the same reslice cursor object.
153  vtkResliceCursorLineRepresentation *rep =
154  vtkResliceCursorLineRepresentation::SafeDownCast(riw[i]->GetResliceCursorWidget()->GetRepresentation());
155  riw[i]->SetResliceCursor(riw[0]->GetResliceCursor());
156 
157  rep->GetResliceCursorActor()->GetCursorAlgorithm()->SetReslicePlaneNormal(i);
158 
159  riw[i]->SetInputData(vtkImage);
160  riw[i]->SetSliceOrientation(i);
161  riw[i]->SetSlice(imageDims[i] / 2);
162  riw[i]->SetResliceModeToOblique();
163  riw[i]->SliceScrollOnMouseWheelOff(); // scroll on mouse wheel not working weell (differents views not
164  // synchronized), so we disable it
165  }
166  this->view4->setImageData(vtkImage);
167  this->view4->setPlanes(riw[0]->GetResliceCursor()->GetPlane(0), riw[1]->GetResliceCursor()->GetPlane(1),
168  riw[2]->GetResliceCursor()->GetPlane(2));
169 
170  this->view4->init();
171 
172  vtkSmartPointer<vtkResliceCursorCallback> cbk = vtkSmartPointer<vtkResliceCursorCallback>::New();
173 
174  cbk->widget3D = this->view4;
175 
176  for (int i = 0; i < 3; i++) {
177  cbk->RIW[i] = riw[i];
178  riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::ResliceAxesChangedEvent, cbk);
179  riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::WindowLevelEvent, cbk);
180  riw[i]->GetResliceCursorWidget()->AddObserver(vtkResliceCursorWidget::ResetCursorEvent, cbk);
181  }
182 
183  for (int i = 0; i < 3; i++) {
184  riw[i]->SetResliceMode(1);
185  riw[i]->GetRenderer()->ResetCamera();
186  if (i == 2)
187  riw[i]->GetRenderer()->GetActiveCamera()->SetRoll(180);
188  riw[i]->Render();
189  }
190 
191 #if USTK_HAVE_VTK_VERSION < 0x090000
192  this->view4->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera()->SetRoll(180);
193 #else
194  this->view4->renderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera()->SetRoll(180);
195 #endif
196 
197  // Set up action signals and slots
198  connect(this->resetButton, SIGNAL(pressed()), this, SLOT(ResetViews()));
199  ResetViews();
200 }
201 
205 void usMedicalImageViewer::slotExit() { qApp->exit(); }
206 
211 
216 {
217  // Render everything
218  for (int i = 0; i < 3; i++) {
219  riw[i]->GetLookupTable()->SetRange(0, 255);
220  riw[i]->GetResliceCursorWidget()->Render();
221  }
222 }
223 
228 {
229 #if USTK_HAVE_VTK_VERSION < 0x090000
230  this->view1->GetRenderWindow()->Render();
231  this->view2->GetRenderWindow()->Render();
232  this->view3->GetRenderWindow()->Render();
233 #else
234  this->view1->renderWindow()->Render();
235  this->view2->renderWindow()->Render();
236  this->view3->renderWindow()->Render();
237 #endif
238 
239  this->view1->update();
240  this->view2->update();
241  this->view3->update();
242  this->view4->update();
243 }
244 
249 
255 {
256  // remove existing widgets.
257  if (this->DistanceWidget[i]) {
258  this->DistanceWidget[i]->SetEnabled(0);
259  this->DistanceWidget[i] = NULL;
260  }
261 
262  // add new widget
263  this->DistanceWidget[i] = vtkSmartPointer<vtkDistanceWidget>::New();
264  this->DistanceWidget[i]->SetInteractor(this->riw[i]->GetResliceCursorWidget()->GetInteractor());
265 
266  // Set a priority higher than our reslice cursor widget
267  this->DistanceWidget[i]->SetPriority(this->riw[i]->GetResliceCursorWidget()->GetPriority() + 0.01);
268 
269  vtkSmartPointer<vtkPointHandleRepresentation2D> handleRep = vtkSmartPointer<vtkPointHandleRepresentation2D>::New();
270  vtkSmartPointer<vtkDistanceRepresentation2D> distanceRep = vtkSmartPointer<vtkDistanceRepresentation2D>::New();
271  distanceRep->SetHandleRepresentation(handleRep);
272  this->DistanceWidget[i]->SetRepresentation(distanceRep);
273  distanceRep->InstantiateHandleRepresentation();
274  distanceRep->GetPoint1Representation()->SetPointPlacer(riw[i]->GetPointPlacer());
275  distanceRep->GetPoint2Representation()->SetPointPlacer(riw[i]->GetPointPlacer());
276 
277  // Add the distance to the list of widgets whose visibility is managed based
278  // on the reslice plane by the ResliceImageViewerMeasurements class
279  this->riw[i]->GetMeasurements()->AddItem(this->DistanceWidget[i]);
280 
281  this->DistanceWidget[i]->CreateDefaultRepresentation();
282  this->DistanceWidget[i]->EnabledOn();
283 }
284 
288 void usMedicalImageViewer::setupUi()
289 {
290  this->setMinimumSize(640, 480);
291 #if USTK_HAVE_VTK_VERSION < 0x090000
292  QRect screenRect = QApplication::desktop()->screenGeometry();
293 #else
294  QRect screenRect = QApplication::screens()[0]->geometry();
295 #endif
296  this->resize(screenRect.size());
297 
298  gridLayoutWidget = new QWidget(this);
299  gridLayoutWidget->setObjectName(QString::fromUtf8("gridLayoutWidget"));
300  gridLayoutWidget->setGeometry(QRect(10, 10, screenRect.width() - 200, screenRect.height() - 40));
301  gridLayout_2 = new QGridLayout(gridLayoutWidget);
302  gridLayout_2->setObjectName(QString::fromUtf8("gridLayout_2"));
303  gridLayout_2->setContentsMargins(0, 0, 0, 0);
304  view2 = new usViewerWidget(gridLayoutWidget);
305  view2->setObjectName(QString::fromUtf8("view2"));
306 
307  gridLayout_2->addWidget(view2, 1, 0, 1, 1);
308 
309  view4 = new us3DSceneWidget(gridLayoutWidget);
310  view4->setObjectName(QString::fromUtf8("view4"));
311 
312  gridLayout_2->addWidget(view4, 0, 1, 1, 1);
313 
314  view3 = new usViewerWidget(gridLayoutWidget);
315  view3->setObjectName(QString::fromUtf8("view3"));
316 
317  gridLayout_2->addWidget(view3, 1, 1, 1, 1);
318 
319  view1 = new usViewerWidget(gridLayoutWidget);
320  view1->setObjectName(QString::fromUtf8("view1"));
321 
322  gridLayout_2->addWidget(view1, 0, 0, 1, 1);
323 
324  resetButton = new QPushButton(this);
325  resetButton->setObjectName(QString::fromUtf8("resetButton"));
326  resetButton->setText(QString::fromUtf8("Reset views"));
327  resetButton->setGeometry(QRect(screenRect.width() - 180, 30, 160, 31));
328 
329  resetColorsButton = new QPushButton(this);
330  resetColorsButton->setObjectName(QString::fromUtf8("resetColorsButton"));
331  resetColorsButton->setText(QString::fromUtf8("Reset colormap"));
332  resetColorsButton->setGeometry(QRect(screenRect.width() - 180, 80, 160, 31));
333 
334  AddDistance1Button = new QPushButton(this);
335  AddDistance1Button->setObjectName(QString::fromUtf8("AddDistance1Button"));
336  AddDistance1Button->setText(QString::fromUtf8("Add distance 1"));
337  AddDistance1Button->setGeometry(QRect(screenRect.width() - 180, 130, 160, 31));
338 }
339 
343 void usMedicalImageViewer::resizeEvent(QResizeEvent *event)
344 {
345  // Min size : 640*480
346  if (event->size().width() >= 640 && event->size().height() >= 480) {
347  QMainWindow::resizeEvent(event);
348  gridLayoutWidget->setGeometry(QRect(10, 10, event->size().width() - 220, event->size().height() - 20));
349  resetButton->setGeometry(QRect(event->size().width() - 180, 30, 160, 31));
350  resetColorsButton->setGeometry(QRect(event->size().width() - 180, 80, 160, 31));
351  AddDistance1Button->setGeometry(QRect(event->size().width() - 180, 130, 160, 31));
352  }
353 }
354 #endif
Class used to render a 3D vtk scene containing a vtkImageData in a QWidget (based on QVTKWidget).
void setPlanes(vtkPlane *plane1, vtkPlane *plane2, vtkPlane *plane3)
void setImageData(vtkImageData *imageData)
static void read(usImageRF2D< short int > &imageRf2D, const std::string &headerFileName)
Definition: usImageIo.cpp:153
virtual void AddDistanceMeasurementToView1()
vtkSmartPointer< vtkResliceImageViewer > riw[3]
usMedicalImageViewer(std::string imageFileName)
virtual void AddDistanceMeasurementToView(int)
void resizeEvent(QResizeEvent *event)
vtkSmartPointer< vtkDistanceWidget > DistanceWidget[3]
static void convert(const usImagePostScan3D< unsigned char > &postScanImage, vtkSmartPointer< vtkImageData > &vtkPostScanImage, vtkSmartPointer< vtkImageImport > importer=NULL)
View used to render a vtk scene in a QWidget (based on QVTKWidget for Qt4, QVTKOpenGLWidget for Qt5)