Medical Imaging Interaction Toolkit  2018.4.99-9a29ffc6
Medical Imaging Interaction Toolkit
QmitkSlicesInterpolator.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 
16 #include "QmitkStdMultiWidget.h"
17 
19 #include "mitkColorProperty.h"
20 #include "mitkCoreObjectFactory.h"
21 #include "mitkDiffImageApplier.h"
22 #include "mitkInteractionConst.h"
24 #include "mitkOperationEvent.h"
26 #include "mitkProgressBar.h"
27 #include "mitkProperties.h"
28 #include "mitkRenderingManager.h"
29 #include "mitkSegTool2D.h"
32 #include "mitkToolManager.h"
33 #include "mitkUndoController.h"
34 #include <mitkExtractSliceFilter.h>
35 #include <mitkImageReadAccessor.h>
36 #include <mitkImageTimeSelector.h>
37 #include <mitkImageWriteAccessor.h>
38 #include <mitkPlaneProposer.h>
40 #include <mitkVtkImageOverwrite.h>
41 
42 #include <itkCommand.h>
43 
44 #include <QCheckBox>
45 #include <QCursor>
46 #include <QMenu>
47 #include <QMessageBox>
48 #include <QPushButton>
49 #include <QVBoxLayout>
50 
51 #include <vtkPolyVertex.h>
52 #include <vtkUnstructuredGrid.h>
53 
54 //#define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a)))
55 
56 float SURFACE_COLOR_RGB[3] = {0.49f, 1.0f, 0.16f};
57 
58 const std::map<QAction *, mitk::SliceNavigationController *> QmitkSlicesInterpolator::createActionToSliceDimension()
59 {
60  std::map<QAction *, mitk::SliceNavigationController *> actionToSliceDimension;
61  foreach (mitk::SliceNavigationController *slicer, m_ControllerToDeleteObserverTag.keys())
62  {
63  actionToSliceDimension[new QAction(QString::fromStdString(slicer->GetViewDirectionAsString()), nullptr)] = slicer;
64  }
65 
66  return actionToSliceDimension;
67 }
68 
69 QmitkSlicesInterpolator::QmitkSlicesInterpolator(QWidget *parent, const char * /*name*/)
70  : QWidget(parent),
71  // ACTION_TO_SLICEDIMENSION( createActionToSliceDimension() ),
72  m_Interpolator(mitk::SegmentationInterpolationController::New()),
73  m_SurfaceInterpolator(mitk::SurfaceInterpolationController::GetInstance()),
74  m_ToolManager(nullptr),
75  m_Initialized(false),
76  m_LastSNC(nullptr),
77  m_LastSliceIndex(0),
78  m_2DInterpolationEnabled(false),
79  m_3DInterpolationEnabled(false),
80  m_FirstRun(true)
81 {
82  m_GroupBoxEnableExclusiveInterpolationMode = new QGroupBox("Interpolation", this);
83 
84  QVBoxLayout *vboxLayout = new QVBoxLayout(m_GroupBoxEnableExclusiveInterpolationMode);
85 
87  m_PointScorer = mitk::PointCloudScoringFilter::New();
88 
89  m_CmbInterpolation = new QComboBox(m_GroupBoxEnableExclusiveInterpolationMode);
90  m_CmbInterpolation->addItem("Disabled");
91  m_CmbInterpolation->addItem("2-Dimensional");
92  m_CmbInterpolation->addItem("3-Dimensional");
93  vboxLayout->addWidget(m_CmbInterpolation);
94 
95  m_BtnApply2D = new QPushButton("Confirm for single slice", m_GroupBoxEnableExclusiveInterpolationMode);
96  vboxLayout->addWidget(m_BtnApply2D);
97 
98  m_BtnApplyForAllSlices2D = new QPushButton("Confirm for all slices", m_GroupBoxEnableExclusiveInterpolationMode);
99  vboxLayout->addWidget(m_BtnApplyForAllSlices2D);
100 
101  m_BtnApply3D = new QPushButton("Confirm", m_GroupBoxEnableExclusiveInterpolationMode);
102  vboxLayout->addWidget(m_BtnApply3D);
103 
104  m_BtnSuggestPlane = new QPushButton("Suggest a plane", m_GroupBoxEnableExclusiveInterpolationMode);
105  vboxLayout->addWidget(m_BtnSuggestPlane);
106 
107  m_BtnReinit3DInterpolation = new QPushButton("Reinit Interpolation", m_GroupBoxEnableExclusiveInterpolationMode);
108  vboxLayout->addWidget(m_BtnReinit3DInterpolation);
109 
110  m_ChkShowPositionNodes = new QCheckBox("Show Position Nodes", m_GroupBoxEnableExclusiveInterpolationMode);
111  vboxLayout->addWidget(m_ChkShowPositionNodes);
112 
113  this->HideAllInterpolationControls();
114 
115  connect(m_CmbInterpolation, SIGNAL(currentIndexChanged(int)), this, SLOT(OnInterpolationMethodChanged(int)));
116  connect(m_BtnApply2D, SIGNAL(clicked()), this, SLOT(OnAcceptInterpolationClicked()));
117  connect(m_BtnApplyForAllSlices2D, SIGNAL(clicked()), this, SLOT(OnAcceptAllInterpolationsClicked()));
118  connect(m_BtnApply3D, SIGNAL(clicked()), this, SLOT(OnAccept3DInterpolationClicked()));
119 
120  connect(m_BtnSuggestPlane, SIGNAL(clicked()), this, SLOT(OnSuggestPlaneClicked()));
121 
122  connect(m_BtnReinit3DInterpolation, SIGNAL(clicked()), this, SLOT(OnReinit3DInterpolation()));
123  connect(m_ChkShowPositionNodes, SIGNAL(toggled(bool)), this, SLOT(OnShowMarkers(bool)));
124  connect(m_ChkShowPositionNodes, SIGNAL(toggled(bool)), this, SIGNAL(SignalShowMarkerNodes(bool)));
125 
126  QHBoxLayout *layout = new QHBoxLayout(this);
127  layout->addWidget(m_GroupBoxEnableExclusiveInterpolationMode);
128  this->setLayout(layout);
129 
130  itk::ReceptorMemberCommand<QmitkSlicesInterpolator>::Pointer command =
131  itk::ReceptorMemberCommand<QmitkSlicesInterpolator>::New();
132  command->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnInterpolationInfoChanged);
133  InterpolationInfoChangedObserverTag = m_Interpolator->AddObserver(itk::ModifiedEvent(), command);
134 
135  itk::ReceptorMemberCommand<QmitkSlicesInterpolator>::Pointer command2 =
136  itk::ReceptorMemberCommand<QmitkSlicesInterpolator>::New();
137  command2->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnSurfaceInterpolationInfoChanged);
138  SurfaceInterpolationInfoChangedObserverTag = m_SurfaceInterpolator->AddObserver(itk::ModifiedEvent(), command2);
139 
140  // feedback node and its visualization properties
141  m_FeedbackNode = mitk::DataNode::New();
142  mitk::CoreObjectFactory::GetInstance()->SetDefaultProperties(m_FeedbackNode);
143 
144  m_FeedbackNode->SetProperty("binary", mitk::BoolProperty::New(true));
145  m_FeedbackNode->SetProperty("outline binary", mitk::BoolProperty::New(true));
146  m_FeedbackNode->SetProperty("color", mitk::ColorProperty::New(255.0, 255.0, 0.0));
147  m_FeedbackNode->SetProperty("texture interpolation", mitk::BoolProperty::New(false));
148  m_FeedbackNode->SetProperty("layer", mitk::IntProperty::New(20));
149  m_FeedbackNode->SetProperty("levelwindow", mitk::LevelWindowProperty::New(mitk::LevelWindow(0, 1)));
150  m_FeedbackNode->SetProperty("name", mitk::StringProperty::New("Interpolation feedback"));
151  m_FeedbackNode->SetProperty("opacity", mitk::FloatProperty::New(0.8));
152  m_FeedbackNode->SetProperty("helper object", mitk::BoolProperty::New(true));
153 
154  m_InterpolatedSurfaceNode = mitk::DataNode::New();
155  m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB));
156  m_InterpolatedSurfaceNode->SetProperty("name", mitk::StringProperty::New("Surface Interpolation feedback"));
157  m_InterpolatedSurfaceNode->SetProperty("opacity", mitk::FloatProperty::New(0.5));
158  m_InterpolatedSurfaceNode->SetProperty("line width", mitk::FloatProperty::New(4.0f));
159  m_InterpolatedSurfaceNode->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false));
160  m_InterpolatedSurfaceNode->SetProperty("helper object", mitk::BoolProperty::New(true));
161  m_InterpolatedSurfaceNode->SetVisibility(false);
162 
163  m_3DContourNode = mitk::DataNode::New();
164  m_3DContourNode->SetProperty("color", mitk::ColorProperty::New(0.0, 0.0, 0.0));
165  m_3DContourNode->SetProperty("hidden object", mitk::BoolProperty::New(true));
166  m_3DContourNode->SetProperty("name", mitk::StringProperty::New("Drawn Contours"));
167  m_3DContourNode->SetProperty("material.representation", mitk::VtkRepresentationProperty::New(VTK_WIREFRAME));
168  m_3DContourNode->SetProperty("material.wireframeLineWidth", mitk::FloatProperty::New(2.0f));
169  m_3DContourNode->SetProperty("3DContourContainer", mitk::BoolProperty::New(true));
170  m_3DContourNode->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false));
171  m_3DContourNode->SetVisibility(
173  m_3DContourNode->SetVisibility(
175  m_3DContourNode->SetVisibility(
177  m_3DContourNode->SetVisibility(
179 
180  QWidget::setContentsMargins(0, 0, 0, 0);
181  if (QWidget::layout() != nullptr)
182  {
183  QWidget::layout()->setContentsMargins(0, 0, 0, 0);
184  }
185 
186  // For running 3D Interpolation in background
187  // create a QFuture and a QFutureWatcher
188 
189  connect(&m_Watcher, SIGNAL(started()), this, SLOT(StartUpdateInterpolationTimer()));
190  connect(&m_Watcher, SIGNAL(finished()), this, SLOT(OnSurfaceInterpolationFinished()));
191  connect(&m_Watcher, SIGNAL(finished()), this, SLOT(StopUpdateInterpolationTimer()));
192  m_Timer = new QTimer(this);
193  connect(m_Timer, SIGNAL(timeout()), this, SLOT(ChangeSurfaceColor()));
194 }
195 
197 {
198  if (m_DataStorage == storage)
199  {
200  return;
201  }
202 
203  if (m_DataStorage.IsNotNull())
204  {
205  m_DataStorage->RemoveNodeEvent.RemoveListener(
206  mitk::MessageDelegate1<QmitkSlicesInterpolator, const mitk::DataNode*>(this, &QmitkSlicesInterpolator::NodeRemoved)
207  );
208  }
209 
210  m_DataStorage = storage;
211  m_SurfaceInterpolator->SetDataStorage(storage);
212 
213  if (m_DataStorage.IsNotNull())
214  {
215  m_DataStorage->RemoveNodeEvent.AddListener(
216  mitk::MessageDelegate1<QmitkSlicesInterpolator, const mitk::DataNode*>(this, &QmitkSlicesInterpolator::NodeRemoved)
217  );
218  }
219 }
220 
222 {
223  if (m_DataStorage.IsNotNull())
224  {
225  return m_DataStorage;
226  }
227  else
228  {
229  return nullptr;
230  }
231 }
232 
234  const QList<mitk::SliceNavigationController *> &controllers)
235 {
236  Q_ASSERT(!controllers.empty());
237 
238  if (m_Initialized)
239  {
240  // remove old observers
241  Uninitialize();
242  }
243 
244  m_ToolManager = toolManager;
245 
246  if (m_ToolManager)
247  {
248  // set enabled only if a segmentation is selected
249  mitk::DataNode *node = m_ToolManager->GetWorkingData(0);
250  QWidget::setEnabled(node != nullptr);
251 
252  // react whenever the set of selected segmentation changes
253  m_ToolManager->WorkingDataChanged +=
255  m_ToolManager->ReferenceDataChanged += mitk::MessageDelegate<QmitkSlicesInterpolator>(
257 
258  // connect to the slice navigation controller. after each change, call the interpolator
259  foreach (mitk::SliceNavigationController *slicer, controllers)
260  {
261  // Has to be initialized
262  m_LastSNC = slicer;
263  m_TimePoints.insert(slicer, slicer->GetSelectedTimePoint());
264 
265  itk::MemberCommand<QmitkSlicesInterpolator>::Pointer deleteCommand =
266  itk::MemberCommand<QmitkSlicesInterpolator>::New();
267  deleteCommand->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnSliceNavigationControllerDeleted);
268  m_ControllerToDeleteObserverTag.insert(slicer, slicer->AddObserver(itk::DeleteEvent(), deleteCommand));
269 
270  itk::MemberCommand<QmitkSlicesInterpolator>::Pointer timeChangedCommand =
271  itk::MemberCommand<QmitkSlicesInterpolator>::New();
272  timeChangedCommand->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnTimeChanged);
273  m_ControllerToTimeObserverTag.insert(
274  slicer, slicer->AddObserver(mitk::SliceNavigationController::TimeGeometryEvent(nullptr, 0), timeChangedCommand));
275 
276  itk::MemberCommand<QmitkSlicesInterpolator>::Pointer sliceChangedCommand =
277  itk::MemberCommand<QmitkSlicesInterpolator>::New();
278  sliceChangedCommand->SetCallbackFunction(this, &QmitkSlicesInterpolator::OnSliceChanged);
279  m_ControllerToSliceObserverTag.insert(
280  slicer, slicer->AddObserver(mitk::SliceNavigationController::GeometrySliceEvent(nullptr, 0), sliceChangedCommand));
281  }
283  }
284 
285  m_Initialized = true;
286 }
287 
289 {
290  if (m_ToolManager.IsNotNull())
291  {
292  m_ToolManager->WorkingDataChanged -=
294  m_ToolManager->ReferenceDataChanged -= mitk::MessageDelegate<QmitkSlicesInterpolator>(
296  }
297 
298  foreach (mitk::SliceNavigationController *slicer, m_ControllerToSliceObserverTag.keys())
299  {
300  slicer->RemoveObserver(m_ControllerToDeleteObserverTag.take(slicer));
301  slicer->RemoveObserver(m_ControllerToTimeObserverTag.take(slicer));
302  slicer->RemoveObserver(m_ControllerToSliceObserverTag.take(slicer));
303  }
304 
305  ACTION_TO_SLICEDIMENSION.clear();
306 
307  m_ToolManager = nullptr;
308 
309  m_Initialized = false;
310 }
311 
313 {
314  if (m_Initialized)
315  {
316  // remove old observers
317  Uninitialize();
318  }
319 
320  WaitForFutures();
321 
322  if (m_DataStorage.IsNotNull())
323  {
324  m_DataStorage->RemoveNodeEvent.RemoveListener(
325  mitk::MessageDelegate1<QmitkSlicesInterpolator, const mitk::DataNode*>(this, &QmitkSlicesInterpolator::NodeRemoved)
326  );
327  if (m_DataStorage->Exists(m_3DContourNode))
328  m_DataStorage->Remove(m_3DContourNode);
329  if (m_DataStorage->Exists(m_InterpolatedSurfaceNode))
330  m_DataStorage->Remove(m_InterpolatedSurfaceNode);
331  }
332 
333  // remove observer
334  m_Interpolator->RemoveObserver(InterpolationInfoChangedObserverTag);
335  m_SurfaceInterpolator->RemoveObserver(SurfaceInterpolationInfoChangedObserverTag);
336 
337  delete m_Timer;
338 }
339 
344 {
345  QWidget::setEnabled(enable);
346 
347  // Set the gui elements of the different interpolation modi enabled
348  if (enable)
349  {
350  if (m_2DInterpolationEnabled)
351  {
352  this->Show2DInterpolationControls(true);
353  m_Interpolator->Activate2DInterpolation(true);
354  }
355  else if (m_3DInterpolationEnabled)
356  {
357  this->Show3DInterpolationControls(true);
358  this->Show3DInterpolationResult(true);
359  }
360  }
361  // Set all gui elements of the interpolation disabled
362  else
363  {
364  this->HideAllInterpolationControls();
365  this->Show3DInterpolationResult(false);
366  }
367 }
368 
370 {
371  OnInterpolationActivated(status);
372  m_Interpolator->Activate2DInterpolation(status);
373 }
374 
376 {
378 }
379 
381 {
382  if (status)
383  {
384  OnInterpolationActivated(!status);
386  this->Show3DInterpolationResult(false);
387  }
388 }
389 
390 void QmitkSlicesInterpolator::HideAllInterpolationControls()
391 {
392  this->Show2DInterpolationControls(false);
393  this->Show3DInterpolationControls(false);
394 }
395 
396 void QmitkSlicesInterpolator::Show2DInterpolationControls(bool show)
397 {
398  m_BtnApply2D->setVisible(show);
399  m_BtnApplyForAllSlices2D->setVisible(show);
400 }
401 
402 void QmitkSlicesInterpolator::Show3DInterpolationControls(bool show)
403 {
404  m_BtnApply3D->setVisible(show);
405  m_BtnSuggestPlane->setVisible(show);
406  m_ChkShowPositionNodes->setVisible(show);
407  m_BtnReinit3DInterpolation->setVisible(show);
408 }
409 
411 {
412  switch (index)
413  {
414  case 0: // Disabled
415  m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation");
416  this->HideAllInterpolationControls();
417  this->OnInterpolationActivated(false);
418  this->On3DInterpolationActivated(false);
419  this->Show3DInterpolationResult(false);
420  m_Interpolator->Activate2DInterpolation(false);
421  break;
422 
423  case 1: // 2D
424  m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation (Enabled)");
425  this->HideAllInterpolationControls();
426  this->Show2DInterpolationControls(true);
427  this->OnInterpolationActivated(true);
428  this->On3DInterpolationActivated(false);
429  m_Interpolator->Activate2DInterpolation(true);
430  break;
431 
432  case 2: // 3D
433  m_GroupBoxEnableExclusiveInterpolationMode->setTitle("Interpolation (Enabled)");
434  this->HideAllInterpolationControls();
435  this->Show3DInterpolationControls(true);
436  this->OnInterpolationActivated(false);
437  this->On3DInterpolationActivated(true);
438  m_Interpolator->Activate2DInterpolation(false);
439  break;
440 
441  default:
442  MITK_ERROR << "Unknown interpolation method!";
443  m_CmbInterpolation->setCurrentIndex(0);
444  break;
445  }
446 }
447 
449 {
450  mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers =
451  m_DataStorage->GetSubset(mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true)));
452 
453  for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End();
454  ++it)
455  {
456  it->Value()->SetProperty("helper object", mitk::BoolProperty::New(!state));
457  }
458 }
459 
461 {
462  if (m_ToolManager->GetWorkingData(0) != nullptr)
463  {
464  m_Segmentation = dynamic_cast<mitk::Image *>(m_ToolManager->GetWorkingData(0)->GetData());
465  m_BtnReinit3DInterpolation->setEnabled(true);
466  }
467  else
468  {
469  // If no workingdata is set, remove the interpolation feedback
470  this->GetDataStorage()->Remove(m_FeedbackNode);
471  m_FeedbackNode->SetData(nullptr);
472  this->GetDataStorage()->Remove(m_3DContourNode);
473  m_3DContourNode->SetData(nullptr);
474  this->GetDataStorage()->Remove(m_InterpolatedSurfaceNode);
475  m_InterpolatedSurfaceNode->SetData(nullptr);
476  m_BtnReinit3DInterpolation->setEnabled(false);
477  return;
478  }
479  // Updating the current selected segmentation for the 3D interpolation
481 
482  if (m_2DInterpolationEnabled)
483  {
484  OnInterpolationActivated(true); // re-initialize if needed
485  }
486  this->CheckSupportedImageDimension();
487 }
488 
490 {
491 }
492 
493 void QmitkSlicesInterpolator::OnTimeChanged(itk::Object *sender, const itk::EventObject &e)
494 {
495  // Check if we really have a GeometryTimeEvent
496  if (!dynamic_cast<const mitk::SliceNavigationController::GeometryTimeEvent *>(&e))
497  return;
498 
499  mitk::SliceNavigationController *slicer = dynamic_cast<mitk::SliceNavigationController *>(sender);
500  Q_ASSERT(slicer);
501 
502  const auto timePoint = slicer->GetSelectedTimePoint();
503  m_TimePoints[slicer] = timePoint;
504 
505  m_SurfaceInterpolator->SetCurrentTimePoint(timePoint);
506 
507  if (m_LastSNC == slicer)
508  {
509  slicer->SendSlice(); // will trigger a new interpolation
510  }
511 }
512 
513 void QmitkSlicesInterpolator::OnSliceChanged(itk::Object *sender, const itk::EventObject &e)
514 {
515  // Check whether we really have a GeometrySliceEvent
516  if (!dynamic_cast<const mitk::SliceNavigationController::GeometrySliceEvent *>(&e))
517  return;
518 
519  mitk::SliceNavigationController *slicer = dynamic_cast<mitk::SliceNavigationController *>(sender);
520 
522  {
523  slicer->GetRenderer()->RequestUpdate();
524  }
525 }
526 
529 {
530  if (!m_2DInterpolationEnabled)
531  return false;
532 
533  try
534  {
537 
538  mitk::TimeGeometry *tsg = event.GetTimeGeometry();
539  if (tsg && m_TimePoints.contains(slicer) && tsg->IsValidTimePoint(m_TimePoints[slicer]))
540  {
541  mitk::SlicedGeometry3D *slicedGeometry =
542  dynamic_cast<mitk::SlicedGeometry3D *>(tsg->GetGeometryForTimePoint(m_TimePoints[slicer]).GetPointer());
543  if (slicedGeometry)
544  {
545  m_LastSNC = slicer;
546  mitk::PlaneGeometry *plane =
547  dynamic_cast<mitk::PlaneGeometry *>(slicedGeometry->GetPlaneGeometry(event.GetPos()));
548  if (plane)
549  Interpolate(plane, m_TimePoints[slicer], slicer);
550  return true;
551  }
552  }
553  }
554  catch (const std::bad_cast &)
555  {
556  return false; // so what
557  }
558 
559  return false;
560 }
561 
563  mitk::TimePointType timePoint,
565 {
566  if (m_ToolManager)
567  {
568  mitk::DataNode *node = m_ToolManager->GetWorkingData(0);
569  if (node)
570  {
571  m_Segmentation = dynamic_cast<mitk::Image *>(node->GetData());
572  if (m_Segmentation)
573  {
574  if (!m_Segmentation->GetTimeGeometry()->IsValidTimePoint(timePoint))
575  {
576  MITK_WARN << "Cannot interpolate segmentation. Passed time point is not within the time bounds of WorkingImage. Time point: " << timePoint;
577  return;
578  }
579  const auto timeStep = m_Segmentation->GetTimeGeometry()->TimePointToTimeStep(timePoint);
580 
581  int clickedSliceDimension(-1);
582  int clickedSliceIndex(-1);
583 
584  // calculate real slice position, i.e. slice of the image and not slice of the TimeSlicedGeometry
585  mitk::SegTool2D::DetermineAffectedImageSlice(m_Segmentation, plane, clickedSliceDimension, clickedSliceIndex);
586 
587  mitk::Image::Pointer interpolation =
588  m_Interpolator->Interpolate(clickedSliceDimension, clickedSliceIndex, plane, timeStep);
589  m_FeedbackNode->SetData(interpolation);
590 
591  m_LastSNC = slicer;
592  m_LastSliceIndex = clickedSliceIndex;
593  }
594  }
595  }
596 }
597 
599 {
600  mitk::Surface::Pointer interpolatedSurface = m_SurfaceInterpolator->GetInterpolationResult();
601  mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0);
602 
603  if (interpolatedSurface.IsNotNull() && workingNode &&
604  workingNode->IsVisible(
606  {
607  m_BtnApply3D->setEnabled(true);
608  m_BtnSuggestPlane->setEnabled(true);
609  m_InterpolatedSurfaceNode->SetData(interpolatedSurface);
610  m_3DContourNode->SetData(m_SurfaceInterpolator->GetContoursAsSurface());
611 
612  this->Show3DInterpolationResult(true);
613 
614  if (!m_DataStorage->Exists(m_InterpolatedSurfaceNode))
615  {
616  m_DataStorage->Add(m_InterpolatedSurfaceNode);
617  }
618  if (!m_DataStorage->Exists(m_3DContourNode))
619  {
620  m_DataStorage->Add(m_3DContourNode, workingNode);
621  }
622  }
623  else if (interpolatedSurface.IsNull())
624  {
625  m_BtnApply3D->setEnabled(false);
626  m_BtnSuggestPlane->setEnabled(false);
627 
628  if (m_DataStorage->Exists(m_InterpolatedSurfaceNode))
629  {
630  this->Show3DInterpolationResult(false);
631  }
632  }
633 
634  m_BtnReinit3DInterpolation->setEnabled(true);
635 
636  foreach (mitk::SliceNavigationController *slicer, m_ControllerToTimeObserverTag.keys())
637  {
638  slicer->GetRenderer()->RequestUpdate();
639  }
640 }
641 
643 {
644  if (m_Segmentation && m_FeedbackNode->GetData())
645  {
646  // Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk
647  // reslicer
648  vtkSmartPointer<mitkVtkImageOverwrite> reslice = vtkSmartPointer<mitkVtkImageOverwrite>::New();
649 
650  // Set slice as input
651  mitk::Image::Pointer slice = dynamic_cast<mitk::Image *>(m_FeedbackNode->GetData());
652  reslice->SetInputSlice(slice->GetSliceData()->GetVtkImageAccessor(slice)->GetVtkImageData());
653  // set overwrite mode to true to write back to the image volume
654  reslice->SetOverwriteMode(true);
655  reslice->Modified();
656 
657  const auto timePoint = m_LastSNC->GetSelectedTimePoint();
658  if (!m_Segmentation->GetTimeGeometry()->IsValidTimePoint(timePoint))
659  {
660  MITK_WARN << "Cannot accept interpolation. Time point selected by SliceNavigationController is not within the time bounds of segmentation. Time point: " << timePoint;
661  return;
662  }
663 
665  extractor->SetInput(m_Segmentation);
666  const auto timeStep = m_Segmentation->GetTimeGeometry()->TimePointToTimeStep(timePoint);
667  extractor->SetTimeStep(timeStep);
668  extractor->SetWorldGeometry(m_LastSNC->GetCurrentPlaneGeometry());
669  extractor->SetVtkOutputRequest(true);
670  extractor->SetResliceTransformByGeometry(m_Segmentation->GetTimeGeometry()->GetGeometryForTimeStep(timeStep));
671 
672  extractor->Modified();
673  extractor->Update();
674 
675  // the image was modified within the pipeline, but not marked so
676  m_Segmentation->Modified();
677  m_Segmentation->GetVtkImageData()->Modified();
678 
679  m_FeedbackNode->SetData(nullptr);
681  }
682 }
683 
685 {
686  /*
687  * What exactly is done here:
688  * 1. We create an empty diff image for the current segmentation
689  * 2. All interpolated slices are written into the diff image
690  * 3. Then the diffimage is applied to the original segmentation
691  */
692  if (m_Segmentation)
693  {
694  mitk::Image::Pointer image3D = m_Segmentation;
695  unsigned int timeStep(0);
696  const auto timePoint = slicer->GetSelectedTimePoint();
697  if (m_Segmentation->GetDimension() == 4)
698  {
699  if (!m_Segmentation->GetTimeGeometry()->IsValidTimePoint(timePoint))
700  {
701  MITK_WARN << "Cannot accept all interpolations. Time point selected by passed SliceNavigationController is not within the time bounds of segmentation. Time point: " << timePoint;
702  return;
703  }
704 
705  timeStep = m_Segmentation->GetTimeGeometry()->TimePointToTimeStep(timePoint);
707  timeSelector->SetInput(m_Segmentation);
708  timeSelector->SetTimeNr(timeStep);
709  timeSelector->Update();
710  image3D = timeSelector->GetOutput();
711  }
712  // create a empty diff image for the undo operation
714  diffImage->Initialize(image3D);
715 
716  // Create scope for ImageWriteAccessor so that the accessor is destroyed
717  // after the image is initialized. Otherwise later image access will lead to an error
718  {
719  mitk::ImageWriteAccessor imAccess(diffImage);
720 
721  // Set all pixels to zero
722  mitk::PixelType pixelType(mitk::MakeScalarPixelType<mitk::Tool::DefaultSegmentationDataType>());
723 
724  // For legacy purpose support former pixel type of segmentations (before multilabel)
725  if (m_Segmentation->GetImageDescriptor()->GetChannelDescriptor().GetPixelType().GetComponentType() ==
726  itk::ImageIOBase::UCHAR)
727  {
728  pixelType = mitk::MakeScalarPixelType<unsigned char>();
729  }
730 
731  memset(imAccess.GetData(),
732  0,
733  (pixelType.GetBpe() >> 3) * diffImage->GetDimension(0) * diffImage->GetDimension(1) *
734  diffImage->GetDimension(2));
735  }
736 
737  // Since we need to shift the plane it must be clone so that the original plane isn't altered
738  mitk::PlaneGeometry::Pointer reslicePlane = slicer->GetCurrentPlaneGeometry()->Clone();
739 
740  int sliceDimension(-1);
741  int sliceIndex(-1);
742  mitk::SegTool2D::DetermineAffectedImageSlice(m_Segmentation, reslicePlane, sliceDimension, sliceIndex);
743 
744  unsigned int zslices = m_Segmentation->GetDimension(sliceDimension);
746 
747  mitk::Point3D origin = reslicePlane->GetOrigin();
748  unsigned int totalChangedSlices(0);
749 
750  for (unsigned int sliceIndex = 0; sliceIndex < zslices; ++sliceIndex)
751  {
752  // Transforming the current origin of the reslice plane
753  // so that it matches the one of the next slice
754  m_Segmentation->GetSlicedGeometry()->WorldToIndex(origin, origin);
755  origin[sliceDimension] = sliceIndex;
756  m_Segmentation->GetSlicedGeometry()->IndexToWorld(origin, origin);
757  reslicePlane->SetOrigin(origin);
758  // Set the slice as 'input'
759  mitk::Image::Pointer interpolation =
760  m_Interpolator->Interpolate(sliceDimension, sliceIndex, reslicePlane, timeStep);
761 
762  if (interpolation.IsNotNull()) // we don't check if interpolation is necessary/sensible - but m_Interpolator does
763  {
764  // Setting up the reslicing pipeline which allows us to write the interpolation results back into
765  // the image volume
766  vtkSmartPointer<mitkVtkImageOverwrite> reslice = vtkSmartPointer<mitkVtkImageOverwrite>::New();
767 
768  // set overwrite mode to true to write back to the image volume
769  reslice->SetInputSlice(interpolation->GetSliceData()->GetVtkImageAccessor(interpolation)->GetVtkImageData());
770  reslice->SetOverwriteMode(true);
771  reslice->Modified();
772 
774  diffslicewriter->SetInput(diffImage);
775  diffslicewriter->SetTimeStep(0);
776  diffslicewriter->SetWorldGeometry(reslicePlane);
777  diffslicewriter->SetVtkOutputRequest(true);
778  diffslicewriter->SetResliceTransformByGeometry(diffImage->GetTimeGeometry()->GetGeometryForTimeStep(0));
779 
780  diffslicewriter->Modified();
781  diffslicewriter->Update();
782  ++totalChangedSlices;
783  }
785  }
787 
788  if (totalChangedSlices > 0)
789  {
790  // store undo stack items
791  if (true)
792  {
793  // create do/undo operations
795  new mitk::ApplyDiffImageOperation(mitk::OpTEST, m_Segmentation, diffImage, timeStep);
797  new mitk::ApplyDiffImageOperation(mitk::OpTEST, m_Segmentation, diffImage, timeStep);
798  undoOp->SetFactor(-1.0);
799  std::stringstream comment;
800  comment << "Confirm all interpolations (" << totalChangedSlices << ")";
801  mitk::OperationEvent *undoStackItem =
802  new mitk::OperationEvent(mitk::DiffImageApplier::GetInstanceForUndo(), doOp, undoOp, comment.str());
806 
807  // acutally apply the changes here to the original image
809  }
810  }
811 
812  m_FeedbackNode->SetData(nullptr);
814  }
815 }
816 
818 {
819  // this redirect is for calling from outside
820 
821  if (slicer == nullptr)
823  else
824  AcceptAllInterpolations(slicer);
825 }
826 
828 {
829  QMenu orientationPopup(this);
830  std::map<QAction *, mitk::SliceNavigationController *>::const_iterator it;
831  for (it = ACTION_TO_SLICEDIMENSION.begin(); it != ACTION_TO_SLICEDIMENSION.end(); it++)
832  orientationPopup.addAction(it->first);
833 
834  connect(&orientationPopup, SIGNAL(triggered(QAction *)), this, SLOT(OnAcceptAllPopupActivated(QAction *)));
835 
836  orientationPopup.exec(QCursor::pos());
837 }
838 
840 {
841  if (m_InterpolatedSurfaceNode.IsNotNull() && m_InterpolatedSurfaceNode->GetData())
842  {
843  mitk::DataNode *segmentationNode = m_ToolManager->GetWorkingData(0);
844  mitk::Image *currSeg = dynamic_cast<mitk::Image *>(segmentationNode->GetData());
845 
847  s2iFilter->MakeOutputBinaryOn();
848  if (currSeg->GetPixelType().GetComponentType() == itk::ImageIOBase::USHORT)
849  s2iFilter->SetUShortBinaryPixelType(true);
850  s2iFilter->SetInput(dynamic_cast<mitk::Surface *>(m_InterpolatedSurfaceNode->GetData()));
851 
852  // check if ToolManager holds valid ReferenceData
853  if (m_ToolManager->GetReferenceData(0) == nullptr || m_ToolManager->GetWorkingData(0) == nullptr)
854  {
855  return;
856  }
857  s2iFilter->SetImage(dynamic_cast<mitk::Image *>(m_ToolManager->GetReferenceData(0)->GetData()));
858  s2iFilter->Update();
859 
860  mitk::Image::Pointer newSeg = s2iFilter->GetOutput();
861 
862  const auto timePoint = m_LastSNC->GetSelectedTimePoint();
863  if (!m_ToolManager->GetReferenceData(0)->GetData()->GetTimeGeometry()->IsValidTimePoint(timePoint) ||
864  !m_ToolManager->GetWorkingData(0)->GetData()->GetTimeGeometry()->IsValidTimePoint(timePoint))
865  {
866  MITK_WARN << "Cannot accept interpolation. Time point selected by SliceNavigationController is not within the time bounds of reference or working image. Time point: " << timePoint;
867  return;
868  }
869 
870  const auto newTimeStep = newSeg->GetTimeGeometry()->TimePointToTimeStep(timePoint);
871  mitk::ImageReadAccessor readAccess(newSeg, newSeg->GetVolumeData(newTimeStep));
872  const void *cPointer = readAccess.GetData();
873 
874  if (currSeg && cPointer)
875  {
876  const auto curTimeStep = currSeg->GetTimeGeometry()->TimePointToTimeStep(timePoint);
877  currSeg->SetVolume(cPointer, curTimeStep, 0);
878  }
879  else
880  {
881  return;
882  }
883 
884  m_CmbInterpolation->setCurrentIndex(0);
887  float rgb[3];
888  segmentationNode->GetColor(rgb);
889  segSurface->SetColor(rgb);
890  segSurface->SetData(m_InterpolatedSurfaceNode->GetData());
891  std::stringstream stream;
892  stream << segmentationNode->GetName();
893  stream << "_";
894  stream << "3D-interpolation";
895  segSurface->SetName(stream.str());
896  segSurface->SetProperty("opacity", mitk::FloatProperty::New(0.7));
897  segSurface->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(true));
898  segSurface->SetProperty("3DInterpolationResult", mitk::BoolProperty::New(true));
899  segSurface->SetVisibility(false);
900  m_DataStorage->Add(segSurface, segmentationNode);
901  this->Show3DInterpolationResult(false);
902  }
903 }
904 
905 void ::QmitkSlicesInterpolator::OnSuggestPlaneClicked()
906 {
907  if (m_PlaneWatcher.isRunning())
908  m_PlaneWatcher.waitForFinished();
909  m_PlaneFuture = QtConcurrent::run(this, &QmitkSlicesInterpolator::RunPlaneSuggestion);
910  m_PlaneWatcher.setFuture(m_PlaneFuture);
911 }
912 
913 void ::QmitkSlicesInterpolator::RunPlaneSuggestion()
914 {
915  if (m_FirstRun)
917  else
919 
920  m_EdgeDetector->SetSegmentationMask(m_Segmentation);
921  m_EdgeDetector->SetInput(dynamic_cast<mitk::Image *>(m_ToolManager->GetReferenceData(0)->GetData()));
922  m_EdgeDetector->Update();
923 
925  uGrid->SetVtkUnstructuredGrid(m_EdgeDetector->GetOutput()->GetVtkUnstructuredGrid());
926 
928 
929  mitk::Surface::Pointer surface = dynamic_cast<mitk::Surface *>(m_InterpolatedSurfaceNode->GetData());
930 
931  vtkSmartPointer<vtkPolyData> vtkpoly = surface->GetVtkPolyData();
932  vtkSmartPointer<vtkPoints> vtkpoints = vtkpoly->GetPoints();
933 
934  vtkSmartPointer<vtkUnstructuredGrid> vGrid = vtkSmartPointer<vtkUnstructuredGrid>::New();
935  vtkSmartPointer<vtkPolyVertex> verts = vtkSmartPointer<vtkPolyVertex>::New();
936 
937  verts->GetPointIds()->SetNumberOfIds(vtkpoints->GetNumberOfPoints());
938  for (int i = 0; i < vtkpoints->GetNumberOfPoints(); i++)
939  {
940  verts->GetPointIds()->SetId(i, i);
941  }
942 
943  vGrid->Allocate(1);
944  vGrid->InsertNextCell(verts->GetCellType(), verts->GetPointIds());
945  vGrid->SetPoints(vtkpoints);
946 
948  interpolationGrid->SetVtkUnstructuredGrid(vGrid);
949 
950  m_PointScorer->SetInput(0, uGrid);
951  m_PointScorer->SetInput(1, interpolationGrid);
952  m_PointScorer->Update();
953 
955  scoredGrid = m_PointScorer->GetOutput();
956 
958 
961  clusterFilter->SetInput(scoredGrid);
962  clusterFilter->SetMeshing(false);
963  clusterFilter->SetMinPts(4);
964  clusterFilter->Seteps(spacing);
965  clusterFilter->Update();
966 
968 
969  // Create plane suggestion
972  mitk::PlaneProposer planeProposer;
973  std::vector<mitk::UnstructuredGrid::Pointer> grids = clusterFilter->GetAllClusters();
974 
975  planeProposer.SetUnstructuredGrids(grids);
976  mitk::SliceNavigationController::Pointer snc = br->GetSliceNavigationController();
977  planeProposer.SetSliceNavigationController(snc);
978  planeProposer.SetUseDistances(true);
979  try
980  {
981  planeProposer.CreatePlaneInfo();
982  }
983  catch (const mitk::Exception &e)
984  {
985  MITK_ERROR << e.what();
986  }
987 
989 
990  m_FirstRun = false;
991 }
992 
994 {
996  mitk::NodePredicateProperty::New("3DContourContainer", mitk::BoolProperty::New(true));
997  mitk::DataStorage::SetOfObjects::ConstPointer contourNodes =
998  m_DataStorage->GetDerivations(m_ToolManager->GetWorkingData(0), pred);
999 
1000  if (contourNodes->Size() != 0)
1001  {
1002  m_BtnApply3D->setEnabled(true);
1003  m_3DContourNode = contourNodes->at(0);
1004  mitk::Surface::Pointer contours = dynamic_cast<mitk::Surface *>(m_3DContourNode->GetData());
1005  if (contours)
1007  m_BtnReinit3DInterpolation->setEnabled(false);
1008  }
1009  else
1010  {
1011  m_BtnApply3D->setEnabled(false);
1012  QMessageBox errorInfo;
1013  errorInfo.setWindowTitle("Reinitialize surface interpolation");
1014  errorInfo.setIcon(QMessageBox::Information);
1015  errorInfo.setText("No contours available for the selected segmentation!");
1016  errorInfo.exec();
1017  }
1018 }
1019 
1021 {
1022  try
1023  {
1024  std::map<QAction *, mitk::SliceNavigationController *>::const_iterator iter = ACTION_TO_SLICEDIMENSION.find(action);
1025  if (iter != ACTION_TO_SLICEDIMENSION.end())
1026  {
1027  mitk::SliceNavigationController *slicer = iter->second;
1028  AcceptAllInterpolations(slicer);
1029  }
1030  }
1031  catch (...)
1032  {
1033  /* Showing message box with possible memory error */
1034  QMessageBox errorInfo;
1035  errorInfo.setWindowTitle("Interpolation Process");
1036  errorInfo.setIcon(QMessageBox::Critical);
1037  errorInfo.setText("An error occurred during interpolation. Possible cause: Not enough memory!");
1038  errorInfo.exec();
1039 
1040  // additional error message on std::cerr
1041  std::cerr << "Ill construction in " __FILE__ " l. " << __LINE__ << std::endl;
1042  }
1043 }
1044 
1046 {
1047  m_2DInterpolationEnabled = on;
1048 
1049  try
1050  {
1051  if (m_DataStorage.IsNotNull())
1052  {
1053  if (on && !m_DataStorage->Exists(m_FeedbackNode))
1054  {
1055  m_DataStorage->Add(m_FeedbackNode);
1056  }
1057  }
1058  }
1059  catch (...)
1060  {
1061  // don't care (double add/remove)
1062  }
1063 
1064  if (m_ToolManager)
1065  {
1066  mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0);
1067  mitk::DataNode *referenceNode = m_ToolManager->GetReferenceData(0);
1068  QWidget::setEnabled(workingNode != nullptr);
1069 
1070  m_BtnApply2D->setEnabled(on);
1071  m_FeedbackNode->SetVisibility(on);
1072 
1073  if (!on)
1074  {
1076  return;
1077  }
1078 
1079  if (workingNode)
1080  {
1081  mitk::Image *segmentation = dynamic_cast<mitk::Image *>(workingNode->GetData());
1082  if (segmentation)
1083  {
1084  m_Interpolator->SetSegmentationVolume(segmentation);
1085 
1086  if (referenceNode)
1087  {
1088  mitk::Image *referenceImage = dynamic_cast<mitk::Image *>(referenceNode->GetData());
1089  m_Interpolator->SetReferenceVolume(referenceImage); // may be nullptr
1090  }
1091  }
1092  }
1093  }
1094 
1096 }
1097 
1099 {
1100  m_SurfaceInterpolator->Interpolate();
1101 }
1102 
1104 {
1105  m_Timer->start(500);
1106 }
1107 
1109 {
1110  m_Timer->stop();
1111  m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB));
1113  mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))->GetRenderWindow());
1114 }
1115 
1117 {
1118  float currentColor[3];
1119  m_InterpolatedSurfaceNode->GetColor(currentColor);
1120 
1121  if (currentColor[2] == SURFACE_COLOR_RGB[2])
1122  {
1123  m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(1.0f, 1.0f, 1.0f));
1124  }
1125  else
1126  {
1127  m_InterpolatedSurfaceNode->SetProperty("color", mitk::ColorProperty::New(SURFACE_COLOR_RGB));
1128  }
1129  m_InterpolatedSurfaceNode->Update();
1131  mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))->GetRenderWindow());
1132 }
1133 
1135 {
1136  m_3DInterpolationEnabled = on;
1137 
1138  this->CheckSupportedImageDimension();
1139  try
1140  {
1141  if (m_DataStorage.IsNotNull() && m_ToolManager && m_3DInterpolationEnabled)
1142  {
1143  mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0);
1144 
1145  if (workingNode)
1146  {
1147  bool isInterpolationResult(false);
1148  workingNode->GetBoolProperty("3DInterpolationResult", isInterpolationResult);
1150  mitk::NodePredicateProperty::New("3DInterpolationResult", mitk::BoolProperty::New(true)),
1152  mitk::DataStorage::SetOfObjects::ConstPointer interpolationResults =
1153  m_DataStorage->GetDerivations(workingNode, pred);
1154 
1155  for (unsigned int i = 0; i < interpolationResults->Size(); ++i)
1156  {
1157  mitk::DataNode::Pointer currNode = interpolationResults->at(i);
1158  if (currNode.IsNotNull())
1159  m_DataStorage->Remove(currNode);
1160  }
1161 
1162  if ((workingNode->IsVisible(
1164  !isInterpolationResult && m_3DInterpolationEnabled)
1165  {
1166  int ret = QMessageBox::Yes;
1167 
1168  if (m_SurfaceInterpolator->EstimatePortionOfNeededMemory() > 0.5)
1169  {
1170  QMessageBox msgBox;
1171  msgBox.setText("Due to short handed system memory the 3D interpolation may be very slow!");
1172  msgBox.setInformativeText("Are you sure you want to activate the 3D interpolation?");
1173  msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
1174  ret = msgBox.exec();
1175  }
1176 
1177  if (m_Watcher.isRunning())
1178  m_Watcher.waitForFinished();
1179 
1180  if (ret == QMessageBox::Yes)
1181  {
1182  m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation);
1183  m_Watcher.setFuture(m_Future);
1184  }
1185  else
1186  {
1187  m_CmbInterpolation->setCurrentIndex(0);
1188  }
1189  }
1190  else if (!m_3DInterpolationEnabled)
1191  {
1192  this->Show3DInterpolationResult(false);
1193  m_BtnApply3D->setEnabled(m_3DInterpolationEnabled);
1194  m_BtnSuggestPlane->setEnabled(m_3DInterpolationEnabled);
1195  }
1196  }
1197  else
1198  {
1199  QWidget::setEnabled(false);
1200  m_ChkShowPositionNodes->setEnabled(m_3DInterpolationEnabled);
1201  }
1202  }
1203  if (!m_3DInterpolationEnabled)
1204  {
1205  this->Show3DInterpolationResult(false);
1206  m_BtnApply3D->setEnabled(m_3DInterpolationEnabled);
1207  m_BtnSuggestPlane->setEnabled(m_3DInterpolationEnabled);
1208  }
1209  }
1210  catch (...)
1211  {
1212  MITK_ERROR << "Error with 3D surface interpolation!";
1213  }
1215 }
1216 
1218 {
1219  // only to be called from the outside world
1220  // just a redirection to OnInterpolationActivated
1222 }
1223 
1225 {
1226  // only to be called from the outside world
1227  // just a redirection to OnInterpolationActivated
1229 }
1230 
1232 {
1234 }
1235 
1236 void QmitkSlicesInterpolator::OnInterpolationInfoChanged(const itk::EventObject & /*e*/)
1237 {
1238  // something (e.g. undo) changed the interpolation info, we should refresh our display
1240 }
1241 
1243 {
1244  if (m_3DInterpolationEnabled)
1245  {
1246  if (m_Watcher.isRunning())
1247  m_Watcher.waitForFinished();
1248  m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation);
1249  m_Watcher.setFuture(m_Future);
1250  }
1251 }
1252 
1254 {
1255  // New ContourList = hide current interpolation
1257 
1258  if (m_DataStorage.IsNotNull() && m_ToolManager && m_LastSNC)
1259  {
1260  mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0);
1261 
1262  if (workingNode)
1263  {
1264  bool isInterpolationResult(false);
1265  workingNode->GetBoolProperty("3DInterpolationResult", isInterpolationResult);
1266 
1267  if (!isInterpolationResult)
1268  {
1269  QWidget::setEnabled(true);
1270 
1271  const auto timePoint = m_LastSNC->GetSelectedTimePoint();
1272  // In case the time is not valid use 0 to access the time geometry of the working node
1273  unsigned int time_position = 0;
1274  if (!workingNode->GetData()->GetTimeGeometry()->IsValidTimePoint(timePoint))
1275  {
1276  MITK_WARN << "Cannot accept interpolation. Time point selected by SliceNavigationController is not within the time bounds of WorkingImage. Time point: " << timePoint;
1277  return;
1278  }
1279  time_position = workingNode->GetData()->GetTimeGeometry()->TimePointToTimeStep(timePoint);
1280 
1281  mitk::Vector3D spacing = workingNode->GetData()->GetGeometry(time_position)->GetSpacing();
1282  double minSpacing(100);
1283  double maxSpacing(0);
1284  for (int i = 0; i < 3; i++)
1285  {
1286  if (spacing[i] < minSpacing)
1287  {
1288  minSpacing = spacing[i];
1289  }
1290  if (spacing[i] > maxSpacing)
1291  {
1292  maxSpacing = spacing[i];
1293  }
1294  }
1295 
1296  m_SurfaceInterpolator->SetMaxSpacing(maxSpacing);
1297  m_SurfaceInterpolator->SetMinSpacing(minSpacing);
1298  m_SurfaceInterpolator->SetDistanceImageVolume(50000);
1299 
1300  mitk::Image *segmentationImage = dynamic_cast<mitk::Image *>(workingNode->GetData());
1301 
1302  m_SurfaceInterpolator->SetCurrentInterpolationSession(segmentationImage);
1303  m_SurfaceInterpolator->SetCurrentTimePoint(timePoint);
1304 
1305  if (m_3DInterpolationEnabled)
1306  {
1307  if (m_Watcher.isRunning())
1308  m_Watcher.waitForFinished();
1309  m_Future = QtConcurrent::run(this, &QmitkSlicesInterpolator::Run3DInterpolation);
1310  m_Watcher.setFuture(m_Future);
1311  }
1312  }
1313  }
1314  else
1315  {
1316  QWidget::setEnabled(false);
1317  }
1318  }
1319 }
1320 
1322 {
1323  if (m_InterpolatedSurfaceNode.IsNotNull())
1324  m_InterpolatedSurfaceNode->SetVisibility(status);
1325 
1326  if (m_3DContourNode.IsNotNull())
1327  m_3DContourNode->SetVisibility(
1329 
1331 }
1332 
1333 void QmitkSlicesInterpolator::CheckSupportedImageDimension()
1334 {
1335  if (m_ToolManager->GetWorkingData(0))
1336  m_Segmentation = dynamic_cast<mitk::Image *>(m_ToolManager->GetWorkingData(0)->GetData());
1337 
1338  /*if (m_3DInterpolationEnabled && m_Segmentation && m_Segmentation->GetDimension() != 3)
1339  {
1340  QMessageBox info;
1341  info.setWindowTitle("3D Interpolation Process");
1342  info.setIcon(QMessageBox::Information);
1343  info.setText("3D Interpolation is only supported for 3D images at the moment!");
1344  info.exec();
1345  m_CmbInterpolation->setCurrentIndex(0);
1346  }*/
1347 }
1348 
1350  const itk::EventObject & /*e*/)
1351 {
1352  // Don't know how to avoid const_cast here?!
1354  dynamic_cast<mitk::SliceNavigationController *>(const_cast<itk::Object *>(sender));
1355  if (slicer)
1356  {
1357  m_ControllerToTimeObserverTag.remove(slicer);
1358  m_ControllerToSliceObserverTag.remove(slicer);
1359  m_ControllerToDeleteObserverTag.remove(slicer);
1360  }
1361 }
1362 
1363 void QmitkSlicesInterpolator::WaitForFutures()
1364 {
1365  if (m_Watcher.isRunning())
1366  {
1367  m_Watcher.waitForFinished();
1368  }
1369 
1370  if (m_PlaneWatcher.isRunning())
1371  {
1372  m_PlaneWatcher.waitForFinished();
1373  }
1374 }
1375 
1376 void QmitkSlicesInterpolator::NodeRemoved(const mitk::DataNode* node)
1377 {
1378  if ((m_ToolManager && m_ToolManager->GetWorkingData(0) == node) ||
1379  node == m_3DContourNode ||
1380  node == m_FeedbackNode ||
1381  node == m_InterpolatedSurfaceNode)
1382  {
1383  WaitForFutures();
1384  }
1385 }
QmitkSlicesInterpolator(QWidget *parent=nullptr, const char *name=nullptr)
void Progress(unsigned int steps=1)
Sets the current amount of progress to current progress + steps.
void ReinitializeInterpolation(mitk::Surface::Pointer contours)
Reinitializes the interpolation using the provided contour data.
Operation, that holds information about some image difference.
Class for storing surfaces (vtkPolyData).
Definition: mitkSurface.h:28
void OnAcceptAllPopupActivated(QAction *action)
void IndexToWorld(const mitk::Vector3D &vec_units, mitk::Vector3D &vec_mm) const
Convert (continuous or discrete) index coordinates of a vector vec_units to world coordinates (in mm)...
Data management class that handles &#39;was created by&#39; relations.
static Pointer New()
const std::map< QAction *, mitk::SliceNavigationController * > createActionToSliceDimension()
void OnInterpolationMethodChanged(int index)
static BaseRenderer * GetInstance(vtkRenderWindow *renWin)
static vtkRenderWindow * GetRenderWindowByName(const std::string &name)
static Pointer New()
const mitk::PixelType GetPixelType(int n=0) const
Returns the PixelType of channel n.
Definition: mitkImage.cpp:101
float SURFACE_COLOR_RGB[3]
#define MITK_ERROR
Definition: mitkLogMacros.h:20
void Initialize(mitk::ToolManager *toolManager, const QList< mitk::SliceNavigationController *> &controllers)
static Pointer New()
void OnSliceChanged(itk::Object *sender, const itk::EventObject &)
void OnInterpolationInfoChanged(const itk::EventObject &)
DataCollection - Class to facilitate loading/accessing structured data.
static Pointer New()
virtual vtkImageData * GetVtkImageData(int t=0, int n=0)
Get a volume at a specific time t of channel n as a vtkImageData.
Definition: mitkImage.cpp:217
Pointer Clone() const
void * GetData()
Gives full data access.
Constants for most interaction classes, due to the generic StateMachines.
bool GetBoolProperty(const char *propertyKey, bool &boolValue, const mitk::BaseRenderer *renderer=nullptr) const
Convenience access method for bool properties (instances of BoolProperty)
static ProgressBar * GetInstance()
static method to get the GUI dependent ProgressBar-instance so the methods for steps to do and progre...
Controls the selection of the slice the associated BaseRenderer will display.
virtual bool IsValidTimePoint(TimePointType timePoint) const =0
Tests if a given time point is covered by this object.
virtual mitk::PlaneGeometry * GetPlaneGeometry(int s) const
Returns the PlaneGeometry of the slice (s).
void SignalShowMarkerNodes(bool)
void Interpolate(mitk::PlaneGeometry *plane, mitk::TimePointType timePoint, mitk::SliceNavigationController *slicer)
vcl_size_t GetBpe() const
Get the number of bits per element (of an element)
virtual bool SetVolume(const void *data, int t=0, int n=0)
Set data as volume at time t in channel n. It is in the responsibility of the caller to ensure that t...
Definition: mitkImage.cpp:669
static Pointer New()
void AcceptAllInterpolations(mitk::SliceNavigationController *slicer)
The LevelWindow class Class to store level/window values.
static Pointer New()
int GetComponentType() const
Get the component type (the scalar (!) type). Each element may contain m_NumberOfComponents (more tha...
const mitk::TimeGeometry * GetTimeGeometry() const
Return the TimeGeometry of the data as const pointer.
Definition: mitkBaseData.h:66
virtual void SendSlice()
Send the currently selected slice to the connected observers (renderers)
virtual BaseGeometry::Pointer GetGeometryForTimePoint(TimePointType timePoint) const =0
Returns the geometry of a specific time point.
void SetUseDistances(bool)
If true, the three clusters with the biggest mean distances are used for plane proposal Required the ...
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
void FinishInterpolation(mitk::SliceNavigationController *slicer=nullptr)
mitk::DataStorage * GetDataStorage()
bool IsVisible(const mitk::BaseRenderer *renderer, const char *propertyKey="visible", bool defaultIsOn=true) const
Convenience access method for visibility properties (instances of BoolProperty). Return value is the ...
Definition: mitkDataNode.h:461
static DiffImageApplier * GetInstanceForUndo()
#define MITK_WARN
Definition: mitkLogMacros.h:19
unsigned int GetDimension() const
Get dimension of the image.
Definition: mitkImage.cpp:106
bool GetColor(float rgb[3], const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="color") const
Convenience access method for color properties (instances of ColorProperty)
static Pointer New()
An object of this class represents an exception of MITK. Please don&#39;t instantiate exceptions manually...
Definition: mitkException.h:45
static RenderingManager * GetInstance()
virtual TimeStepType TimePointToTimeStep(TimePointType timePoint) const =0
Converts a time point to the corresponding time step.
void CreatePlaneInfo()
Creates the actual plane proposal.
Image class for storing images.
Definition: mitkImage.h:72
const mitk::PlaneGeometry * GetCurrentPlaneGeometry()
Returns the currently selected Plane in the current BaseGeometry (if existent).
SlicedGeometry3D * GetSlicedGeometry(unsigned int t=0) const
Convenience access method for the geometry, which is of type SlicedGeometry3D (or a sub-class of it)...
bool TranslateAndInterpolateChangedSlice(const itk::EventObject &e, mitk::SliceNavigationController *slicer)
std::map< QAction *, mitk::SliceNavigationController * > ACTION_TO_SLICEDIMENSION
mitk::ScalarType TimePointType
void OnTimeChanged(itk::Object *sender, const itk::EventObject &)
TimePointType GetSelectedTimePoint() const
Convenience method that returns the time point that corresponds to the selected time step...
static Pointer New()
static Pointer New(const char *_arg)
void SetSliceNavigationController(itk::SmartPointer< mitk::SliceNavigationController > &snc)
void WorldToIndex(const mitk::Point3D &pt_mm, mitk::Point3D &pt_units) const
Convert world coordinates (in mm) of a point to (continuous!) index coordinates.
Describes the geometry of a data object consisting of slices.
void ExecuteOperation(Operation *operation) override
static Pointer New()
static Pointer New(const char *_arg)
virtual void Remove(const DataNode *node)=0
Removes node from the DataStorage.
void RequestUpdate(vtkRenderWindow *renderWindow)
void SetDataStorage(mitk::DataStorage::Pointer storage)
void AddStepsToDo(unsigned int steps)
Adds steps to totalSteps.
The PlaneProposer creates a new plane based on an input point cloud.
static Pointer New()
const mitk::Vector3D GetSpacing() const
Get the spacing (size of a pixel).
void OnSurfaceInterpolationInfoChanged(const itk::EventObject &)
static SurfaceInterpolationController * GetInstance()
virtual BaseGeometry::Pointer GetGeometryForTimeStep(TimeStepType timeStep) const =0
Returns the geometry which corresponds to the given time step.
virtual bool SetOperationEvent(UndoStackItem *stackItem)=0
static UndoModel * GetCurrentUndoModel()
gives access to the currently used UndoModel Introduced to access special functions of more specific ...
ImageWriteAccessor class to get locked write-access for a particular image part.
Describes a two-dimensional, rectangular plane.
static void IncCurrObjectEventId()
Increases the current ObjectEventId For example if a button click generates operations the ObjectEven...
void Show3DInterpolationResult(bool)
Set the visibility of the 3d interpolation.
ImageDescriptor::Pointer GetImageDescriptor() const
Definition: mitkImage.h:528
BaseRenderer * GetRenderer() const
Gets the BaseRenderer associated with this SNC (if any). While the BaseRenderer is not directly used ...
ImageReadAccessor class to get locked read access for a particular image part.
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
Definition: mitkBaseData.h:143
static void IncCurrGroupEventId()
Increases the current GroupEventId For example if a button click generates operations the GroupEventI...
static Pointer New()
void OnSliceNavigationControllerDeleted(const itk::Object *sender, const itk::EventObject &)
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
Represents a pair of operations: undo and the according redo.
const void * GetData() const
Gives const access to the data.
void SetUnstructuredGrids(std::vector< itk::SmartPointer< mitk::UnstructuredGrid >> &grids)
Class for nodes of the DataTree.
Definition: mitkDataNode.h:57
static Pointer New()
Class for defining the data type of pixels.
Definition: mitkPixelType.h:51
bool GetName(std::string &nodeName, const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="name") const
Convenience access method for accessing the name of an object (instance of StringProperty with proper...
Definition: mitkDataNode.h:368
Manages and coordinates instances of mitk::Tool.
static bool DetermineAffectedImageSlice(const Image *image, const PlaneGeometry *plane, int &affectedDimension, int &affectedSlice)
Calculates for a given Image and PlaneGeometry, which slice of the image (in index corrdinates) is me...