15 #include <mitkLiveWireTool2D.xpm> 21 #include <type_traits> 29 :
SegTool2D(
"LiveWireTool"), m_CreateAndUseDynamicCosts(false)
38 void mitk::LiveWireTool2D::RemoveHelperObjects()
42 if (
nullptr == dataStorage)
45 for (
const auto &editingContour : m_EditingContours)
46 dataStorage->
Remove(editingContour.first);
48 for (
const auto &workingContour : m_WorkingContours)
49 dataStorage->Remove(workingContour.first);
51 if (m_EditingContourNode.IsNotNull())
52 dataStorage->Remove(m_EditingContourNode);
54 if (m_LiveWireContourNode.IsNotNull())
55 dataStorage->Remove(m_LiveWireContourNode);
57 if (m_ContourNode.IsNotNull())
58 dataStorage->Remove(m_ContourNode);
63 void mitk::LiveWireTool2D::ReleaseHelperObjects()
65 this->RemoveHelperObjects();
67 m_EditingContours.clear();
68 m_WorkingContours.clear();
70 m_EditingContourNode =
nullptr;
71 m_EditingContour =
nullptr;
73 m_LiveWireContourNode =
nullptr;
74 m_LiveWireContour =
nullptr;
76 m_ContourNode =
nullptr;
80 void mitk::LiveWireTool2D::ReleaseInteractors()
82 this->EnableContourLiveWireInteraction(
false);
83 m_LiveWireInteractors.clear();
101 return mitkLiveWireTool2D_xpm;
121 Superclass::Activated();
123 this->EnableContourLiveWireInteraction(
true);
129 Superclass::Deactivated();
132 void mitk::LiveWireTool2D::EnableContourLiveWireInteraction(
bool on)
134 for (
const auto &interactor : m_LiveWireInteractors)
135 interactor->EnableInteraction(on);
142 if (
nullptr == workingNode)
145 auto workingImage =
dynamic_cast<Image *
>(workingNode->GetData());
147 if (
nullptr == workingImage)
150 std::vector<SliceInformation> sliceInfos;
151 sliceInfos.reserve(m_WorkingContours.size());
153 for (
const auto &workingContour : m_WorkingContours)
155 auto contour =
dynamic_cast<ContourModel *
>(workingContour.first->GetData());
157 if (
nullptr == contour)
162 for (std::remove_const_t<decltype(numberOfTimeSteps)> t = 0; t < numberOfTimeSteps; ++t)
164 if (contour->IsEmptyTimeStep(t))
172 sliceInfos.emplace_back(workingSlice, workingContour.second, t);
183 this->ReleaseHelperObjects();
184 this->ReleaseInteractors();
193 if (!isPositionEventInsideImageRegion)
194 MITK_WARN(
"LiveWireTool2D") <<
"PositionEvent is outside ImageRegion!";
196 return isPositionEventInsideImageRegion;
203 if (
nullptr == positionEvent)
208 if (!IsPositionEventInsideImageRegion(positionEvent, workingDataNode->GetData()))
220 m_Contour->Expand(t + 1);
222 m_ContourNode->SetData(m_Contour);
223 m_ContourNode->SetName(
"working contour node");
227 m_ContourNode->AddProperty(
"contour.color",
ColorProperty::New(1.0f, 1.0f, 0.0f),
nullptr,
true);
228 m_ContourNode->AddProperty(
"contour.points.color",
ColorProperty::New(1.0f, 0.0f, 0.1f),
nullptr,
true);
229 m_ContourNode->AddProperty(
"contour.controlpoints.show",
BoolProperty::New(
true),
nullptr,
true);
232 m_LiveWireContour->Expand(t + 1);
234 m_LiveWireContourNode->SetData(m_LiveWireContour);
235 m_LiveWireContourNode->SetName(
"active livewire node");
239 m_LiveWireContourNode->AddProperty(
"contour.color",
ColorProperty::New(0.1f, 1.0f, 0.1f),
nullptr,
true);
243 m_EditingContour->Expand(t + 1);
245 m_EditingContourNode->SetData(m_EditingContour);
246 m_EditingContourNode->SetName(
"editing node");
250 m_EditingContourNode->AddProperty(
"contour.color",
ColorProperty::New(0.1f, 1.0f, 0.1f),
nullptr,
true);
251 m_EditingContourNode->AddProperty(
"contour.points.color",
ColorProperty::New(0.0f, 0.0f, 1.0f),
nullptr,
true);
255 dataStorage->
Add(m_ContourNode, workingDataNode);
256 dataStorage->Add(m_LiveWireContourNode, workingDataNode);
257 dataStorage->Add(m_EditingContourNode, workingDataNode);
262 auto origin = m_WorkingSlice->GetSlicedGeometry()->GetOrigin();
263 m_WorkingSlice->GetSlicedGeometry()->WorldToIndex(origin, origin);
264 m_WorkingSlice->GetSlicedGeometry()->IndexToWorld(origin, origin);
265 m_WorkingSlice->GetSlicedGeometry()->SetOrigin(origin);
268 m_LiveWireFilter->SetInput(m_WorkingSlice);
273 m_WorkingSlice->GetGeometry()->WorldToIndex(click, idx);
279 click[0] = indexWithHighestGradient[0];
280 click[1] = indexWithHighestGradient[1];
281 click[2] = indexWithHighestGradient[2];
282 m_WorkingSlice->GetGeometry()->IndexToWorld(click, click);
285 m_Contour->AddVertex(click,
true, t);
286 m_LiveWireFilter->SetStartPoint(click);
291 m_CreateAndUseDynamicCosts =
true;
303 if (
nullptr == positionEvent)
306 if (m_PlaneGeometry.IsNotNull())
316 std::for_each(m_LiveWireContour->IteratorBegin(), m_LiveWireContour->IteratorEnd(), [
this](
ContourElement::VertexType *vertex) {
317 ImageLiveWireContourModelFilter::InternalImageType::IndexType idx;
318 this->m_WorkingSlice->GetGeometry()->WorldToIndex(vertex->Coordinates, idx);
319 this->m_LiveWireFilter->AddRepulsivePoint(idx);
323 m_LiveWireContour->RemoveVertexAt(0, t);
326 m_LiveWireContour->SetControlVertexAt(m_LiveWireContour->GetNumberOfVertices(t) - 1, t);
329 m_Contour->Concatenate(m_LiveWireContour, t);
332 m_LiveWireContour->Clear(t);
337 if (m_CreateAndUseDynamicCosts)
340 m_LiveWireFilter->CreateDynamicCostMap(m_Contour);
341 m_LiveWireFilter->SetUseDynamicCostMap(
true);
353 if (
nullptr == positionEvent)
359 m_LiveWireFilter->SetTimeStep(t);
360 m_LiveWireFilter->Update();
362 m_LiveWireContour = this->m_LiveWireFilter->GetOutput();
363 m_LiveWireContourNode->SetData(this->m_LiveWireContour);
370 m_LiveWireFilter->SetUseDynamicCostMap(
false);
371 this->OnMouseMoved(
nullptr, interactionEvent);
372 m_LiveWireFilter->SetUseDynamicCostMap(
true);
375 bool mitk::LiveWireTool2D::OnCheckPoint(
const InteractionEvent *interactionEvent)
381 if (
nullptr == positionEvent)
387 mitk::Point3D first = this->m_Contour->GetVertexAt(0, t)->Coordinates;
389 return first.EuclideanDistanceTo(click) < 4.5;
398 if (
nullptr == positionEvent)
407 m_Contour->RemoveVertexAt(m_Contour->GetNumberOfVertices(t) - 1, t);
413 m_LiveWireFilter->SetUseDynamicCostMap(
false);
418 void mitk::LiveWireTool2D::FinishTool()
420 auto numberOfTimesteps =
static_cast<int>(m_Contour->GetTimeGeometry()->CountTimeSteps());
422 for (
int i = 0; i <= numberOfTimesteps; ++i)
427 m_LiveWireContourNode =
nullptr;
428 m_LiveWireContour =
nullptr;
431 m_ContourInteractor->SetDataNode(m_ContourNode);
432 m_ContourInteractor->LoadStateMachine(
"ContourModelModificationInteractor.xml",
us::GetModuleContext()->GetModule());
433 m_ContourInteractor->SetEventConfig(
"ContourModelModificationConfig.xml",
us::GetModuleContext()->GetModule());
434 m_ContourInteractor->SetWorkingImage(this->m_WorkingSlice);
435 m_ContourInteractor->SetEditingContourModelNode(this->m_EditingContourNode);
437 m_ContourNode->SetDataInteractor(m_ContourInteractor.GetPointer());
439 this->m_LiveWireInteractors.push_back(m_ContourInteractor);
447 if (m_Contour->GetNumberOfVertices(t) <= 1)
451 dataStorage->
Remove(m_LiveWireContourNode);
452 dataStorage->Remove(m_ContourNode);
453 dataStorage->Remove(m_EditingContourNode);
456 m_LiveWireContourNode->SetData(m_LiveWireContour);
459 m_ContourNode->SetData(m_Contour);
466 m_LiveWireContourNode->SetData(m_LiveWireContour);
469 newContour->Expand(m_Contour->GetTimeSteps());
471 auto begin = m_Contour->IteratorBegin();
474 auto newLast = m_Contour->IteratorBegin() + (m_Contour->GetNumberOfVertices() - 1);
477 if (newLast != begin)
481 while (newLast != begin && !((*newLast)->IsControlPoint))
485 m_LiveWireFilter->SetStartPoint((*newLast)->Coordinates);
487 auto it = m_Contour->IteratorBegin();
490 while (it <= newLast)
492 newContour->AddVertex((*it)->Coordinates, (*it)->IsControlPoint, t);
496 newContour->SetClosed(m_Contour->IsClosed());
498 m_ContourNode->SetData(newContour);
499 m_Contour = newContour;
505 template <
typename TPixel,
unsigned int VImageDimension>
506 void mitk::LiveWireTool2D::FindHighestGradientMagnitudeByITK(itk::Image<TPixel, VImageDimension> *inputImage,
511 typedef typename InputImageType::IndexType IndexType;
514 const auto MAX_Y = inputImage->GetLargestPossibleRegion().GetSize()[1];
516 returnIndex[0] = index[0];
517 returnIndex[1] = index[1];
518 returnIndex[2] = 0.0;
520 double gradientMagnitude = 0.0;
521 double maxGradientMagnitude = 0.0;
527 typename InputImageType::SizeType size;
532 IndexType startRegion;
533 startRegion[0] = index[0] - 3;
534 startRegion[1] = index[1] - 3;
535 if (startRegion[0] < 0)
537 if (startRegion[1] < 0)
539 if (MAX_X - index[0] < 7)
540 startRegion[0] = MAX_X - 7;
541 if (MAX_Y - index[1] < 7)
542 startRegion[1] = MAX_Y - 7;
544 index[0] = startRegion[0] + 3;
545 index[1] = startRegion[1] + 3;
547 typename InputImageType::RegionType region;
548 region.SetSize(size);
549 region.SetIndex(startRegion);
551 typedef typename itk::GradientMagnitudeImageFilter<InputImageType, InputImageType> GradientMagnitudeFilterType;
552 typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New();
553 gradientFilter->SetInput(inputImage);
554 gradientFilter->GetOutput()->SetRequestedRegion(region);
556 gradientFilter->Update();
557 typename InputImageType::Pointer gradientMagnitudeImage;
558 gradientMagnitudeImage = gradientFilter->GetOutput();
560 IndexType currentIndex;
565 for (
int x = -1; x <= 1; ++x)
567 currentIndex[0] = index[0] + x;
569 for (
int y = -1; y <= 1; ++y)
571 currentIndex[1] = index[1] + y;
572 gradientMagnitude = gradientMagnitudeImage->GetPixel(currentIndex);
575 if (maxGradientMagnitude < gradientMagnitude)
577 maxGradientMagnitude = gradientMagnitude;
578 returnIndex[0] = currentIndex[0];
579 returnIndex[1] = currentIndex[1];
580 returnIndex[2] = 0.0;
584 currentIndex[1] = index[1];
ContourModel is a structure of linked vertices defining a contour in 3D space. The vertices are store...
Super class for all position events.
virtual unsigned int GetSlice() const
Base of all data objects.
static void FillContourInSlice(ContourModel *projectedContour, Image *sliceImage, mitk::Image::Pointer workingImage, int paintingPixelValue=1)
Fill a contour in a 2D slice with a specified pixel value at time step 0.
bool IsInside(const mitk::Point3D &p) const
Test whether the point p (world coordinates in mm) is inside the bounding box.
Point3D GetPositionInWorld() const
::mitk::Image InputImageType
#define MITKSEGMENTATION_EXPORT
DataCollection - Class to facilitate loading/accessing structured data.
virtual const PlaneGeometry * GetCurrentWorldPlaneGeometry()
Get the current 2D-worldgeometry (m_CurrentWorldPlaneGeometry) used for 2D-rendering.
virtual void Add(DataNode *node, const DataStorage::SetOfObjects *parents=nullptr)=0
Adds a DataNode containing a data object to its internal storage.
BaseRenderer * GetSender() const
MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, LiveWireTool2D, "LiveWire tool")
#define AccessFixedDimensionByItk_2(mitkImage, itkImageTypeFunction, dimension, arg1, arg2)
static RenderingManager * GetInstance()
Represents an action, that is executed after a certain event (in statemachine-mechanism) TODO: implem...
virtual unsigned int GetTimeStep() const
Module * GetModule() const
Image class for storing images.
static ContourModel::Pointer ProjectContourTo2DSlice(Image *slice, ContourModel *contourIn3D, bool correctionForIpSegmentation, bool constrainToInside)
Projects a contour onto an image point by point. Converts from world to index coordinates.
void ResetToStartState()
ResetToStartState Reset state machine to it initial starting state.
virtual void Remove(const DataNode *node)=0
Removes node from the DataStorage.
void RequestUpdate(vtkRenderWindow *renderWindow)
vtkRenderWindow * GetRenderWindow() const
Access the RenderWindow into which this renderer renders.
MITKCORE_EXPORT const ScalarType sqrteps
#define CONNECT_CONDITION(a, f)
const RegionType & GetLargestPossibleRegion() const
unsigned int GetTimeSteps() const
Get the number of time steps from the TimeGeometry As the base data has not a data vector given by it...
#define CONNECT_FUNCTION(a, f)
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
Represents a single vertex of contour.
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)