UsTK : Ultrasound ToolKit  version 2.0.1 under development (2023-12-07)
us2DSceneWidget.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 // VISP includes
39 #include <visp3/ustk_core/usConfig.h>
40 #ifdef USTK_HAVE_VTK_QT
41 #include <visp3/ustk_gui/usViewerWidget.h>
42 
43 // USTK includes
44 #include <visp3/ustk_core/usImagePostScan2D.h>
45 #include <visp3/ustk_gui/us2DSceneWidget.h>
46 
52 us2DSceneWidget::us2DSceneWidget(QWidget *parent, Qt::WindowFlags f) : usViewerWidget(parent, f)
53 {
54 
55  m_imageData = NULL;
56  m_resliceMatrix = NULL;
57 
58  m_reslice = vtkImageReslice::New();
59 
60  m_renderer = vtkRenderer::New();
61 
62  m_table = vtkLookupTable::New();
63 
64  m_color = vtkImageMapToColors::New();
65 
66  m_actor = vtkImageActor::New();
67 
68  m_polydataPlaneContour = vtkPolyData::New();
69  m_polyDataPlaneContourMapper = vtkPolyDataMapper::New();
70  m_polydataPlaneContourActor = vtkActor::New();
71 
72  m_polydataMeshContour = vtkPolyData::New();
73  m_polyDataMeshContourMapper = vtkPolyDataMapper::New();
74  m_polydataMeshContourActor = vtkActor::New();
75 
76  // Picker to pick pixels
77  m_propPicker = vtkPropPicker::New();
78 
79  m_rPressed = false;
80  m_pPressed = false;
81  m_mousePressed = false;
82 
83  // disable tracking to receive only mouse move events if a button is pressed
84  setMouseTracking(false);
85 
86  m_pickingState = false;
87 }
88 
93 void us2DSceneWidget::paintEvent(QPaintEvent *event) { usViewerWidget::paintEvent(event); }
94 
99 vtkImageData *us2DSceneWidget::getImageData() { return m_imageData; }
100 
105 vtkMatrix4x4 *us2DSceneWidget::getResliceMatrix() { return m_resliceMatrix; }
106 
111 {
112 
113  // verify imageData and reslice matrix are set
114  if (m_imageData == NULL)
115  throw(vpException(vpException::fatalError, "No imageData provided in us2DSceneWidget"));
116 
117  if (m_resliceMatrix == NULL)
118  throw(vpException(vpException::fatalError, "No reslice matrix provided in us2DSceneWidget"));
119 
120  m_reslice->SetInputData(m_imageData);
121  m_reslice->SetOutputDimensionality(2);
122  m_reslice->SetResliceAxes(m_resliceMatrix);
123  m_reslice->SetInterpolationModeToLinear();
124 
125  // To ensure no part of the image will be cropped
126  m_reslice->AutoCropOutputOn();
127 
128  // Create a greyscale lookup table
129  m_table->SetRange(0, 255); // image intensity range
130  m_table->SetValueRange(0.0, 1.0); // from black to white
131  m_table->SetSaturationRange(0.0, 0.0); // no color saturation
132  m_table->SetRampToLinear();
133  m_table->Build();
134 
135  // Map the image through the lookup table
136  m_color->SetLookupTable(m_table);
137  m_color->SetInputConnection(m_reslice->GetOutputPort());
138 
139  // Display the image
140  m_actor->GetMapper()->SetInputConnection(m_color->GetOutputPort());
141  m_actor->SetOpacity(0.7);
142 
143  m_renderer->AddActor(m_actor);
144 
145  // Setup render window
146 #if USTK_HAVE_VTK_VERSION < 0x090000
147  vtkRenderWindow *renderWindow = this->GetRenderWindow();
148 #else
149  vtkRenderWindow *renderWindow = this->renderWindow();
150 #endif
151  renderWindow->AddRenderer(m_renderer);
152 
153  // Set up the interaction
154  vtkSmartPointer<vtkInteractorStyleImage> imageStyle = vtkSmartPointer<vtkInteractorStyleImage>::New();
155  imageStyle->SetInteractionModeToImageSlicing();
156  renderWindow->GetInteractor()->SetInteractorStyle(imageStyle);
157  // imageStyle->EnabledOff();
158 
159  // picker
160  m_propPicker->PickFromListOn();
161 
162  // Give the picker a prop to pick
163  m_propPicker->AddPickList(m_actor);
164 }
165 
170 void us2DSceneWidget::setImageData(vtkImageData *imageData) { m_imageData = imageData; }
171 
176 void us2DSceneWidget::setResliceMatrix(vtkMatrix4x4 *matrix) { m_resliceMatrix = matrix; }
177 
182 void us2DSceneWidget::setPolyDataPlaneContour(vtkPolyData *polyData)
183 {
184  m_polydataPlaneContour = polyData;
185 
186  // add polygon in scene
187 
188  m_polyDataPlaneContourMapper->SetInputData(m_polydataPlaneContour);
189  m_polyDataPlaneContourMapper->SetScalarRange(m_polydataPlaneContour->GetScalarRange());
190 
191  m_polydataPlaneContourActor->GetProperty()->SetOpacity(1.0);
192  m_polydataPlaneContourActor->GetProperty()->SetLighting(0);
193  m_polydataPlaneContourActor->GetProperty()->SetLineWidth(1);
194  m_polydataPlaneContourActor->GetProperty()->SetOpacity(1.0);
195 
196  vpHomogeneousMatrix mat;
197  usVTKConverter::convert(m_resliceMatrix, mat);
198  vtkMatrix4x4 *matrix = vtkMatrix4x4::New();
199  usVTKConverter::convert(mat.inverse(), matrix);
200  m_polydataPlaneContourActor->SetUserMatrix(matrix);
201 
202  m_polydataPlaneContourActor->SetMapper(m_polyDataPlaneContourMapper);
203 
204  m_renderer->AddActor(m_polydataPlaneContourActor);
205 }
206 
211 void us2DSceneWidget::setPolyDataMeshContour(vtkPolyData *polyData)
212 {
213  m_polydataMeshContour = polyData;
214 
215  // add polygon in scene
216  m_polyDataMeshContourMapper->SetInputData(m_polydataMeshContour);
217  m_polyDataMeshContourMapper->SetScalarRange(m_polydataMeshContour->GetScalarRange());
218 
219  m_polydataMeshContourActor->GetProperty()->SetOpacity(1.0);
220  m_polydataMeshContourActor->GetProperty()->SetLighting(0);
221  m_polydataMeshContourActor->GetProperty()->SetLineWidth(1);
222  m_polydataMeshContourActor->GetProperty()->SetColor(1.0, 1.0, 0.0);
223  m_polydataMeshContourActor->GetProperty()->SetOpacity(1.0);
224 
225  vpHomogeneousMatrix mat;
226  usVTKConverter::convert(m_resliceMatrix, mat);
227  vtkMatrix4x4 *matrix = vtkMatrix4x4::New();
228  usVTKConverter::convert(mat.inverse(), matrix);
229  m_polydataMeshContourActor->SetUserMatrix(matrix);
230 
231  m_polydataMeshContourActor->SetMapper(m_polyDataMeshContourMapper);
232 
233  m_renderer->AddActor(m_polydataMeshContourActor);
234 }
235 
240 void us2DSceneWidget::updateImageData(vtkImageData *imageData)
241 {
242 
243  // remove actor from view to avoid rendering errors during data switch
244  m_renderer->RemoveActor(m_actor);
245 
246  // update internal pointer
247  m_imageData = imageData;
248  // update image reslice with the new image data
249  m_reslice->SetInputData(imageData);
250 
251  // add the actor (modified with vtk because m_reslice input data has changed)
252  m_renderer->AddActor(m_actor);
253 
254  // render the view with the new actor
255 #if USTK_HAVE_VTK_VERSION < 0x090000
256  GetRenderWindow()->Render();
257 #else
258  renderWindow()->Render();
259 #endif
260 }
261 
266 void us2DSceneWidget::changeMatrix(vpHomogeneousMatrix matrix)
267 {
268  usVTKConverter::convert(matrix, m_resliceMatrix);
269  update();
270  emit(matrixChanged(m_resliceMatrix));
271 }
272 
276 void us2DSceneWidget::wheelEvent(QWheelEvent *event)
277 {
278 #if USTK_HAVE_VTK_VERSION < 0x090000
279  int increment = event->delta() / 120;
280 #else
281  int increment = event->angleDelta().y() / 120;
282 #endif
283 
284  // To improve : mean of the 3 spacings according to the plane orientation
285  double sliceSpacing = m_imageData->GetSpacing()[2];
286 
287  vpTranslationVector tVec;
288  tVec.data[0] = 0;
289  tVec.data[1] = 0;
290  tVec.data[2] = sliceSpacing * increment;
291 
292  vpHomogeneousMatrix MTrans;
293  MTrans.buildFrom(tVec, vpThetaUVector(0, 0, 0));
294 
295  vpHomogeneousMatrix MCurrrent;
296  usVTKConverter::convert(m_resliceMatrix, MCurrrent);
297 
298  vpHomogeneousMatrix Mnew = MCurrrent * MTrans;
299 
300  usVTKConverter::convert(Mnew, m_resliceMatrix);
301 
302  // update contour polydata
303  vtkMatrix4x4 *vtkMat = vtkMatrix4x4::New();
304  usVTKConverter::convert(Mnew.inverse(), vtkMat);
305  m_polydataPlaneContourActor->SetUserMatrix(vtkMat);
306  m_polydataMeshContourActor->SetUserMatrix(vtkMat);
307 
308  update();
309  m_renderer->Render();
310 
311  // emit signal to inform other views the reslice matrix changed
312  emit(matrixChanged(m_resliceMatrix));
313 
314  event->accept();
315 }
316 
320 void us2DSceneWidget::keyPressEvent(QKeyEvent *event)
321 {
322  if (event->key() == Qt::Key_H) {
323  m_rPressed = true;
324  } else if (event->key() == Qt::Key_P) {
325  m_pPressed = true;
326  }
327  event->accept();
328 }
329 
333 void us2DSceneWidget::keyReleaseEvent(QKeyEvent *event)
334 {
335  if (event->key() == Qt::Key_H) {
336  m_rPressed = false;
337  } else if (event->key() == Qt::Key_P) {
338  m_pPressed = false;
339  }
340  event->accept();
341 }
342 
346 void us2DSceneWidget::mouseMoveEvent(QMouseEvent *event)
347 {
348  if (m_rPressed) {
349  int dx = m_lastmouserPosX - event->pos().x();
350  int dy = m_lastmouserPosY - event->pos().y();
351 
352  vpHomogeneousMatrix currentMat;
353  usVTKConverter::convert(m_resliceMatrix, currentMat);
354 
355  vpThetaUVector tuVec;
356 
357  // when we move along x we rotate around y (z is normal to the view).
358  if (abs(dx) < 16) {
359  tuVec.data[1] = vpMath::rad(dx * .1);
360  }
361  // when we move along y we rotate around x.
362  if (abs(dy) < 16) {
363  tuVec.data[0] = vpMath::rad(dy * .1);
364  }
365 
366  vpHomogeneousMatrix MRot;
367  MRot.buildFrom(vpTranslationVector(0, 0, 0), tuVec);
368 
369  vpHomogeneousMatrix finalMat = currentMat * MRot;
370 
371  usVTKConverter::convert(finalMat, m_resliceMatrix);
372 
373  // update contour polydata
374  vtkMatrix4x4 *vtkMat = vtkMatrix4x4::New();
375  usVTKConverter::convert(finalMat.inverse(), vtkMat);
376  m_polydataPlaneContourActor->SetUserMatrix(vtkMat);
377  m_polydataMeshContourActor->SetUserMatrix(vtkMat);
378 
379  emit(matrixChanged(m_resliceMatrix));
380  update();
381  m_renderer->Render();
382 
383  m_lastmouserPosX = event->pos().x();
384  m_lastmouserPosY = event->pos().y();
385  event->accept();
386  } else {
387  // propagate event to allow colormap change in vtk
388  usViewerWidget::mouseMoveEvent(event);
389  }
390 }
391 
396 {
397  vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New();
398  std::string absFileName = us::getDataSetPath() + "/sceenshot.png";
399  std::cout << "saving slice in file : " << absFileName << std::endl;
400  writer->SetFileName(absFileName.c_str());
401  writer->SetInputConnection(m_reslice->GetOutputPort());
402  writer->Write();
403 }
404 
410 {
411  // Render to update the view and avoid getting an empty 2D image at reslice output
412 #if USTK_HAVE_VTK_VERSION < 0x090000
413  this->GetRenderWindow()->Render();
414 #else
415  renderWindow()->Render();
416 #endif
417 
418  // convert current VTK slice to a usImagePostScan2D
419  vtkSmartPointer<vtkImageData> vtkImage2D;
420  vtkImage2D = m_reslice->GetOutput();
421  usVTKConverter::convert(vtkImage2D, image2D);
422 }
423 
427 void us2DSceneWidget::mousePressEvent(QMouseEvent *event)
428 {
429  if (m_pPressed || m_pickingState) {
430  int x = event->pos().x();
431  int y = this->height() - event->pos().y(); // change for VTK window coordinate system, Y axis is inverted
432 
433  m_propPicker->Pick(x, y, 0.0, m_renderer);
434 
435  if (m_propPicker->GetPath()) {
436  double p[3];
437  m_propPicker->GetPickPosition(p);
438 
439  // transform in 3D image coordinate system
440  vpHomogeneousMatrix MCurrrent;
441  usVTKConverter::convert(m_resliceMatrix, MCurrrent);
442 
443  vpColVector vector(4);
444  vector.data[0] = p[0];
445  vector.data[1] = p[1];
446  vector.data[2] = p[2];
447  vector.data[3] = 1;
448 
449  vector = MCurrrent * vector;
450  std::cout << "Picked value = " << vector.data[0] << " " << vector.data[1] << " " << vector.data[2] << std::endl;
451  m_pickedVoxel = vector;
452  emit(voxelPicked(vector));
453  } else
454  std::cout << "Pick out of image" << std::endl;
455  }
456  usViewerWidget::mousePressEvent(event);
457 }
458 
459 void us2DSceneWidget::setColor(double r, double g, double b)
460 {
461  // m_renderer->SetBackground(r,g,b);
462  m_polydataPlaneContourActor->GetProperty()->SetColor(r, g, b);
463 }
464 
468 void us2DSceneWidget::drawLine(double u1, double v1, double w1, double u2, double v2, double w2)
469 {
470  // Setup points
471  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
472  points->InsertNextPoint(u1, v1, w1);
473  points->InsertNextPoint(u2, v2, w2);
474 
475  // create a line between each pair of points
476  vtkSmartPointer<vtkLine> line0 = vtkSmartPointer<vtkLine>::New();
477  line0->GetPointIds()->SetId(0, 0);
478  line0->GetPointIds()->SetId(1, 1);
479 
480  // create a cell array to store the line in
481  vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
482  lines->InsertNextCell(line0);
483 
484  // create a polydata to store everything in
485  vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
486 
487  // add the points and lines to the polydata
488  polydata->SetPoints(points);
489  polydata->SetLines(lines);
490 
491  // add polygon in scene
492  vtkSmartPointer<vtkPolyDataMapper> lineMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
493  lineMapper->SetInputData(polydata);
494  lineMapper->SetScalarRange(polydata->GetScalarRange());
495 
496  vtkSmartPointer<vtkActor> lineActor = vtkSmartPointer<vtkActor>::New();
497  lineActor->GetProperty()->SetOpacity(1.0);
498  lineActor->GetProperty()->SetLighting(0);
499  lineActor->GetProperty()->SetLineWidth(1);
500  lineActor->GetProperty()->SetColor(1.0, 0.0, 0.0);
501  lineActor->GetProperty()->SetOpacity(1.0);
502  lineActor->SetMapper(lineMapper);
503 
504  vpHomogeneousMatrix mat;
505  usVTKConverter::convert(m_resliceMatrix, mat);
506  vtkMatrix4x4 *matrix = vtkMatrix4x4::New();
507  usVTKConverter::convert(mat.inverse(), matrix);
508  lineActor->SetUserMatrix(matrix);
509 
510  m_renderer->AddActor(lineActor);
511 #if USTK_HAVE_VTK_VERSION < 0x090000
512  GetRenderWindow()->Render();
513 #else
514  renderWindow()->Render();
515 #endif
516 }
517 
521 #if USTK_HAVE_VTK_VERSION < 0x090000
522 void us2DSceneWidget::updateView() { GetRenderWindow()->Render(); }
523 #else
524 void us2DSceneWidget::updateView() { renderWindow()->Render(); }
525 #endif
526 
531 void us2DSceneWidget::getClick(vpColVector &vec)
532 {
533  m_pickingState = true;
534  QEventLoop loop;
535  connect(this, SIGNAL(voxelPicked(vpColVector)), &loop, SLOT(quit()));
536  loop.exec();
537 
538  vec = m_pickedVoxel;
539  m_pickingState = false;
540 }
541 
542 #endif // USTK_HAVE_VTK_QT
void updateImageData(vtkImageData *imageData)
void keyReleaseEvent(QKeyEvent *event)
void mousePressEvent(QMouseEvent *event)
void getCurrentSlice(usImagePostScan2D< unsigned char > &image2D)
void setColor(double r, double g, double b)
void setImageData(vtkImageData *imageData)
void voxelPicked(vpColVector vector)
void mouseMoveEvent(QMouseEvent *event)
void paintEvent(QPaintEvent *event)
vtkMatrix4x4 * getResliceMatrix()
us2DSceneWidget(QWidget *parent=NULL, Qt::WindowFlags f=Qt::WindowFlags())
void setResliceMatrix(vtkMatrix4x4 *matrix)
vtkImageData * getImageData()
void keyPressEvent(QKeyEvent *event)
void getClick(vpColVector &vec)
void setPolyDataMeshContour(vtkPolyData *polyData)
void matrixChanged(vtkMatrix4x4 *matrix)
void wheelEvent(QWheelEvent *event)
void drawLine(double u1, double v1, double w1, double u2, double v2, double w2)
void setPolyDataPlaneContour(vtkPolyData *polyData)
void changeMatrix(vpHomogeneousMatrix matrix)
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)
void paintEvent(QPaintEvent *event)
VISP_EXPORT std::string getDataSetPath()
Definition: us.cpp:54