diff --git a/Core/Code/Resources/Interactions/Legacy/StateMachine.xml b/Core/Code/Resources/Interactions/Legacy/StateMachine.xml
index 9e12e74455..009f3b95b2 100644
--- a/Core/Code/Resources/Interactions/Legacy/StateMachine.xml
+++ b/Core/Code/Resources/Interactions/Legacy/StateMachine.xml
@@ -1,4086 +1,4107 @@
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx
index 7cdb6d05d9..6f26dfeb9e 100644
--- a/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx
+++ b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx
@@ -1,440 +1,440 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#ifndef __itkShortestPathCostFunctionLiveWire_txx
#define __itkShortestPathCostFunctionLiveWire_txx
#include "itkShortestPathCostFunctionLiveWire.h"
#include
#include
#include
#include
#include
#include
#include
#include
namespace itk
{
// Constructor
template
ShortestPathCostFunctionLiveWire
::ShortestPathCostFunctionLiveWire()
{
m_UseRepulsivePoints = false;
m_GradientMax = 0.0;
m_Initialized = false;
m_UseCostMap = false;
m_MaxMapCosts = -1.0;
}
template
void ShortestPathCostFunctionLiveWire
::AddRepulsivePoint( const IndexType& index )
{
- m_MaskImage->SetPixel(index, 255);
+ this->m_MaskImage->SetPixel(index, 255);
m_UseRepulsivePoints = true;
}
template
void ShortestPathCostFunctionLiveWire
::RemoveRepulsivePoint( const IndexType& index )
{
this->m_MaskImage->SetPixel(index, 0);
}
template
void ShortestPathCostFunctionLiveWire
::SetImage(const TInputImageType* _arg)
{
if (this->m_Image != _arg)
{
this->m_Image = _arg;
// initialize mask image
- m_MaskImage = UnsignedCharImageType::New();
- m_MaskImage->SetRegions(this->m_Image->GetLargestPossibleRegion());
- m_MaskImage->SetOrigin( this->m_Image->GetOrigin() );
- m_MaskImage->SetSpacing( this->m_Image->GetSpacing() );
- m_MaskImage->SetDirection( this->m_Image->GetDirection() );
- m_MaskImage->Allocate ();
- m_MaskImage->FillBuffer(0);
+ this->m_MaskImage = UnsignedCharImageType::New();
+ this->m_MaskImage->SetRegions( this->m_Image->GetLargestPossibleRegion());
+ this->m_MaskImage->SetOrigin( this->m_Image->GetOrigin() );
+ this->m_MaskImage->SetSpacing( this->m_Image->GetSpacing() );
+ this->m_MaskImage->SetDirection( this->m_Image->GetDirection() );
+ this->m_MaskImage->Allocate ();
+ this->m_MaskImage->FillBuffer(0);
this->Modified();
this->m_Initialized = false;
}
}
template
void ShortestPathCostFunctionLiveWire
::ClearRepulsivePoints()
{
m_UseRepulsivePoints = false;
- m_MaskImage->FillBuffer(0);
+ this->m_MaskImage->FillBuffer(0);
}
template
double ShortestPathCostFunctionLiveWire
::GetCost(IndexType p1 ,IndexType p2)
{
// local component costs
// weights
double w1;
double w2;
double w3;
double costs = 0.0;
// if we are on the mask, return asap
if (m_UseRepulsivePoints)
{
if ( (this->m_MaskImage->GetPixel(p1) != 0) ||
(this->m_MaskImage->GetPixel(p2) != 0) )
return 1000;
}
unsigned long xMAX = this->m_Image->GetLargestPossibleRegion().GetSize()[0];
unsigned long yMAX = this->m_Image->GetLargestPossibleRegion().GetSize()[1];
double gradientX, gradientY;
gradientX = gradientY = 0.0;
double gradientCost;
double gradientMagnitude;
// Gradient Magnitude costs
gradientMagnitude = this->m_GradientMagnitudeImage->GetPixel(p2);
gradientX = m_GradientImage->GetPixel(p2)[0];
gradientY = m_GradientImage->GetPixel(p2)[1];
if(m_UseCostMap && !m_CostMap.empty())
{
std::map< int, int >::iterator end = m_CostMap.end();
std::map< int, int >::iterator last = --(m_CostMap.end());
//current position
std::map< int, int >::iterator x;
//std::map< int, int >::key_type keyOfX = static_cast::key_type>(gradientMagnitude * 1000);
int keyOfX = static_cast(gradientMagnitude /* ShortestPathCostFunctionLiveWire::MAPSCALEFACTOR*/);
x = m_CostMap.find( keyOfX );
std::map< int, int >::iterator left2;
std::map< int, int >::iterator left1;
std::map< int, int >::iterator right1;
std::map< int, int >::iterator right2;
if( x == end )
{//x can also be == end if the key is not in the map but between two other keys
//search next key within map from x upwards
right1 = m_CostMap.lower_bound( keyOfX );
}
else
{
right1 = x;
}
if(right1 == end || right1 == last )
{
right2 = end;
}
else//( right1 != (end-1) )
{
std::map< int, int >::iterator temp = right1;
right2 = ++right1;//rght1 + 1
right1 = temp;
}
if( right1 == m_CostMap.begin() )
{
left1 = end;
left2 = end;
}
else if( right1 == (++(m_CostMap.begin())) )
{
std::map< int, int >::iterator temp = right1;
left1 = --right1;//rght1 - 1
right1 = temp;
left2 = end;
}
else
{
std::map< int, int >::iterator temp = right1;
left1 = --right1;//rght1 - 1
left2 = --right1;//rght1 - 2
right1 = temp;
}
double partRight1, partRight2, partLeft1, partLeft2;
partRight1 = partRight2 = partLeft1 = partLeft2 = 0.0;
/*
f(x) = v(bin) * e^ ( -1/2 * (|x-k(bin)| / sigma)^2 )
gaussian approximation
where
v(bin) is the value in the map
k(bin) is the key
*/
if( left2 != end )
{
partLeft2 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, left2->first, left2->second);
}
if( left1 != end )
{
partLeft1 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, left1->first, left1->second);
}
if( right1 != end )
{
partRight1 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, right1->first, right1->second);
}
if( right2 != end )
{
partRight2 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, right2->first, right2->second);
}
if( m_MaxMapCosts > 0.0 )
{
gradientCost = 1.0 - ( (partRight1 + partRight2 + partLeft1 + partLeft2) / m_MaxMapCosts );
}
else
{//use linear mapping
gradientCost = 1.0 - (gradientMagnitude / m_GradientMax);
}
}
else
{//use linear mapping
//value between 0 (good) and 1 (bad)
gradientCost = 1.0 - (gradientMagnitude / m_GradientMax);
}
// Laplacian zero crossing costs
// f(p) = 0; if I(p)=0
// or 1; if I(p)!=0
double laplacianCost;
typename Superclass::PixelType laplaceImageValue;
laplaceImageValue = m_EdgeImage->GetPixel(p2);
if(laplaceImageValue < 0 || laplaceImageValue > 0)
{
laplacianCost = 1.0;
}
else
{
laplacianCost = 0.0;
}
// Gradient direction costs
//vector q-p i.e. p2-p1
double vQP[2];
vQP[0] = p2[0] - p1[0];
vQP[1] = p2[1] - p1[1];
//-------
//vector p-q i.e. p1-p2
double vPQ[2];
vPQ[0] = p1[0] - p2[0];
vPQ[1] = p1[1] - p2[1];
//-------
// gradient vector at p1
double nGradientAtP1[2];
nGradientAtP1[0] = gradientX;//previously computed for gradient magnitude
nGradientAtP1[1] = gradientY;
//gradient direction unit vector of p1
nGradientAtP1[0] /= gradientMagnitude;
nGradientAtP1[1] /= gradientMagnitude;
//-------
// gradient vector at p1
double nGradientAtP2[2];
nGradientAtP2[0] = m_GradientImage->GetPixel(p2)[0];
nGradientAtP2[1] = m_GradientImage->GetPixel(p2)[1];
nGradientAtP2[0] /= m_GradientMagnitudeImage->GetPixel(p2);
nGradientAtP2[1] /= m_GradientMagnitudeImage->GetPixel(p2);
double scalarProduct = (nGradientAtP1[0] * nGradientAtP2[0]) + (nGradientAtP1[1] * nGradientAtP2[1]);
if( abs(scalarProduct) >= 1.0)
{
//this should probably not happen; make sure the input for acos is valid
scalarProduct = 0.999999999;
}
double gradientDirectionCost = acos( scalarProduct ) / 3.14159265;
if (this->m_UseCostMap)
{
w1 = 0.43;
w2= 0.43;
w3 = 0.14;
}else{
w1 = 0.10;
w2= 0.85;
w3 = 0.05;
}
costs = w1 * laplacianCost + w2 * gradientCost + w3 * gradientDirectionCost;
//scale by euclidian distance
double costScale;
if( p1[0] == p2[0] || p1[1] == p2[1])
{
//horizontal or vertical neighbor
costScale = 1.0;
}
else
{
//diagonal neighbor
costScale = sqrt(2.0);
}
costs *= costScale;
return costs;
}
template
double ShortestPathCostFunctionLiveWire
::GetMinCost()
{
return minCosts;
}
template
void ShortestPathCostFunctionLiveWire
::Initialize()
{
if(!m_Initialized)
{
typedef itk::CastImageFilter< TInputImageType, FloatImageType > CastFilterType;
typename CastFilterType::Pointer castFilter = CastFilterType::New();
castFilter->SetInput(this->m_Image);
// init gradient magnitude image
typedef itk::GradientMagnitudeImageFilter< FloatImageType, FloatImageType> GradientMagnitudeFilterType;
typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New();
gradientFilter->SetInput(castFilter->GetOutput());
//gradientFilter->SetNumberOfThreads(4);
//gradientFilter->GetOutput()->SetRequestedRegion(m_RequestedRegion);
gradientFilter->Update();
this->m_GradientMagnitudeImage = gradientFilter->GetOutput();
typedef itk::StatisticsImageFilter StatisticsImageFilterType;
typename StatisticsImageFilterType::Pointer statisticsImageFilter = StatisticsImageFilterType::New();
statisticsImageFilter->SetInput(this->m_GradientMagnitudeImage);
statisticsImageFilter->Update();
m_GradientMax = statisticsImageFilter->GetMaximum();
typedef itk::GradientImageFilter< FloatImageType > GradientFilterType;
typename GradientFilterType::Pointer filter = GradientFilterType::New();
//sigma is specified in millimeters
//filter->SetSigma( 1.5 );
filter->SetInput(castFilter->GetOutput());
filter->Update();
m_GradientImage = filter->GetOutput();
// init zero crossings
//typedef itk::ZeroCrossingImageFilter< TInputImageType, UnsignedCharImageType > ZeroCrossingImageFilterType;
//ZeroCrossingImageFilterType::Pointer zeroCrossingImageFilter = ZeroCrossingImageFilterType::New();
//zeroCrossingImageFilter->SetInput(this->m_Image);
//zeroCrossingImageFilter->SetBackgroundValue(1);
//zeroCrossingImageFilter->SetForegroundValue(0);
//zeroCrossingImageFilter->SetNumberOfThreads(4);
//zeroCrossingImageFilter->Update();
//m_EdgeImage = zeroCrossingImageFilter->GetOutput();
//cast image to float to apply canny edge dection filter
/*typedef itk::CastImageFilter< TInputImageType, FloatImageType > CastFilterType;
CastFilterType::Pointer castFilter = CastFilterType::New();
castFilter->SetInput(this->m_Image);*/
//typedef itk::LaplacianImageFilter filterType;
//filterType::Pointer laplacianFilter = filterType::New();
//laplacianFilter->SetInput( castFilter->GetOutput() ); // NOTE: input image type must be double or float
//laplacianFilter->Update();
//m_EdgeImage = laplacianFilter->GetOutput();
//init canny edge detection
typedef itk::CannyEdgeDetectionImageFilter CannyEdgeDetectionImageFilterType;
typename CannyEdgeDetectionImageFilterType::Pointer cannyEdgeDetectionfilter = CannyEdgeDetectionImageFilterType::New();
cannyEdgeDetectionfilter->SetInput(castFilter->GetOutput());
cannyEdgeDetectionfilter->SetUpperThreshold(30);
cannyEdgeDetectionfilter->SetLowerThreshold(15);
cannyEdgeDetectionfilter->SetVariance(4);
cannyEdgeDetectionfilter->SetMaximumError(.01f);
cannyEdgeDetectionfilter->Update();
m_EdgeImage = cannyEdgeDetectionfilter->GetOutput();
// set minCosts
minCosts = 0.0; // The lower, the more thouroughly! 0 = dijkstra. If estimate costs are lower than actual costs everything is fine. If estimation is higher than actual costs, you might not get the shortest but a different path.
m_Initialized = true;
}
// check start/end point value
startValue= this->m_Image->GetPixel(this->m_StartIndex);
endValue= this->m_Image->GetPixel(this->m_EndIndex);
}
template
double ShortestPathCostFunctionLiveWire::SigmoidFunction(double I, double max, double min, double alpha, double beta)
{
// Using the SIgmoid formula from ITK Software Guide 6.3.2 Non Linear Mappings
double Exponent = -1 * ((I - beta) / alpha);
double Factor = 1 / (1 + exp(Exponent));
double newI = (max - min) * Factor + min;
return newI;
}
template
double ShortestPathCostFunctionLiveWire::Gaussian(double x, double xOfGaussian, double yOfGaussian)
{
return yOfGaussian * exp( -0.5 * pow( (x - xOfGaussian), 2) );
}
} // end namespace itk
#endif // __itkShortestPathCostFunctionLiveWire_txx
diff --git a/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp
index 1cbf067bf6..93407c25fc 100644
--- a/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp
+++ b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp
@@ -1,475 +1,473 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkContourModelLiveWireInteractor.h"
#include "mitkToolManager.h"
#include "mitkBaseRenderer.h"
#include "mitkRenderingManager.h"
#include
#include
#include
#include "mitkIOUtil.h"
mitk::ContourModelLiveWireInteractor::ContourModelLiveWireInteractor(DataNode* dataNode)
:ContourModelInteractor(dataNode)
{
m_LiveWireFilter = mitk::ImageLiveWireContourModelFilter::New();
m_NextActiveVertexDown.Fill(0);
m_NextActiveVertexUp.Fill(0);
}
mitk::ContourModelLiveWireInteractor::~ContourModelLiveWireInteractor()
{
}
bool mitk::ContourModelLiveWireInteractor::OnCheckPointClick( Action* action, const StateEvent* stateEvent)
{
const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
if (!positionEvent)
{
this->HandleEvent( new mitk::StateEvent(EIDNO, stateEvent->GetEvent()) );
return false;
}
mitk::StateEvent* newStateEvent = NULL;
int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep();
mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() );
assert ( contour );
contour->Deselect();
// Check distance to any vertex.
// Transition YES if click close to a vertex
mitk::Point3D click = positionEvent->GetWorldPosition();
if (contour->SelectVertexAt(click, 1.5, timestep) )
{
contour->SetSelectedVertexAsControlPoint(false);
//m_lastMousePosition = click;
m_ContourLeft = mitk::ContourModel::New();
//get coordinates of next active vertex downwards from selected vertex
int downIndex = this->SplitContourFromSelectedVertex( contour, m_ContourLeft, false, timestep);
m_NextActiveVertexDownIter = contour->IteratorBegin() + downIndex;
m_NextActiveVertexDown = (*m_NextActiveVertexDownIter)->Coordinates;
m_ContourRight = mitk::ContourModel::New();
//get coordinates of next active vertex upwards from selected vertex
int upIndex = this->SplitContourFromSelectedVertex( contour, m_ContourRight, true, timestep);
m_NextActiveVertexUpIter = contour->IteratorBegin() + upIndex;
m_NextActiveVertexUp = (*m_NextActiveVertexUpIter)->Coordinates;
// clear previous void positions
this->m_LiveWireFilter->ClearRepulsivePoints();
// set the current contour as void positions in the cost map
// start with down side
mitk::ContourModel::VertexIterator iter = contour->IteratorBegin(timestep);
for (;iter != m_NextActiveVertexDownIter; iter++)
{
itk::Index<2> idx;
this->m_WorkingSlice->GetGeometry()->WorldToIndex((*iter)->Coordinates, idx);
this->m_LiveWireFilter->AddRepulsivePoint( idx );
}
// continue with upper side
iter = m_NextActiveVertexUpIter + 1;
for (;iter != contour->IteratorEnd(timestep); iter++)
{
itk::Index<2> idx;
this->m_WorkingSlice->GetGeometry()->WorldToIndex((*iter)->Coordinates, idx);
this->m_LiveWireFilter->AddRepulsivePoint( idx );
}
// clear container with void points between neighboring control points
m_ContourBeingModified.clear();
// let us have the selected point as a control point
contour->SetSelectedVertexAsControlPoint(true);
// finally, allow to leave current state
newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent());
}
else
{
// do not allow to leave current state
newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent());
}
this->HandleEvent( newStateEvent );
assert( positionEvent->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
return true;
}
void mitk::ContourModelLiveWireInteractor::SetEditingContourModelNode (mitk::DataNode* _arg)
{
if (this->m_EditingContourNode != _arg)
{
this->m_EditingContourNode = _arg;
this->Modified();
}
}
void mitk::ContourModelLiveWireInteractor::SetWorkingImage (mitk::Image* _arg)
{
if (this->m_WorkingSlice != _arg)
{
this->m_WorkingSlice = _arg;
this->m_LiveWireFilter->SetInput(this->m_WorkingSlice);
this->Modified();
}
}
bool mitk::ContourModelLiveWireInteractor::OnDeletePoint( Action* action, const StateEvent* stateEvent)
{
int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep();
mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() );
assert ( contour );
if (contour->GetSelectedVertex())
{
mitk::ContourModel::Pointer newContour = mitk::ContourModel::New();
newContour->Expand(contour->GetTimeSteps());
newContour->Concatenate( m_ContourLeft, timestep );
//recompute contour between neighbored two active control points
this->m_LiveWireFilter->SetStartPoint( this->m_NextActiveVertexDown );
this->m_LiveWireFilter->SetEndPoint( this->m_NextActiveVertexUp );
// this->m_LiveWireFilter->ClearRepulsivePoints();
this->m_LiveWireFilter->Update();
mitk::ContourModel *liveWireContour = this->m_LiveWireFilter->GetOutput();
assert ( liveWireContour );
if ( liveWireContour->IsEmpty(timestep) )
return false;
liveWireContour->RemoveVertexAt( 0, timestep);
liveWireContour->RemoveVertexAt( liveWireContour->GetNumberOfVertices(timestep) - 1, timestep);
//insert new live wire computed points
newContour->Concatenate( liveWireContour, timestep );
// insert right side of original contour
newContour->Concatenate( this->m_ContourRight, timestep );
newContour->SetIsClosed(contour->IsClosed(timestep), timestep);
m_DataNode->SetData(newContour);
assert( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
return true;
}
return false;
}
bool mitk::ContourModelLiveWireInteractor::OnMovePoint( Action* action, const StateEvent* stateEvent)
{
const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
if (!positionEvent) return false;
int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep();
mitk::Point3D currentPosition = positionEvent->GetWorldPosition();
mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() );
assert ( contour );
+ mitk::ContourModel::Pointer editingContour = mitk::ContourModel::New();
+ editingContour->Expand(contour->GetTimeSteps());
+
// recompute left live wire, i.e. the contour between previous active vertex and selected vertex
this->m_LiveWireFilter->SetStartPoint( this->m_NextActiveVertexDown );
this->m_LiveWireFilter->SetEndPoint( currentPosition );
// remove void positions between previous active vertex and next active vertex.
if (!m_ContourBeingModified.empty())
{
std::vector< itk::Index< 2 > >::const_iterator iter = m_ContourBeingModified.begin();
for (;iter != m_ContourBeingModified.end(); iter++)
{
this->m_LiveWireFilter->RemoveRepulsivePoint( (*iter) );
}
}
// update to get the left livewire. Remember that the points in the rest of the contour are already
// set as void positions in the filter
this->m_LiveWireFilter->Update();
mitk::ContourModel::Pointer leftLiveWire = this->m_LiveWireFilter->GetOutput();
assert ( leftLiveWire );
if ( !leftLiveWire->IsEmpty(timestep) )
leftLiveWire->RemoveVertexAt(0, timestep);
+ editingContour->Concatenate( leftLiveWire, timestep );
+
+ //the new index of the selected vertex
+ unsigned int selectedVertexIndex = this->m_ContourLeft->GetNumberOfVertices(timestep) + leftLiveWire->GetNumberOfVertices(timestep) -1;
+
// at this point the container has to be empty
m_ContourBeingModified.clear();
// add points from left live wire contour
mitk::ContourModel::VertexIterator iter = leftLiveWire->IteratorBegin(timestep);
for (;iter != leftLiveWire->IteratorEnd(timestep); iter++)
{
itk::Index<2> idx;
this->m_WorkingSlice->GetGeometry()->WorldToIndex((*iter)->Coordinates, idx);
this->m_LiveWireFilter->AddRepulsivePoint( idx );
// add indices
m_ContourBeingModified.push_back(idx);
}
// recompute right live wire, i.e. the contour between selected vertex and next active vertex
this->m_LiveWireFilter->SetStartPoint( currentPosition );
this->m_LiveWireFilter->SetEndPoint( m_NextActiveVertexUp );
// update filter with all contour points set as void but the right live wire portion to be calculated now
this->m_LiveWireFilter->Update();
mitk::ContourModel::Pointer rightLiveWire = this->m_LiveWireFilter->GetOutput();
assert ( rightLiveWire );
// reject strange paths
if ( abs (rightLiveWire->GetNumberOfVertices(timestep) - leftLiveWire->GetNumberOfVertices(timestep)) > 50 )
{
return false;
}
if ( !leftLiveWire->IsEmpty(timestep) )
leftLiveWire->SetControlVertexAt(leftLiveWire->GetNumberOfVertices()-1, timestep);
if ( !rightLiveWire->IsEmpty(timestep) )
rightLiveWire->RemoveVertexAt(0, timestep);
+ editingContour->Concatenate( rightLiveWire, timestep );
+
// not really needed
/*
// add points from right live wire contour
iter = rightLiveWire->IteratorBegin(timestep);
for (;iter != rightLiveWire->IteratorEnd(timestep); iter++)
{
itk::Index<2> idx;
this->m_WorkingSlice->GetGeometry()->WorldToIndex((*iter)->Coordinates, idx);
this->m_LiveWireFilter->AddRepulsivePoint( idx );
// add indices
m_ContourBeingModified.push_back(idx);
}
*/
- mitk::ContourModel::Pointer editingContour = mitk::ContourModel::New();
- editingContour->Expand(contour->GetTimeSteps());
-
- editingContour->Concatenate( leftLiveWire, timestep );
- editingContour->Concatenate( rightLiveWire, timestep );
m_EditingContourNode->SetData(editingContour);
mitk::ContourModel::Pointer newContour = mitk::ContourModel::New();
newContour->Expand(contour->GetTimeSteps());
// concatenate left original contour
newContour->Concatenate( this->m_ContourLeft, timestep );
- newContour->Deselect();
- // concatenate left live wire but only if we have more than one vertex
- if (!leftLiveWire->IsEmpty())
- {
- newContour->Concatenate( leftLiveWire, timestep, true);
- }
+ newContour->Concatenate( editingContour, timestep, true);
// set last inserted vertex as selected
- newContour->SelectVertexAt(newContour->GetNumberOfVertices()-1, timestep);
+ newContour->SelectVertexAt(selectedVertexIndex, timestep);
+
+ //set as control point
+ newContour->SetSelectedVertexAsControlPoint(true);
- // concatenate right live wire but only if we have more than one vertex
- if (!rightLiveWire->IsEmpty())
- {
- newContour->Concatenate( rightLiveWire, timestep, true );
- }
// concatenate right original contour
newContour->Concatenate( this->m_ContourRight, timestep );
newContour->SetIsClosed(contour->IsClosed(timestep), timestep);
m_DataNode->SetData(newContour);
//this->m_lastMousePosition = positionEvent->GetWorldPosition();
assert( positionEvent->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
return true;
}
int mitk::ContourModelLiveWireInteractor::SplitContourFromSelectedVertex(mitk::ContourModel* srcContour,
mitk::ContourModel* destContour,
bool fromSelectedUpwards, int timestep)
{
mitk::ContourModel::VertexIterator end = srcContour->IteratorEnd();
mitk::ContourModel::VertexIterator begin = srcContour->IteratorBegin();
//search next active control point to left and rigth and set as start and end point for filter
mitk::ContourModel::VertexIterator itSelected = begin;
// move iterator to position
while ((*itSelected) != srcContour->GetSelectedVertex())
{
itSelected++;
}
// CASE search upwards for next control point
if(fromSelectedUpwards)
{
mitk::ContourModel::VertexIterator itUp = itSelected;
if(itUp != end)
{
itUp++;//step once up otherwise the loop breaks immediately
}
while( itUp != end && !((*itUp)->IsControlPoint))
{
itUp++;
}
mitk::ContourModel::VertexIterator it = itUp;
if (itSelected != begin)
{
//copy the rest of the original contour
while (it != end)
{
destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
it++;
}
}
//else do not copy the contour
//return the offset of iterator at one before next-vertex-upwards
if(itUp != begin)
{
return std::distance( begin, itUp) - 1;
}
else
{
return std::distance( begin, itUp);
}
}
else //CASE search downwards for next control point
{
mitk::ContourModel::VertexIterator itDown = itSelected;
mitk::ContourModel::VertexIterator it = srcContour->IteratorBegin();
if( itSelected != begin )
{
if(itDown != begin)
{
itDown--;//step once down otherwise the the loop breaks immediately
}
while( itDown != begin && !((*itDown)->IsControlPoint)){ itDown--; }
if(it != end)//if not empty
{
//always add the first vertex
destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
it++;
}
//copy from begin to itDown
while(it <= itDown)
{
destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
it++;
}
}
else
{
//if selected vertex is the first element search from end of contour downwards
itDown = end;
itDown--;
while(!((*itDown)->IsControlPoint)){itDown--;}
//move one forward as we don't want the first control point
it++;
//move iterator to second control point
while( (it!=end) && !((*it)->IsControlPoint) ){it++;}
//copy from begin to itDown
while(it <= itDown)
{
//copy the contour from second control point to itDown
destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
it++;
}
}
/*
//add vertex at itDown - it's not considered during while loop
if( it != begin && it != end)
{
//destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
}
*/
//return the offset of iterator at one after next-vertex-downwards
if( itDown != end)
{
return std::distance( begin, itDown);// + 1;//index of next vertex
}
else
{
return std::distance( begin, itDown) - 1;
}
}
}
bool mitk::ContourModelLiveWireInteractor::OnFinishEditing( Action* action, const StateEvent* stateEvent)
{
int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep();
mitk::ContourModel *editingContour = dynamic_cast( this->m_EditingContourNode->GetData() );
assert ( editingContour );
editingContour->Clear(timestep);
/*
mitk::ContourModel *rightLiveWire = dynamic_cast( this->m_RightLiveWireContourNode->GetData() );
assert ( rightLiveWire );
rightLiveWire->Clear(timestep);
*/
assert( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
return true;
}
diff --git a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp
index 07f6030edf..962e3de251 100644
--- a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp
+++ b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp
@@ -1,669 +1,673 @@
/*===================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.
This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.
See LICENSE.txt or http://www.mitk.org for details.
===================================================================*/
#include "mitkLiveWireTool2D.h"
#include "mitkToolManager.h"
#include "mitkBaseRenderer.h"
#include "mitkRenderingManager.h"
#include "mitkLiveWireTool2D.xpm"
#include
#include
#include "mitkContourUtils.h"
#include "mitkContour.h"
#include
// us
#include "mitkModule.h"
#include "mitkModuleResource.h"
#include
namespace mitk {
MITK_TOOL_MACRO(Segmentation_EXPORT, LiveWireTool2D, "LiveWire tool");
}
mitk::LiveWireTool2D::LiveWireTool2D()
:SegTool2D("LiveWireTool")
{
// great magic numbers
CONNECT_ACTION( AcINITNEWOBJECT, OnInitLiveWire );
CONNECT_ACTION( AcADDPOINT, OnAddPoint );
CONNECT_ACTION( AcMOVE, OnMouseMoveNoDynamicCosts );
CONNECT_ACTION( AcCHECKPOINT, OnCheckPoint );
CONNECT_ACTION( AcFINISH, OnFinish );
CONNECT_ACTION( AcDELETEPOINT, OnLastSegmentDelete );
CONNECT_ACTION( AcADDLINE, OnMouseMoved );
}
mitk::LiveWireTool2D::~LiveWireTool2D()
{
this->m_WorkingContours.clear();
this->m_EditingContours.clear();
}
float mitk::LiveWireTool2D::CanHandleEvent( StateEvent const *stateEvent) const
{
mitk::PositionEvent const *positionEvent =
dynamic_cast (stateEvent->GetEvent());
//Key event handling:
if (positionEvent == NULL)
{
//check for delete and escape event
if(stateEvent->GetId() == 12 || stateEvent->GetId() == 14)
{
return 1.0;
}
//check, if the current state has a transition waiting for that key event.
else if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL)
{
return 0.5;
}
else
{
return 0.0;
}
}
else
{
if ( positionEvent->GetSender()->GetMapperID() != BaseRenderer::Standard2D )
return 0.0; // we don't want anything but 2D
return 1.0;
}
}
const char** mitk::LiveWireTool2D::GetXPM() const
{
return mitkLiveWireTool2D_xpm;
}
mitk::ModuleResource mitk::LiveWireTool2D::GetIconResource() const
{
Module* module = GetModuleContext()->GetModule();
ModuleResource resource = module->GetResource("LiveWire_48x48.png");
return resource;
}
mitk::ModuleResource mitk::LiveWireTool2D::GetCursorIconResource() const
{
Module* module = GetModuleContext()->GetModule();
ModuleResource resource = module->GetResource("LiveWire_Cursor_32x32.png");
return resource;
}
const char* mitk::LiveWireTool2D::GetName() const
{
return "Live Wire";
}
void mitk::LiveWireTool2D::Activated()
{
Superclass::Activated();
}
void mitk::LiveWireTool2D::Deactivated()
{
this->ClearContours();
Superclass::Deactivated();
}
void mitk::LiveWireTool2D::ClearContours()
{
// for all contours in list (currently created by tool)
std::vector< std::pair >::iterator iter = this->m_WorkingContours.begin();
while(iter != this->m_WorkingContours.end() )
{
//remove contour node from datastorage
m_ToolManager->GetDataStorage()->Remove( iter->first );
++iter;
}
this->m_WorkingContours.clear();
// for all contours in list (currently created by tool)
std::vector< std::pair >::iterator itEditingContours = this->m_EditingContours.begin();
while(itEditingContours != this->m_EditingContours.end() )
{
//remove contour node from datastorage
m_ToolManager->GetDataStorage()->Remove( itEditingContours->first );
++itEditingContours;
}
this->m_EditingContours.clear();
std::vector< mitk::ContourModelLiveWireInteractor::Pointer >::iterator itLiveWireInteractors = this->m_LiveWireInteractors.begin();
while(itLiveWireInteractors != this->m_LiveWireInteractors.end() )
{
// remove interactors from globalInteraction instance
mitk::GlobalInteraction::GetInstance()->RemoveInteractor( *itLiveWireInteractors );
++itLiveWireInteractors;
}
this->m_LiveWireInteractors.clear();
}
void mitk::LiveWireTool2D::ConfirmSegmentation()
{
DataNode* workingNode( m_ToolManager->GetWorkingData(0) );
assert ( workingNode );
Image* workingImage = dynamic_cast(workingNode->GetData());
assert ( workingImage );
ContourUtils::Pointer contourUtils = mitk::ContourUtils::New();
// for all contours in list (currently created by tool)
std::vector< std::pair >::iterator itWorkingContours = this->m_WorkingContours.begin();
while(itWorkingContours != this->m_WorkingContours.end() )
{
// if node contains data
if( itWorkingContours->first->GetData() )
{
// if this is a contourModel
mitk::ContourModel* contourModel = dynamic_cast(itWorkingContours->first->GetData());
if( contourModel )
{
// for each timestep of this contourModel
for( int currentTimestep = 0; currentTimestep < contourModel->GetTimeSlicedGeometry()->GetTimeSteps(); currentTimestep++)
{
//get the segmentation image slice at current timestep
mitk::Image::Pointer workingSlice = this->GetAffectedImageSliceAs2DImage(itWorkingContours->second, workingImage, currentTimestep);
mitk::ContourModel::Pointer projectedContour = contourUtils->ProjectContourTo2DSlice(workingSlice, contourModel, true, false);
contourUtils->FillContourInSlice(projectedContour, workingSlice, 1.0);
//write back to image volume
this->WriteBackSegmentationResult(itWorkingContours->second, workingSlice, currentTimestep);
}
//remove contour node from datastorage
// m_ToolManager->GetDataStorage()->Remove( itWorkingContours->first );
}
}
++itWorkingContours;
}
/*
this->m_WorkingContours.clear();
// for all contours in list (currently created by tool)
std::vector< std::pair >::iterator itEditingContours = this->m_EditingContours.begin();
while(itEditingContours != this->m_EditingContours.end() )
{
//remove contour node from datastorage
m_ToolManager->GetDataStorage()->Remove( itEditingContours->first );
++itEditingContours;
}
this->m_EditingContours.clear();
std::vector< mitk::ContourModelLiveWireInteractor::Pointer >::iterator itLiveWireInteractors = this->m_LiveWireInteractors.begin();
while(itLiveWireInteractors != this->m_LiveWireInteractors.end() )
{
// remove interactors from globalInteraction instance
mitk::GlobalInteraction::GetInstance()->RemoveInteractor( *itLiveWireInteractors );
++itLiveWireInteractors;
}
this->m_LiveWireInteractors.clear();
*/
this->ClearContours();
}
bool mitk::LiveWireTool2D::OnInitLiveWire (Action* action, const StateEvent* stateEvent)
{
const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
if (!positionEvent) return false;
m_LastEventSender = positionEvent->GetSender();
m_LastEventSlice = m_LastEventSender->GetSlice();
if ( Superclass::CanHandleEvent(stateEvent) < 1.0 ) return false;
int timestep = positionEvent->GetSender()->GetTimeStep();
m_Contour = mitk::ContourModel::New();
m_Contour->Expand(timestep+1);
m_ContourModelNode = mitk::DataNode::New();
m_ContourModelNode->SetData( m_Contour );
m_ContourModelNode->SetName("working contour node");
m_ContourModelNode->AddProperty( "contour.color", ColorProperty::New(1, 1, 0), NULL, true );
m_ContourModelNode->AddProperty( "contour.points.color", ColorProperty::New(1.0, 0.0, 0.1), NULL, true );
m_ContourModelNode->AddProperty( "contour.controlpoints.show", BoolProperty::New(true), NULL, true );
m_LiveWireContour = mitk::ContourModel::New();
m_LiveWireContour->Expand(timestep+1);
m_LiveWireContourNode = mitk::DataNode::New();
m_LiveWireContourNode->SetData( m_LiveWireContour );
m_LiveWireContourNode->SetName("active livewire node");
+ m_LiveWireContourNode->SetProperty( "layer", IntProperty::New(100));
+ m_LiveWireContourNode->SetProperty( "helper object", mitk::BoolProperty::New(true));
m_LiveWireContourNode->AddProperty( "contour.color", ColorProperty::New(0.1, 1.0, 0.1), NULL, true );
m_LiveWireContourNode->AddProperty( "contour.width", mitk::FloatProperty::New( 4.0 ), NULL, true );
m_EditingContour = mitk::ContourModel::New();
m_EditingContour->Expand(timestep+1);
m_EditingContourNode = mitk::DataNode::New();
m_EditingContourNode->SetData( m_EditingContour );
m_EditingContourNode->SetName("editing node");
+ m_EditingContourNode->SetProperty( "layer", IntProperty::New(100));
+ m_EditingContourNode->SetProperty( "helper object", mitk::BoolProperty::New(true));
m_EditingContourNode->AddProperty( "contour.color", ColorProperty::New(0.1, 1.0, 0.1), NULL, true );
m_EditingContourNode->AddProperty( "contour.points.color", ColorProperty::New(0.0, 0.0, 1.0), NULL, true );
m_EditingContourNode->AddProperty( "contour.width", mitk::FloatProperty::New( 4.0 ), NULL, true );
m_ToolManager->GetDataStorage()->Add( m_ContourModelNode );
m_ToolManager->GetDataStorage()->Add( m_LiveWireContourNode );
m_ToolManager->GetDataStorage()->Add( m_EditingContourNode );
//set current slice as input for ImageToLiveWireContourFilter
m_WorkingSlice = this->GetAffectedReferenceSlice(positionEvent);
m_LiveWireFilter = mitk::ImageLiveWireContourModelFilter::New();
m_LiveWireFilter->SetInput(m_WorkingSlice);
//map click to pixel coordinates
mitk::Point3D click = const_cast(positionEvent->GetWorldPosition());
itk::Index<3> idx;
m_WorkingSlice->GetGeometry()->WorldToIndex(click, idx);
// get the pixel the gradient in region of 5x5
itk::Index<3> indexWithHighestGradient;
AccessFixedDimensionByItk_2(m_WorkingSlice, FindHighestGradientMagnitudeByITK, 2, idx, indexWithHighestGradient);
// itk::Index to mitk::Point3D
click[0] = indexWithHighestGradient[0];
click[1] = indexWithHighestGradient[1];
click[2] = indexWithHighestGradient[2];
m_WorkingSlice->GetGeometry()->IndexToWorld(click, click);
//set initial start point
m_Contour->AddVertex( click, true, timestep );
m_LiveWireFilter->SetStartPoint(click);
m_CreateAndUseDynamicCosts = true;
//render
assert( positionEvent->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
return true;
}
bool mitk::LiveWireTool2D::OnAddPoint (Action* action, const StateEvent* stateEvent)
{
//complete LiveWire interaction for last segment
//add current LiveWire contour to the finished contour and reset
//to start new segment and computation
/* check if event can be handled */
const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
if (!positionEvent) return false;
if ( Superclass::CanHandleEvent(stateEvent) < 1.0 ) return false;
/* END check if event can be handled */
int timestep = positionEvent->GetSender()->GetTimeStep();
//add repulsive points to avoid to get the same path again
typedef mitk::ImageLiveWireContourModelFilter::InternalImageType::IndexType IndexType;
mitk::ContourModel::ConstVertexIterator iter = m_LiveWireContour->IteratorBegin(timestep);
for (;iter != m_LiveWireContour->IteratorEnd(timestep); iter++)
{
IndexType idx;
this->m_WorkingSlice->GetGeometry()->WorldToIndex((*iter)->Coordinates, idx);
this->m_LiveWireFilter->AddRepulsivePoint( idx );
}
//remove duplicate first vertex, it's already contained in m_Contour
m_LiveWireContour->RemoveVertexAt(0, timestep);
// set last added point as control point
m_LiveWireContour->SetControlVertexAt(m_LiveWireContour->GetNumberOfVertices(timestep)-1, timestep);
//merge contours
m_Contour->Concatenate(m_LiveWireContour, timestep);
//clear the livewire contour and reset the corresponding datanode
m_LiveWireContour->Clear(timestep);
//set new start point
m_LiveWireFilter->SetStartPoint(const_cast(positionEvent->GetWorldPosition()));
if( m_CreateAndUseDynamicCosts )
{
//use dynamic cost map for next update
m_LiveWireFilter->CreateDynamicCostMap(m_Contour);
m_LiveWireFilter->SetUseDynamicCostMap(true);
//m_CreateAndUseDynamicCosts = false;
}
//render
assert( positionEvent->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
return true;
}
bool mitk::LiveWireTool2D::OnMouseMoved( Action* action, const StateEvent* stateEvent)
{
//compute LiveWire segment from last control point to current mouse position
// check if event can be handled
if ( Superclass::CanHandleEvent(stateEvent) < 1.0 ) return false;
const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
if (!positionEvent) return false;
// actual LiveWire computation
int timestep = positionEvent->GetSender()->GetTimeStep();
m_LiveWireFilter->SetEndPoint(const_cast(positionEvent->GetWorldPosition()));
m_LiveWireFilter->SetTimeStep(m_TimeStep);
m_LiveWireFilter->Update();
m_LiveWireContour = this->m_LiveWireFilter->GetOutput();
m_LiveWireContourNode->SetData( this->m_LiveWireContour );
//render
assert( positionEvent->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
return true;
}
bool mitk::LiveWireTool2D::OnMouseMoveNoDynamicCosts(Action* action, const StateEvent* stateEvent)
{
//do not use dynamic cost map
m_LiveWireFilter->SetUseDynamicCostMap(false);
OnMouseMoved(action, stateEvent);
m_LiveWireFilter->SetUseDynamicCostMap(true);
return true;
}
bool mitk::LiveWireTool2D::OnCheckPoint( Action* action, const StateEvent* stateEvent)
{
//check double click on first control point to finish the LiveWire tool
//
//Check distance to first point.
//Transition YES if click close to first control point
//
mitk::StateEvent* newStateEvent = NULL;
const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
if (!positionEvent)
{
//stay in current state
newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent());
}
else
{
int timestep = positionEvent->GetSender()->GetTimeStep();
mitk::Point3D click = positionEvent->GetWorldPosition();
mitk::Point3D first = this->m_Contour->GetVertexAt(0, timestep)->Coordinates;
if (first.EuclideanDistanceTo(click) < 4.5)
{
// allow to finish
newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent());
}
else
{
//stay active
newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent());
}
}
this->HandleEvent( newStateEvent );
return true;
}
bool mitk::LiveWireTool2D::OnFinish( Action* action, const StateEvent* stateEvent)
{
// finish livewire tool interaction
// check if event can be handled
if ( Superclass::CanHandleEvent(stateEvent) < 1.0 ) return false;
const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
if (!positionEvent) return false;
// actual timestep
int timestep = positionEvent->GetSender()->GetTimeStep();
// remove last control point being added by double click
m_Contour->RemoveVertexAt(m_Contour->GetNumberOfVertices(timestep) - 1, timestep);
// save contour and corresponding plane geometry to list
std::pair cp(m_ContourModelNode, dynamic_cast(positionEvent->GetSender()->GetCurrentWorldGeometry2D()->Clone().GetPointer()) );
this->m_WorkingContours.push_back(cp);
std::pair ecp(m_EditingContourNode, dynamic_cast(positionEvent->GetSender()->GetCurrentWorldGeometry2D()->Clone().GetPointer()) );
this->m_EditingContours.push_back(ecp);
m_LiveWireFilter->SetUseDynamicCostMap(false);
this->FinishTool();
return true;
}
void mitk::LiveWireTool2D::FinishTool()
{
unsigned int numberOfTimesteps = m_Contour->GetTimeSlicedGeometry()->GetTimeSteps();
//close contour in each timestep
for( int i = 0; i <= numberOfTimesteps; i++)
{
m_Contour->Close(i);
}
m_ToolManager->GetDataStorage()->Remove( m_LiveWireContourNode );
// clear live wire contour node
m_LiveWireContourNode = NULL;
m_LiveWireContour = NULL;
//change color as visual feedback of completed livewire
//m_ContourModelNode->AddProperty( "contour.color", ColorProperty::New(1.0, 1.0, 0.1), NULL, true );
//m_ContourModelNode->SetName("contour node");
//set the livewire interactor to edit control points
m_ContourInteractor = mitk::ContourModelLiveWireInteractor::New(m_ContourModelNode);
m_ContourInteractor->SetWorkingImage(this->m_WorkingSlice);
m_ContourInteractor->SetEditingContourModelNode(this->m_EditingContourNode);
m_ContourModelNode->SetInteractor(m_ContourInteractor);
this->m_LiveWireInteractors.push_back( m_ContourInteractor );
//add interactor to globalInteraction instance
mitk::GlobalInteraction::GetInstance()->AddInteractor(m_ContourInteractor);
}
bool mitk::LiveWireTool2D::OnLastSegmentDelete( Action* action, const StateEvent* stateEvent)
{
int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep();
//if last point of current contour will be removed go to start state and remove nodes
if( m_Contour->GetNumberOfVertices(timestep) <= 1 )
{
m_ToolManager->GetDataStorage()->Remove( m_LiveWireContourNode );
m_ToolManager->GetDataStorage()->Remove( m_ContourModelNode );
m_ToolManager->GetDataStorage()->Remove( m_EditingContourNode );
m_LiveWireContour = mitk::ContourModel::New();
m_Contour = mitk::ContourModel::New();
m_ContourModelNode->SetData( m_Contour );
m_LiveWireContourNode->SetData( m_LiveWireContour );
Superclass::Deactivated(); //go to start state
}
else //remove last segment from contour and reset livewire contour
{
m_LiveWireContour = mitk::ContourModel::New();
m_LiveWireContourNode->SetData(m_LiveWireContour);
mitk::ContourModel::Pointer newContour = mitk::ContourModel::New();
newContour->Expand(m_Contour->GetTimeSteps());
mitk::ContourModel::VertexIterator begin = m_Contour->IteratorBegin();
//iterate from last point to next active point
mitk::ContourModel::VertexIterator newLast = m_Contour->IteratorBegin() + (m_Contour->GetNumberOfVertices() - 1);
//go at least one down
if(newLast != begin)
{
newLast--;
}
//search next active control point
while(newLast != begin && !((*newLast)->IsControlPoint) )
{
newLast--;
}
//set position of start point for livewire filter to coordinates of the new last point
m_LiveWireFilter->SetStartPoint((*newLast)->Coordinates);
mitk::ContourModel::VertexIterator it = m_Contour->IteratorBegin();
//fill new Contour
while(it <= newLast)
{
newContour->AddVertex((*it)->Coordinates, (*it)->IsControlPoint, timestep);
it++;
}
newContour->SetIsClosed(m_Contour->IsClosed());
//set new contour visible
m_ContourModelNode->SetData(newContour);
m_Contour = newContour;
assert( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
}
return true;
}
template
void mitk::LiveWireTool2D::FindHighestGradientMagnitudeByITK(itk::Image* inputImage, itk::Index<3> &index, itk::Index<3> &returnIndex)
{
typedef itk::Image InputImageType;
typedef typename InputImageType::IndexType IndexType;
unsigned long xMAX = inputImage->GetLargestPossibleRegion().GetSize()[0];
unsigned long yMAX = inputImage->GetLargestPossibleRegion().GetSize()[1];
returnIndex[0] = index[0];
returnIndex[1] = index[1];
returnIndex[2] = 0.0;
double gradientMagnitude = 0.0;
double maxGradientMagnitude = 0.0;
/*
the size and thus the region of 7x7 is only used to calculate the gradient magnitude in that region
not for searching the maximum value
*/
//maximum value in each direction for size
typename InputImageType::SizeType size;
size[0] = 7;
size[1] = 7;
//minimum value in each direction for startRegion
IndexType startRegion;
startRegion[0] = index[0] - 3;
startRegion[1] = index[1] - 3;
if(startRegion[0] < 0) startRegion[0] = 0;
if(startRegion[1] < 0) startRegion[1] = 0;
if(xMAX - index[0] < 7) startRegion[0] = xMAX - 7;
if(yMAX - index[1] < 7) startRegion[1] = yMAX - 7;
index[0] = startRegion[0] + 3;
index[1] = startRegion[1] + 3;
typename InputImageType::RegionType region;
region.SetSize( size );
region.SetIndex( startRegion );
typedef typename itk::GradientMagnitudeImageFilter< InputImageType, InputImageType> GradientMagnitudeFilterType;
typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New();
gradientFilter->SetInput(inputImage);
gradientFilter->GetOutput()->SetRequestedRegion(region);
gradientFilter->Update();
typename InputImageType::Pointer gradientMagnImage;
gradientMagnImage = gradientFilter->GetOutput();
IndexType currentIndex;
currentIndex[0] = 0;
currentIndex[1] = 0;
// search max (approximate) gradient magnitude
for( int x = -1; x <= 1; ++x)
{
currentIndex[0] = index[0] + x;
for( int y = -1; y <= 1; ++y)
{
currentIndex[1] = index[1] + y;
gradientMagnitude = gradientMagnImage->GetPixel(currentIndex);
//check for new max
if(maxGradientMagnitude < gradientMagnitude)
{
maxGradientMagnitude = gradientMagnitude;
returnIndex[0] = currentIndex[0];
returnIndex[1] = currentIndex[1];
returnIndex[2] = 0.0;
}//end if
}//end for y
currentIndex[1] = index[1];
}//end for x
}