UsTK : Ultrasound ToolKit  version 2.0.1 under development (2024-12-03)
usResliceMatrixViewer.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_gui/usResliceMatrixViewer.h>
39 
40 #ifdef USTK_HAVE_VTK_QT
41 
42 #include <visp3/ustk_core/usImagePostScan3D.h>
43 #include <visp3/ustk_gui/usVTKConverter.h>
44 
45 #include <vtkAbstractTransform.h>
46 #include <vtkActor.h>
47 #include <vtkActor2D.h>
48 #include <vtkBoundedPlanePointPlacer.h>
49 #include <vtkCamera.h>
50 #include <vtkCellPicker.h>
51 #include <vtkCommand.h>
52 #include <vtkDistanceRepresentation.h>
53 #include <vtkDistanceRepresentation2D.h>
54 #include <vtkDistanceWidget.h>
55 #include <vtkHandleRepresentation.h>
56 #include <vtkImageActor.h>
57 #include <vtkImageData.h>
58 #include <vtkImageMapToWindowLevelColors.h>
59 #include <vtkImageSlabReslice.h>
60 #include <vtkInteractorStyleImage.h>
61 #include <vtkLookupTable.h>
62 #include <vtkMapper.h>
63 #include <vtkMatrix4x4.h>
64 #include <vtkMetaImageReader.h>
65 #include <vtkPlane.h>
66 #include <vtkPlaneSource.h>
67 #include <vtkProperty.h>
68 #include <vtkRenderWindow.h>
69 #include <vtkRenderer.h>
70 #include <vtkRendererCollection.h>
71 #include <vtkResliceImageViewer.h>
72 #include <vtkResliceImageViewerMeasurements.h>
73 
74 #include <vtkHomogeneousTransform.h>
75 
76 #include <QDesktopWidget>
77 #include <QFileDialog>
78 #include <QResizeEvent>
79 
85 {
86  this->setupUi();
87  usImageIo::read(postScanImage, imageFileName);
88  usVTKConverter::convert(postScanImage, vtkImage);
89 
90  int imageDims[3];
91  double spacing[3];
92  vtkImage->GetDimensions(imageDims);
93  vtkImage->GetSpacing(spacing);
94 
95  // matrix representing plane 3
96  vpHomogeneousMatrix matrix3;
97  matrix3.eye();
98  matrix3[0][3] = imageDims[0] * spacing[0] / 2;
99  matrix3[1][3] = imageDims[1] * spacing[1] / 2;
100  matrix3[2][3] = imageDims[2] * spacing[2] / 2;
101  matrix3[0][0] = 1;
102  matrix3[1][1] = -1;
103  matrix3[2][2] = -1;
104  vtkMatrix3 = vtkMatrix4x4::New();
105  usVTKConverter::convert(matrix3, vtkMatrix3);
106 
107  // matrix representing plane 2
108  vpHomogeneousMatrix matrix2;
109  matrix2.eye();
110  matrix2[0][3] = imageDims[0] * spacing[0] / 2;
111  matrix2[1][3] = imageDims[1] * spacing[1] / 2;
112  matrix2[2][3] = imageDims[2] * spacing[2] / 2;
113  matrix2[0][0] = 1;
114  matrix2[2][1] = 1;
115  matrix2[1][1] = 0;
116  matrix2[1][2] = -1;
117  matrix2[2][2] = 0;
118 
119  vtkMatrix2 = vtkMatrix4x4::New();
120  usVTKConverter::convert(matrix2, vtkMatrix2);
121 
122  // matrix representing plane 1
123  vpHomogeneousMatrix matrix1;
124  matrix1.eye();
125  matrix1[0][3] = imageDims[0] * spacing[0] / 2;
126  matrix1[1][3] = imageDims[1] * spacing[1] / 2;
127  matrix1[2][3] = imageDims[2] * spacing[2] / 2;
128  matrix1[0][0] = 0;
129  matrix1[0][2] = 1;
130  matrix1[1][1] = -1;
131  matrix1[2][0] = 1;
132  matrix1[2][2] = 0;
133  vtkMatrix1 = vtkMatrix4x4::New();
134  usVTKConverter::convert(matrix1, vtkMatrix1);
135 
136  view2->setImageData(vtkImage);
137  view2->updateMatrix1(vtkMatrix1);
138  view2->updateMatrix2(vtkMatrix2);
139  view2->updateMatrix3(vtkMatrix3);
140  view2->init();
141 
142  view1->setImageData(vtkImage);
143  view1->setResliceMatrix(vtkMatrix1);
144  view1->setPolyDataPlaneContour(view2->getContour1());
145  view1->setPolyDataMeshContour(view2->getMeshInPlane1());
146  view1->init();
147  view1->setColor(1.0, 0, 0);
148 
149  view4->setImageData(vtkImage);
150  view4->setResliceMatrix(vtkMatrix2);
151  view4->setPolyDataPlaneContour(view2->getContour2());
152  view4->setPolyDataMeshContour(view2->getMeshInPlane2());
153  view4->init();
154  view4->setColor(0, 1.0, 0);
155 
156  view3->setImageData(vtkImage);
157  view3->setResliceMatrix(vtkMatrix3);
158  view3->setPolyDataPlaneContour(view2->getContour3());
159  view3->setPolyDataMeshContour(view2->getMeshInPlane3());
160  view3->init();
161  view3->setColor(0, 0, 1.0);
162 
163  // Set up action signals and slots
164  connect(this->resetButton, SIGNAL(pressed()), this, SLOT(ResetViews()));
165  // connect(this->saveView1Button, SIGNAL(pressed()), view1, SLOT(saveViewSlot()));
166  connect(this->openImageButton, SIGNAL(pressed()), this, SLOT(openPostScan3D()));
167  connect(this->saveView1Button, SIGNAL(pressed()), this, SLOT(getView1Slice()));
168  connect(this->saveView4Button, SIGNAL(pressed()), view4, SLOT(saveViewSlot()));
169  connect(this->saveView3Button, SIGNAL(pressed()), view3, SLOT(saveViewSlot()));
170 
171  // updates of planes in 3D scene
172  connect(view1, SIGNAL(matrixChanged(vtkMatrix4x4 *)), view2, SLOT(updateMatrix1(vtkMatrix4x4 *)));
173  connect(view4, SIGNAL(matrixChanged(vtkMatrix4x4 *)), view2, SLOT(updateMatrix2(vtkMatrix4x4 *)));
174  connect(view3, SIGNAL(matrixChanged(vtkMatrix4x4 *)), view2, SLOT(updateMatrix3(vtkMatrix4x4 *)));
175  // update back 2D views (for polydata intersections)
176  connect(view2, SIGNAL(plane2Changed()), view1, SLOT(updateView()));
177  connect(view2, SIGNAL(plane2Changed()), view4, SLOT(updateView()));
178  connect(view2, SIGNAL(plane2Changed()), view3, SLOT(updateView()));
179 
180  ResetViews();
181 }
182 
186 void usResliceMatrixViewer::slotExit() { qApp->exit(); }
187 
192 {
193  int imageDims[3];
194  double spacing[3];
195  vtkImage->GetDimensions(imageDims);
196  vtkImage->GetSpacing(spacing);
197 
198  // matrix representing plane 3
199  vpHomogeneousMatrix matrix3;
200  matrix3.eye();
201  matrix3[0][3] = imageDims[0] * spacing[0] / 2;
202  matrix3[1][3] = imageDims[1] * spacing[1] / 2;
203  matrix3[2][3] = imageDims[2] * spacing[2] / 2;
204  matrix3[0][0] = 1;
205  matrix3[1][1] = -1;
206  matrix3[2][2] = -1;
207  usVTKConverter::convert(matrix3, vtkMatrix3);
208 
209  // matrix representing plane 2
210  vpHomogeneousMatrix matrix2;
211  matrix2.eye();
212  matrix2[0][3] = imageDims[0] * spacing[0] / 2;
213  matrix2[1][3] = imageDims[1] * spacing[1] / 2;
214  matrix2[2][3] = imageDims[2] * spacing[2] / 2;
215  matrix2[0][0] = 1;
216  matrix2[2][1] = 1;
217  matrix2[1][1] = 0;
218  matrix2[1][2] = -1;
219  matrix2[2][2] = 0;
220  usVTKConverter::convert(matrix2, vtkMatrix2);
221 
222  // matrix representing plane 1
223  vpHomogeneousMatrix matrix1;
224  matrix1.eye();
225  matrix1[0][3] = imageDims[0] * spacing[0] / 2;
226  matrix1[1][3] = imageDims[1] * spacing[1] / 2;
227  matrix1[2][3] = imageDims[2] * spacing[2] / 2;
228  matrix1[0][0] = 0;
229  matrix1[0][2] = 1;
230  matrix1[1][1] = -1;
231  matrix1[2][0] = 1;
232  matrix1[2][2] = 0;
233  usVTKConverter::convert(matrix1, vtkMatrix1);
234 
235  view1->setResliceMatrix(vtkMatrix1);
236  view4->setResliceMatrix(vtkMatrix2);
237  view3->setResliceMatrix(vtkMatrix3);
238 
239  view2->updateMatrix1(vtkMatrix1);
240  view2->updateMatrix2(vtkMatrix2);
241  view2->updateMatrix3(vtkMatrix3);
242 
243  this->Render();
244 }
245 
250 {
251  this->view1->GetRenderWindow()->Render();
252  this->view2->GetRenderWindow()->Render();
253  this->view3->GetRenderWindow()->Render();
254  this->view4->GetRenderWindow()->Render();
255 }
256 
260 void usResliceMatrixViewer::setupUi()
261 {
262  this->setMinimumSize(640, 480);
263  QRect screenRect = QApplication::desktop()->screenGeometry();
264  this->resize(screenRect.size());
265 
266  gridLayoutWidget = new QWidget(this);
267  gridLayoutWidget->setObjectName(QString::fromUtf8("gridLayoutWidget"));
268  gridLayoutWidget->setGeometry(QRect(10, 10, screenRect.width() - 200, screenRect.height() - 40));
269  gridLayout_2 = new QGridLayout(gridLayoutWidget);
270  gridLayout_2->setObjectName(QString::fromUtf8("gridLayout_2"));
271  gridLayout_2->setContentsMargins(0, 0, 0, 0);
272  view1 = new us2DSceneWidget(gridLayoutWidget);
273  view1->setObjectName(QString::fromUtf8("view1"));
274 
275  gridLayout_2->addWidget(view1, 0, 0, 1, 1);
276 
277  view2 = new us3DSceneWidget(gridLayoutWidget);
278  view2->setObjectName(QString::fromUtf8("view1"));
279 
280  gridLayout_2->addWidget(view2, 1, 0, 1, 1);
281 
282  view3 = new us2DSceneWidget(gridLayoutWidget);
283  view3->setObjectName(QString::fromUtf8("view1"));
284 
285  gridLayout_2->addWidget(view3, 0, 1, 1, 1);
286 
287  view4 = new us2DSceneWidget(gridLayoutWidget);
288  view4->setObjectName(QString::fromUtf8("view2"));
289 
290  gridLayout_2->addWidget(view4, 1, 1, 1, 1);
291 
292  resetButton = new QPushButton(this);
293  resetButton->setObjectName(QString::fromUtf8("resetButton"));
294  resetButton->setText(QString::fromUtf8("Reset views"));
295  resetButton->setGeometry(QRect(screenRect.width() - 180, 30, 160, 31));
296 
297  openImageButton = new QPushButton(this);
298  openImageButton->setObjectName(QString::fromUtf8("openImageButton"));
299  openImageButton->setText(QString::fromUtf8("Open new image"));
300  openImageButton->setGeometry(QRect(screenRect.width() - 180, 80, 160, 31));
301 
302  saveView1Button = new QPushButton(this);
303  saveView1Button->setObjectName(QString::fromUtf8("saveView1Button"));
304  saveView1Button->setText(QString::fromUtf8("Save view 1"));
305  saveView1Button->setGeometry(QRect(screenRect.width() - 180, 130, 160, 31));
306 
307  saveView4Button = new QPushButton(this);
308  saveView4Button->setObjectName(QString::fromUtf8("saveView4Button"));
309  saveView4Button->setText(QString::fromUtf8("Save view 4"));
310  saveView4Button->setGeometry(QRect(screenRect.width() - 180, 180, 160, 31));
311 
312  saveView3Button = new QPushButton(this);
313  saveView3Button->setObjectName(QString::fromUtf8("saveView3Button"));
314  saveView3Button->setText(QString::fromUtf8("Save view 3"));
315  saveView3Button->setGeometry(QRect(screenRect.width() - 180, 230, 160, 31));
316 }
317 
321 void usResliceMatrixViewer::resizeEvent(QResizeEvent *event)
322 {
323  // Min size : 640*480
324  if (event->size().width() >= 640 && event->size().height() >= 480) {
325  QMainWindow::resizeEvent(event);
326  gridLayoutWidget->setGeometry(QRect(10, 10, event->size().width() - 220, event->size().height() - 20));
327  resetButton->setGeometry(QRect(event->size().width() - 180, 30, 160, 31));
328  openImageButton->setGeometry(QRect(event->size().width() - 180, 80, 160, 31));
329  saveView1Button->setGeometry(QRect(event->size().width() - 180, 130, 160, 31));
330  saveView4Button->setGeometry(QRect(event->size().width() - 180, 180, 160, 31));
331  saveView3Button->setGeometry(QRect(event->size().width() - 180, 230, 160, 31));
332  }
333 }
334 
339 {
340  usImagePostScan2D<unsigned char> postScanSlice;
341  view1->getCurrentSlice(postScanSlice);
342  usImageIo::write(postScanSlice, "sliceView1.xml");
343 }
344 
349 {
350  // open file dialog to let the user select the new mhd file to display
351  QString fileName = QFileDialog::getOpenFileName(this, tr("Open Image"), us::getDataSetPath().c_str(),
352  tr("Meta header files (*.mhd)"));
353 
354  if (fileName.size() == 0)
355  return;
356 
357  double t0 = vpTime::measureTimeMs();
358 
359  // read the image and convert it to vtkImageData
360  usImageIo::read(postScanImage, fileName.toStdString());
361  double t1 = vpTime::measureTimeMs();
362  std::cout << "read image time (ms) = " << t1 - t0 << std::endl;
363  usVTKConverter::convert(postScanImage, vtkImage);
364 
365  // update the views
366  view2->updateImageData(vtkImage);
367  view1->updateImageData(vtkImage);
368  view3->updateImageData(vtkImage);
369  view4->updateImageData(vtkImage);
370 
371  std::cout << "convert/update image time (ms) = " << vpTime::measureTimeMs() - t1 << std::endl;
372 }
373 #endif
Class used to render a 2D slice of a vtkImageData in a vtk scene in a QWidget (based on QVTKWidget)
void updateImageData(vtkImageData *imageData)
void getCurrentSlice(usImagePostScan2D< unsigned char > &image2D)
void setColor(double r, double g, double b)
void setImageData(vtkImageData *imageData)
void setResliceMatrix(vtkMatrix4x4 *matrix)
void setPolyDataMeshContour(vtkPolyData *polyData)
void setPolyDataPlaneContour(vtkPolyData *polyData)
Class used to render a 3D vtk scene containing a vtkImageData in a QWidget (based on QVTKWidget).
void updateImageData(vtkImageData *imageData)
vtkPolyData * getMeshInPlane2()
void updateMatrix2(vtkMatrix4x4 *matrix)
vtkPolyData * getContour3()
vtkPolyData * getMeshInPlane3()
void updateMatrix3(vtkMatrix4x4 *matrix)
vtkPolyData * getContour2()
void setImageData(vtkImageData *imageData)
vtkPolyData * getContour1()
vtkPolyData * getMeshInPlane1()
void updateMatrix1(vtkMatrix4x4 *matrix)
static void read(usImageRF2D< short int > &imageRf2D, const std::string &headerFileName)
Definition: usImageIo.cpp:153
static void write(const usImageRF2D< short > &rfImage, const std::string &headerFileName, const std::string &imageExtension2D)
Definition: usImageIo.cpp:104
usResliceMatrixViewer(std::string imageFileName)
void resizeEvent(QResizeEvent *event)
static void convert(const usImagePostScan3D< unsigned char > &postScanImage, vtkSmartPointer< vtkImageData > &vtkPostScanImage, vtkSmartPointer< vtkImageImport > importer=NULL)
VISP_EXPORT std::string getDataSetPath()
Definition: us.cpp:54