diff --git a/Core/Code/Resources/Interactions/Legacy/StateMachine.xml b/Core/Code/Resources/Interactions/Legacy/StateMachine.xml
index 0cd6f2be12..9e12e74455 100644
--- a/Core/Code/Resources/Interactions/Legacy/StateMachine.xml
+++ b/Core/Code/Resources/Interactions/Legacy/StateMachine.xml
@@ -1,4101 +1,4086 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/Modules/GraphAlgorithms/itkShortestPathCostFunction.h b/Modules/GraphAlgorithms/itkShortestPathCostFunction.h
index 986d75d4a2..34595b3f81 100644
--- a/Modules/GraphAlgorithms/itkShortestPathCostFunction.h
+++ b/Modules/GraphAlgorithms/itkShortestPathCostFunction.h
@@ -1,97 +1,90 @@
/*===================================================================
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 __itkShortestPathCostFunction_h
#define __itkShortestPathCostFunction_h
#include "itkObject.h"
#include "itkObjectFactory.h"
#include "itkShapedNeighborhoodIterator.h"
-#include
namespace itk
{
- // \brief this is a pure virtual superclass for all cost function for the itkShortestPathImageFilter
+ // \brief this is a pure virtual superclass for all cost functions used in itkShortestPathImageFilter
template
class ShortestPathCostFunction : public Object
{
public:
/** Standard class typedefs. */
typedef ShortestPathCostFunction Self;
typedef Object Superclass;
typedef SmartPointer Pointer;
typedef SmartPointer ConstPointer;
- typedef ShapedNeighborhoodIterator< TInputImageType > itkShapedNeighborhoodIteratorType;
-
+ typedef ShapedNeighborhoodIterator< TInputImageType > ShapedNeighborhoodIteratorType;
/** Run-time type information (and related methods). */
itkTypeMacro(ShortestPathCostFunction, Object);
/** Type definition for the input image. */
typedef TInputImageType ImageType;
// More typdefs for convenience
typedef typename TInputImageType::Pointer ImagePointer;
typedef typename TInputImageType::ConstPointer ImageConstPointer;
-
-
typedef typename TInputImageType::PixelType PixelType;
-
typedef typename TInputImageType::IndexType IndexType;
- /** Set the input image. */
+ // \brief Set the input image.
itkSetConstObjectMacro(Image,TInputImageType);
- // \brief calculates the costs for going from pixel1 to pixel2
+ // \brief Calculate the cost for going from pixel p1 to pixel p2
virtual double GetCost( IndexType p1, IndexType p2) = 0;
- // \brief returns the minimal costs possible (needed for A*)
+ // \brief Return the minimal possible cost (needed for A*)
virtual double GetMinCost() = 0;
// \brief Initialize the metric
virtual void Initialize () = 0;
- // \brief Set Starpoint for Path
- void SetStartIndex (const IndexType & StartIndex);
-
- // \brief Set Endpoint for Path
- void SetEndIndex(const IndexType & EndIndex);
-
+ // \brief Set the starting index of a path
+ void SetStartIndex (const IndexType & index);
- ShortestPathCostFunction();
+ // \brief Set the ending index of a path
+ void SetEndIndex(const IndexType & index);
protected:
+ ShortestPathCostFunction() {};
virtual ~ShortestPathCostFunction() {};
void PrintSelf(std::ostream& os, Indent indent) const;
ImageConstPointer m_Image;
IndexType m_StartIndex, m_EndIndex;
private:
ShortestPathCostFunction(const Self&); //purposely not implemented
void operator=(const Self&); //purposely not implemented
};
} // end namespace itk
#include "itkShortestPathCostFunction.txx"
#endif /* __itkShortestPathCostFunction_h */
diff --git a/Modules/GraphAlgorithms/itkShortestPathCostFunction.txx b/Modules/GraphAlgorithms/itkShortestPathCostFunction.txx
index d620e89be6..e7b4141b06 100644
--- a/Modules/GraphAlgorithms/itkShortestPathCostFunction.txx
+++ b/Modules/GraphAlgorithms/itkShortestPathCostFunction.txx
@@ -1,64 +1,57 @@
/*===================================================================
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 __itkShortestPathCostFunction_cpp
-#define __itkShortestPathCostFunction_cpp
+#ifndef __itkShortestPathCostFunction_txx
+#define __itkShortestPathCostFunction_txx
+#include "itkShortestPathCostFunction.h"
namespace itk
{
- // Constructor
- template
- ShortestPathCostFunction
- ::ShortestPathCostFunction()
- {
- }
-
-
template
void
ShortestPathCostFunction
::PrintSelf( std::ostream& os, Indent indent ) const
{
Superclass::PrintSelf(os,indent);
}
template
void ShortestPathCostFunction::
- SetStartIndex (const typename TInputImageType::IndexType &StartIndex)
+ SetStartIndex (const typename TInputImageType::IndexType &index)
{
for (unsigned int i=0;i
void ShortestPathCostFunction::
- SetEndIndex (const typename TInputImageType::IndexType &EndIndex)
+ SetEndIndex (const typename TInputImageType::IndexType &index)
{
for (unsigned int i=0;i
-
+#include "itkShortestPathCostFunction.h"
+#include "itkImageRegionConstIterator.h"
namespace itk
{
/** \brief Cost function for LiveWire purposes.
Specific features are considered to calculate cummulative
costs of a link between two pixels. These are:
- Gradient Magnitude
- Gradient Direction
- Laplacian Zero Crossing
- By default the Gradient Magnitude is mapped linear to costs
+ By default the Gradient Magnitude is mapped linearly to cost values
between 0 (good) and 1 (bad). Via SetDynamicCostMap( std::map< int, int > &costMap)
a cost map can be set to dynamically map Gradient Magnitude (non
- linear). Thus lower values can be considered with lower costs
+ linear). Thus, lower values can be considered with lower costs
than higher values of gradient magnitudes.
To compute the costs of the gradient magnitude dynamically
- a iverted map of the histogram of gradient magnitude image is used.
+ an iverted map of the histogram of gradient magnitude image is used.
*/
template
class ITK_EXPORT ShortestPathCostFunctionLiveWire : public ShortestPathCostFunction
{
public:
/** Standard class typedefs. */
typedef ShortestPathCostFunctionLiveWire Self;
typedef ShortestPathCostFunction Superclass;
typedef SmartPointer Pointer;
typedef SmartPointer ConstPointer;
typedef itk::ImageRegionConstIterator ConstIteratorType;
/** Method for creation through the object factory. */
itkNewMacro(Self);
/** Run-time type information (and related methods). */
itkTypeMacro(ShortestPathCostFunctionLiveWire, ShortestPathCostFunction);
- typedef itk::Image UnsignedCharImageType;
- typedef itk::Image FloatImageType;
+ typedef itk::Image UnsignedCharImageType;
+ typedef itk::Image FloatImageType;
typedef float ComponentType;
- typedef itk::CovariantVector< ComponentType, 2 > OutputPixelType;
- typedef itk::Image< OutputPixelType, 2 > VectorOutputImageType;
-
- typedef typename TInputImageType::IndexType IndexType;
- typedef TInputImageType ImageType;
- typedef itk::ImageRegion<2> RegionType;
+ typedef itk::CovariantVector< ComponentType, 2 > OutputPixelType;
+ typedef itk::Image< OutputPixelType, 2 > VectorOutputImageType;
+ typedef typename TInputImageType::IndexType IndexType;
+ typedef TInputImageType ImageType;
+ typedef itk::ImageRegion<2> RegionType;
/** \brief calculates the costs for going from p1 to p2*/
virtual double GetCost(IndexType p1, IndexType p2);
/** \brief returns the minimal costs possible (needed for A*)*/
virtual double GetMinCost();
/** \brief Initialize the metric*/
virtual void Initialize ();
+ /** \brief Add void pixel in cost map*/
+ virtual void AddRepulsivePoint( const IndexType& index );
- /** \brief Set repulsive path*/
- virtual void AddRepulsivePoint( itk::Index<3> );
-
- /** \brief Clear repulsive path*/
- virtual void ClearRepulsivePoints( );
-
-
-
- ShortestPathCostFunctionLiveWire();
+ /** \brief Remove void pixel in cost map*/
+ virtual void RemoveRepulsivePoint( const IndexType& index );
+ /** \brief Clear repulsive points in cost function*/
+ virtual void ClearRepulsivePoints();
itkSetMacro (RequestedRegion, RegionType);
itkGetMacro (RequestedRegion, RegionType);
// Set/Get function for sigma parameter
itkSetMacro (UseApproximateGradient, bool);
itkGetMacro (UseApproximateGradient, bool);
- virtual void SetImage(const TInputImageType* _arg)
- {
- if (this->m_Image != _arg)
- {
- this->m_Image = _arg;
- this->Modified();
- this->m_Initialized = false;
- }
- }
+ virtual void SetImage(const TInputImageType* _arg);
void SetDynamicCostMap( std::map< int, int > &costMap)
{
this->m_CostMap = costMap;
this->m_UseCostMap = true;
this->m_MaxMapCosts = -1;
this->Modified();
}
void SetUseCostMap(bool useCostMap)
{
this->m_UseCostMap = useCostMap;
}
/**
\brief Set the maximum of the dynamic cost map to save computation time.
*/
void SetCostMapMaximum(double max)
{
this->m_MaxMapCosts = max;
}
enum Constants{
MAPSCALEFACTOR = 10
};
/** \brief Returns the y value of gaussian with given offset and amplitude
gaussian approximation
f(x) = v(bin) * e^ ( -1/2 * (|x-k(bin)| / sigma)^2 )
\param x
\param xOfGaussian - offset
\param yOfGaussian - amplitude
*/
static double Gaussian(double x, double xOfGaussian, double yOfGaussian);
+ const UnsignedCharImageType* GetMaskImage()
+ { return this->m_MaskImage.GetPointer(); };
+
+ const FloatImageType* GetGradientMagnitudeImage()
+ { return this->m_GradientMagnitudeImage.GetPointer(); };
+
+ const FloatImageType* GetEdgeImage()
+ { return this->m_EdgeImage.GetPointer(); };
+
+ const VectorOutputImageType* GetGradientImage()
+ { return this->m_GradientImage.GetPointer(); };
+
protected:
+ ShortestPathCostFunctionLiveWire();
+
virtual ~ShortestPathCostFunctionLiveWire() {};
- typename ImageType::Pointer m_GradientMagnImage;
- typename UnsignedCharImageType::Pointer m_ZeroCrossingsImage;
- typename FloatImageType::Pointer m_EdgeImage;
- typename VectorOutputImageType::Pointer m_GradientImage;
+ FloatImageType::Pointer m_GradientMagnitudeImage;
+ FloatImageType::Pointer m_EdgeImage;
+ UnsignedCharImageType::Pointer m_MaskImage;
+ VectorOutputImageType::Pointer m_GradientImage;
double minCosts;
- bool m_UseRepulsivePoint;
-
- std::vector< itk::Index<3> > m_RepulsivePoints;
+ bool m_UseRepulsivePoints;
typename Superclass::PixelType val;
typename Superclass::PixelType startValue;
typename Superclass::PixelType endValue;
double m_GradientMax;
RegionType m_RequestedRegion;
bool m_UseApproximateGradient;
bool m_Initialized;
std::map< int, int > m_CostMap;
bool m_UseCostMap;
double m_MaxMapCosts;
private:
double SigmoidFunction(double I, double max, double min, double alpha, double beta);
};
} // end namespace itk
#ifndef ITK_MANUAL_INSTANTIATION
#include "itkShortestPathCostFunctionLiveWire.txx"
#endif
#endif /* __itkShortestPathCostFunctionLiveWire_h */
diff --git a/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx
index a9ad943a75..5afae1f6e5 100644
--- a/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx
+++ b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx
@@ -1,441 +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
-#include
#include
namespace itk
{
// Constructor
template
ShortestPathCostFunctionLiveWire
::ShortestPathCostFunctionLiveWire()
{
- m_UseRepulsivePoint = false;
+ m_UseRepulsivePoints = false;
m_GradientMax = 0.0;
m_Initialized = false;
m_UseCostMap = false;
m_MaxMapCosts = -1.0;
}
-
-
template
void ShortestPathCostFunctionLiveWire
- ::AddRepulsivePoint( itk::Index<3> c )
+ ::AddRepulsivePoint( const IndexType& index )
{
- m_RepulsivePoints.push_back(c);
- m_UseRepulsivePoint = true;
+ 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 (m_Image != _arg)
+ {
+ m_Image = _arg;
+
+ // initialize mask image
+ m_MaskImage = UnsignedCharImageType::New();
+ m_MaskImage->SetRegions(m_Image->GetLargestPossibleRegion());
+ m_MaskImage->SetOrigin( m_Image->GetOrigin() );
+ m_MaskImage->SetSpacing( m_Image->GetSpacing() );
+ m_MaskImage->SetDirection( m_Image->GetDirection() );
+ m_MaskImage->Allocate ();
+ m_MaskImage->FillBuffer(0);
+
+ this->Modified();
+ this->m_Initialized = false;
+ }
+ }
template
void ShortestPathCostFunctionLiveWire
::ClearRepulsivePoints()
{
- m_RepulsivePoints.clear();
- m_UseRepulsivePoint = false;
+ m_UseRepulsivePoints = false;
+ 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;
- /* ++++++++++++++++++++ GradientMagnitude costs ++++++++++++++++++++++++++*/
-
- gradientMagnitude = this->m_GradientMagnImage->GetPixel(p2);
+ // 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 ++++++++++++++++++++++++++*/
+ // 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 ++++++++++++++++++++++++++*/
+ // 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_GradientMagnImage->GetPixel(p2);
- nGradientAtP2[1] /= m_GradientMagnImage->GetPixel(p2);
+ 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;
- /*------------------------------------------------------------------------*/
-
-
-
-
- /*+++++++++++++++++++++ local component costs +++++++++++++++++++++++++++*/
- /*weights*/
- double w1;
- double w2;
- double w3;
- double costs = 0.0;
- if (this->m_UseCostMap){
+ 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;
+ //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();
- m_GradientMagnImage = gradientFilter->GetOutput();
+ this->m_GradientMagnitudeImage = gradientFilter->GetOutput();
typedef itk::StatisticsImageFilter StatisticsImageFilterType;
typename StatisticsImageFilterType::Pointer statisticsImageFilter = StatisticsImageFilterType::New();
- statisticsImageFilter->SetInput(this->m_GradientMagnImage);
+ statisticsImageFilter->SetInput(this->m_GradientMagnitudeImage);
statisticsImageFilter->Update();
m_GradientMax = statisticsImageFilter->GetMaximum();
-
-
- //Filter class is instantiated
- /*typedef itk::GradientRecursiveGaussianImageFilter GradientFilterType;*/
-
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/GraphAlgorithms/itkShortestPathImageFilter.txx b/Modules/GraphAlgorithms/itkShortestPathImageFilter.txx
index 933130fe43..06c880b31b 100644
--- a/Modules/GraphAlgorithms/itkShortestPathImageFilter.txx
+++ b/Modules/GraphAlgorithms/itkShortestPathImageFilter.txx
@@ -1,951 +1,953 @@
/*===================================================================
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 __itkShortestPathImageFilter_txx
#define __itkShortestPathImageFilter_txx
+#include "itkShortestPathImageFilter.h"
+
#include "time.h"
#include "mitkMemoryUtilities.h"
#include
#include
#include
namespace itk
{
// Constructor (initialize standard values)
template
ShortestPathImageFilter
::ShortestPathImageFilter() :
m_FullNeighborsMode(false),
m_MakeOutputImage(true),
m_StoreVectorOrder(false),
m_CalcAllDistances(false),
m_ActivateTimeOut(false),
multipleEndPoints(false),
m_Initialized(false),
m_Nodes(0),
m_Graph_NumberOfNodes(0)
{
m_endPoints.clear();
m_endPointsClosed.clear();
if (m_MakeOutputImage)
{
this->SetNumberOfRequiredOutputs(1);
this->SetNthOutput( 0, OutputImageType::New() );
}
}
template
ShortestPathImageFilter
::~ShortestPathImageFilter()
{
delete [] m_Nodes;
}
template
inline typename ShortestPathImageFilter::IndexType
ShortestPathImageFilter
::NodeToCoord (NodeNumType node)
{
const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize();
int dim = InputImageType::ImageDimension;
IndexType coord;
if (dim == 2)
{
coord[1] = node / size[0];
coord[0] = node % size[0];
if ((coord[0] >= size[0]) || (coord[1] >= size[1]))
{
coord[0] = 0;
coord[1] = 0;
}
}
if (dim == 3)
{
coord[2] = node / (size[0]*size[1]);
coord[1] = (node % (size[0]*size[1])) / size[0];
coord[0] = (node % (size[0]*size[1])) % size[0];
if ((coord[0] >= size[0]) || (coord[1] >= size[1]) || (coord[2] >= size[2]))
{
coord[0] = 0;
coord[1] = 0;
coord[2] = 0;
}
}
return coord;
}
template
inline typename itk::NodeNumType
ShortestPathImageFilter::
CoordToNode (IndexType coord)
{
const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize();
int dim = InputImageType::ImageDimension;
NodeNumType node = 0;
if (dim == 2)
{
node = (coord[1]*size[0]) + coord[0];
}
if (dim == 3)
{
node = (coord[2]*size[0]*size[1]) + (coord[1]*size[0]) + coord[0];
}
if ((m_Graph_NumberOfNodes > 0) && (node >= m_Graph_NumberOfNodes))
{
/*MITK_INFO << "WARNING! Coordinates outside image!";
MITK_INFO << "Coords = " << coord ;
MITK_INFO << "ImageDim = " << dim ;
MITK_INFO << "RequestedRegionSize = " << size ;*/
node = 0;
}
return node;
}
template
inline bool
ShortestPathImageFilter::
CoordIsInBounds (IndexType coord)
{
const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize();
int dim = InputImageType::ImageDimension;
if (dim == 2)
{
if ((coord[0] >= 0)
&& (coord[0] < size[0])
&& (coord[1] >= 0 )
&& (coord[1] < size[1] ))
{
return true;
}
}
if (dim == 3)
{
if ((coord[0] >= 0)
&& (coord[0] < size[0])
&& (coord[1] >= 0 )
&& (coord[1] < size[1] )
&& (coord[2] >= 0 )
&& (coord[2] < size[2] ))
{
return true;
}
}
return false;
}
template
inline std::vector< ShortestPathNode* >
ShortestPathImageFilter::
GetNeighbors (unsigned int nodeNum, bool FullNeighbors)
{
// returns a vector of nodepointers.. these nodes are the neighbors
int dim = InputImageType::ImageDimension;
IndexType Coord = NodeToCoord(nodeNum);
IndexType NeighborCoord;
std::vector nodeList;
int neighborDistance = 1; //if i increase that, i might not hit the endnote
// maybe use itkNeighborhoodIterator here, might be faster
if ( dim == 2)
{
// N4
NeighborCoord[0] = Coord[0];
NeighborCoord[1] = Coord[1]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1];
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0];
NeighborCoord[1] = Coord[1]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1];
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
if (FullNeighbors)
{
// N8
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
}
}
if ( dim == 3)
{
// N6
NeighborCoord[0] = Coord[0];
NeighborCoord[1] = Coord[1]-neighborDistance;
NeighborCoord[2] = Coord[2];
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1];
NeighborCoord[2] = Coord[2];
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0];
NeighborCoord[1] = Coord[1]+neighborDistance;
NeighborCoord[2] = Coord[2];
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1];
NeighborCoord[2] = Coord[2];
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0];
NeighborCoord[1] = Coord[1];
NeighborCoord[2] = Coord[2]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0];
NeighborCoord[1] = Coord[1];
NeighborCoord[2] = Coord[2]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
if (FullNeighbors)
{
// N26
// Middle Slice
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1]-neighborDistance;
NeighborCoord[2] = Coord[2];
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1]-neighborDistance;
NeighborCoord[2] = Coord[2];
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1]+neighborDistance;
NeighborCoord[2] = Coord[2];
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1]+neighborDistance;
NeighborCoord[2] = Coord[2];
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
// BackSlice (Diagonal)
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1]-neighborDistance;
NeighborCoord[2] = Coord[2]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1]-neighborDistance;
NeighborCoord[2] = Coord[2]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1]+neighborDistance;
NeighborCoord[2] = Coord[2]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1]+neighborDistance;
NeighborCoord[2] = Coord[2]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
//BackSlice (Non-Diag)
NeighborCoord[0] = Coord[0];
NeighborCoord[1] = Coord[1]-neighborDistance;
NeighborCoord[2] = Coord[2]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1];
NeighborCoord[2] = Coord[2]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0];
NeighborCoord[1] = Coord[1]+neighborDistance;
NeighborCoord[2] = Coord[2]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1];
NeighborCoord[2] = Coord[2]-neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
// FrontSlice (Diagonal)
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1]-neighborDistance;
NeighborCoord[2] = Coord[2]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1]-neighborDistance;
NeighborCoord[2] = Coord[2]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1]+neighborDistance;
NeighborCoord[2] = Coord[2]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1]+neighborDistance;
NeighborCoord[2] = Coord[2]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
//FrontSlice(Non-Diag)
NeighborCoord[0] = Coord[0];
NeighborCoord[1] = Coord[1]-neighborDistance;
NeighborCoord[2] = Coord[2]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]+neighborDistance;
NeighborCoord[1] = Coord[1];
NeighborCoord[2] = Coord[2]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0];
NeighborCoord[1] = Coord[1]+neighborDistance;
NeighborCoord[2] = Coord[2]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
NeighborCoord[0] = Coord[0]-neighborDistance;
NeighborCoord[1] = Coord[1];
NeighborCoord[2] = Coord[2]+neighborDistance;
if (CoordIsInBounds(NeighborCoord))
nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]);
}
}
return nodeList;
}
template
void ShortestPathImageFilter::
SetStartIndex (const typename TInputImageType::IndexType &StartIndex)
{
for (unsigned int i=0;i
void ShortestPathImageFilter::
SetEndIndex (const typename TInputImageType::IndexType &EndIndex)
{
for (unsigned int i=0;i
void ShortestPathImageFilter::
AddEndIndex (const typename TInputImageType::IndexType &index)
{
// ONLY FOR MULTIPLE END POINTS SEARCH
IndexType newEndIndex;
for (unsigned int i=0;i
inline double ShortestPathImageFilter::
getEstimatedCostsToTarget (const typename TInputImageType::IndexType &a)
{
// Returns the minimal possible costs for a path from "a" to targetnode.
itk::Vector v;
v[0] = m_EndIndex[0]-a[0];
v[1] = m_EndIndex[1]-a[1];
v[2] = m_EndIndex[2]-a[2];
return m_CostFunction->GetMinCost() * v.GetNorm();
}
template
void
ShortestPathImageFilter::
InitGraph()
{
if(!m_Initialized)
{
// Clean up previous stuff
CleanUp();
// Calc Number of nodes
m_ImageDimensions = TInputImageType::ImageDimension;
const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize();
m_Graph_NumberOfNodes = 1;
for (NodeNumType i=0; iInitialize();
}
template
void
ShortestPathImageFilter::
StartShortestPathSearch()
{
// Setup Timer
clock_t startAll = clock();
clock_t stopAll = clock();
// init variables
double durationAll = 0;
bool timeout = false;
bool makeNewHeapNecessary = false;
NodeNumType mainNodeListIndex = 0;
DistanceType curNodeDistance = 0;
DistanceType curNodeDistAndEst = 0;
NodeNumType numberOfNodesChecked = 0;
// Create Multimap (tree structure for fast searching)
std::multimap myMap;
std::pair< std::multimap::iterator, std::multimap::iterator> ret;
std::multimap::iterator it;
// At first, only startNote is discovered.
myMap.insert( std::pair (m_Nodes[m_Graph_StartNode].distAndEst, &m_Nodes[m_Graph_StartNode]) );
// While there are discovered Nodes, pick the one with lowest distance,
// update its neighbors and eventually delete it from the discovered Nodes list.
while(!myMap.empty())
{
numberOfNodesChecked++;
/*if ( (numberOfNodesChecked % (m_Graph_NumberOfNodes/100)) == 0)
{
MITK_INFO << "Checked " << ( numberOfNodesChecked / (m_Graph_NumberOfNodes/100) ) << "% List: " << myMap.size() << "\n";
}*/
// Get element with lowest score
mainNodeListIndex = myMap.begin()->second->mainListIndex;
curNodeDistAndEst = myMap.begin()->second->distAndEst;
curNodeDistance = myMap.begin()->second->distance;
myMap.begin()->second->closed = true; // close it
// Debug:
//MITK_INFO << "INFO: size " << myMap.size();
/*
for (it = myMap.begin(); it != myMap.end(); ++it)
{
MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex;
}
*/
// Kicks out element with lowest score
myMap.erase( myMap.begin() );
// if wanted, store vector order
if (m_StoreVectorOrder)
{
m_VectorOrder.push_back(mainNodeListIndex);
}
// Check neighbors
std::vector neighborNodes = GetNeighbors(mainNodeListIndex, m_Graph_fullNeighbors);
for (NodeNumType i=0; iclosed)
continue; // this nodes is already closed, go to next neighbor
IndexType coordCurNode = NodeToCoord(mainNodeListIndex);
IndexType coordNeighborNode = NodeToCoord(neighborNodes[i]->mainListIndex);
// calculate the new Distance to the current neighbor
double newDistance = curNodeDistance
+ (m_CostFunction->GetCost(coordCurNode, coordNeighborNode));
// if it is shorter than any yet known path to this neighbor, than the current path is better. Save that!
if ((newDistance < neighborNodes[i]->distance) || (neighborNodes[i]->distance == -1) )
{
// if that neighbornode is not in discoverednodeList yet, Push it there and update
if (neighborNodes[i]->distance == -1)
{
neighborNodes[i]->distance = newDistance;
neighborNodes[i]->distAndEst = newDistance + getEstimatedCostsToTarget(coordNeighborNode);
neighborNodes[i]->prevNode = mainNodeListIndex;
myMap.insert( std::pair (m_Nodes[neighborNodes[i]->mainListIndex].distAndEst, &m_Nodes[neighborNodes[i]->mainListIndex]) );
/*
MITK_INFO << "Inserted: " << m_Nodes[neighborNodes[i]->mainListIndex].distAndEst << "|" << m_Nodes[neighborNodes[i]->mainListIndex].mainListIndex;
MITK_INFO << "INFO: size " << myMap.size();
for (it = myMap.begin(); it != myMap.end(); ++it)
{
MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex;
}
*/
}
// or if is already in discoverednodelist, update
else
{
/*
it = myMap.find(neighborNodes[i]->distAndEst);
if (it == myMap.end() )
{
MITK_INFO << "Nothing!";
// look further
for (it = myMap.begin(); it != myMap.end(); ++it)
{
if ((*it).second->mainListIndex == lookForId)
{
MITK_INFO << "But it is there!!!";
MITK_INFO << "Searched for: " << lookFor << " but had: " << (*it).second->distAndEst;
}
}
}
*/
// 1st : find and delete old element
bool found = false;
double lookFor = neighborNodes[i]->distAndEst;
unsigned int lookForId = neighborNodes[i]->mainListIndex;
ret = myMap.equal_range(neighborNodes[i]->distAndEst);
if ((ret.first == ret.second))
{
/*+++++++++++++ no exact match +++++++++++++*/
//MITK_INFO << "No exact match!"; // if this happens, you are screwed
/*
MITK_INFO << "Was looking for: " << lookFor << " ID: " << lookForId;
if (ret.first != myMap.end() )
{
it = ret.first;
MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex;
++it;
MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex;
--it;
--it;
MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex;
}
// look if that ID is found in the map
for (it = myMap.begin(); it != myMap.end(); ++it)
{
if ((*it).second->mainListIndex == lookForId)
{
MITK_INFO << "But it is there!!!";
MITK_INFO << "Searched dist: " << lookFor << " found dist: " << (*it).second->distAndEst;
}
}
*/
}
else
{
for (it=ret.first; it!=ret.second; ++it)
{
if (it->second->mainListIndex == neighborNodes[i]->mainListIndex)
{
found = true;
myMap.erase(it);
/*
MITK_INFO << "INFO: size " << myMap.size();
MITK_INFO << "Erase: " << it->first << "|" << it->second->mainListIndex;
MITK_INFO << "INFO: size " << myMap.size();
for (it = myMap.begin(); it != myMap.end(); ++it)
{
MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex;
}
*/
break;
}
}
}
if (!found)
{
//MITK_INFO << "Could not find it! :(";
continue;
}
// 2nd: update and insert new element
neighborNodes[i]->distance = newDistance;
neighborNodes[i]->distAndEst = newDistance + getEstimatedCostsToTarget(coordNeighborNode);
neighborNodes[i]->prevNode = mainNodeListIndex;
//myMap.insert( std::pair (neighborNodes[i]->distAndEst, neighborNodes[i]));
myMap.insert( std::pair (m_Nodes[neighborNodes[i]->mainListIndex].distAndEst, &m_Nodes[neighborNodes[i]->mainListIndex]) );
//MITK_INFO << "Re-Inserted: " << m_Nodes[neighborNodes[i]->mainListIndex].distAndEst << "|" << m_Nodes[neighborNodes[i]->mainListIndex].mainListIndex;
//MITK_INFO << "INFO: size " << myMap.size();
/*for (it = myMap.begin(); it != myMap.end(); ++it)
{
MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex;
}*/
}
}
}
// finished with checking all neighbors.
// Check Timeout, if activated
if (m_ActivateTimeOut)
{
stopAll = clock();
durationAll = (double)(stopAll - startAll) / CLOCKS_PER_SEC;
if (durationAll >= 30)
{
//MITK_INFO << "TIMEOUT!! Search took over 30 seconds";
timeout = true ;
}
}
// Check end criteria:
// For multiple points
if ( multipleEndPoints )
{
// super slow, make it faster
for (int i=0 ;i
void
ShortestPathImageFilter::
MakeOutputs()
{
//MITK_INFO << "Make Output";
if (m_MakeOutputImage)
{
OutputImagePointer output0 = this->GetOutput(0);
output0->SetRegions( this->GetInput()->GetLargestPossibleRegion() );
output0->Allocate();
OutputImageIteratorType shortestPathImageIt (output0, output0->GetRequestedRegion());
// Create ShortestPathImage (Output 0)
for (shortestPathImageIt.GoToBegin(); !shortestPathImageIt.IsAtEnd(); ++shortestPathImageIt)
{
// First intialize with background color
shortestPathImageIt.Set( BACKGROUND ) ;
}
if (!multipleEndPoints) // Only one path was calculated
{
for (int i=0; i< m_VectorPath.size(); i++)
{
shortestPathImageIt.SetIndex( m_VectorPath[i] );
shortestPathImageIt.Set( FOREGROUND ) ;
}
}
else // multiple pathes has been calculated, draw all
{
for (int i =0; i
typename ShortestPathImageFilter::OutputImagePointer
ShortestPathImageFilter::
GetVectorOrderImage()
{
// Create Vector Order Image
// Return it
OutputImagePointer image = OutputImageType::New();
image->SetRegions( this->GetInput()->GetLargestPossibleRegion() );
image->Allocate();
OutputImageIteratorType vectorOrderImageIt (image, image->GetRequestedRegion());
//MITK_INFO << "GetVectorOrderImage";
for (vectorOrderImageIt.GoToBegin(); !vectorOrderImageIt.IsAtEnd(); ++vectorOrderImageIt)
{
// First intialize with background color
vectorOrderImageIt.Value() = BACKGROUND ;
}
for (int i=0; i< m_VectorOrder.size(); i++)
{
vectorOrderImageIt.SetIndex(NodeToCoord(m_VectorOrder[i]) );
vectorOrderImageIt.Set( BACKGROUND+i) ;
}
return image;
}
template
typename ShortestPathImageFilter::OutputImagePointer
ShortestPathImageFilter::
GetDistanceImage()
{
// Create Distance Image
// Return it
OutputImagePointer image = OutputImageType::New();
image->SetRegions( this->GetInput()->GetLargestPossibleRegion() );
image->Allocate();;
OutputImageIteratorType distanceImageIt (image, image->GetRequestedRegion());
// Create Distance Image (Output 1)
NodeNumType myNodeNum;
for (distanceImageIt.GoToBegin(); !distanceImageIt.IsAtEnd(); ++distanceImageIt)
{
IndexType index = distanceImageIt.GetIndex();
myNodeNum = CoordToNode(index);
double newVal = m_Nodes[myNodeNum].distance;
distanceImageIt.Set(newVal);
}
}
template
std::vector< typename ShortestPathImageFilter::IndexType >
ShortestPathImageFilter::
GetVectorPath()
{
return m_VectorPath;
}
template
std::vector< std::vector< typename ShortestPathImageFilter::IndexType > >
ShortestPathImageFilter::
GetMultipleVectorPaths()
{
return m_MultipleVectorPaths;
}
template
void
ShortestPathImageFilter::
MakeShortestPathVector()
{
//MITK_INFO << "Make ShortestPath Vec";
// single end point
if ( !multipleEndPoints )
{
// fill m_VectorPath with the Shortest Path
m_VectorPath.clear();
// Go backwards from endnote to startnode
NodeNumType prevNode = m_Graph_EndNode;
while (prevNode != -1)
{
m_VectorPath.push_back( NodeToCoord(prevNode) );
if (prevNode == m_Graph_StartNode)
break;
prevNode = m_Nodes[prevNode].prevNode;
}
// reverse it
std::reverse(m_VectorPath.begin(), m_VectorPath.end() );
}
// Multiple end end points and pathes
else
{
for (int i=0; i
void
ShortestPathImageFilter::
CleanUp()
{
m_VectorOrder.clear();
m_VectorPath.clear();
//TODO: if multiple Path, clear all multiple Paths
if (m_Nodes)
delete [] m_Nodes;
}
template
void
ShortestPathImageFilter::
GenerateData()
{
// Build Graph
InitGraph();
// Calc Shortest Parth
StartShortestPathSearch();
// Fill Shortest Path
MakeShortestPathVector();
// Make Outputs
MakeOutputs();
}
template
void
ShortestPathImageFilter::
PrintSelf( std::ostream& os, Indent indent ) const
{
Superclass::PrintSelf(os,indent);
}
} /* end namespace itk */
-#endif
+#endif // __itkShortestPathImageFilter_txx
diff --git a/Modules/Segmentation/Algorithms/mitkContourModelSubDivisionFilter.cpp b/Modules/Segmentation/Algorithms/mitkContourModelSubDivisionFilter.cpp
index 2efb3fc92c..ab71af402d 100644
--- a/Modules/Segmentation/Algorithms/mitkContourModelSubDivisionFilter.cpp
+++ b/Modules/Segmentation/Algorithms/mitkContourModelSubDivisionFilter.cpp
@@ -1,217 +1,217 @@
/*===================================================================
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 "mitkContourModelSubDivisionFilter.h"
#include
#include
mitk::ContourModelSubDivisionFilter::ContourModelSubDivisionFilter()
{
OutputType::Pointer output = dynamic_cast ( this->MakeOutput( 0 ).GetPointer() );
this->SetNumberOfRequiredInputs(1);
- this->SetNumberOfOutputs( 1 );
+ this->SetNumberOfIndexedOutputs( 1 );
this->SetNthOutput(0, output.GetPointer());
this->m_InterpolationIterations = 4;
}
mitk::ContourModelSubDivisionFilter::~ContourModelSubDivisionFilter()
{
}
void mitk::ContourModelSubDivisionFilter::SetInput ( const mitk::ContourModelSubDivisionFilter::InputType* input )
{
this->SetInput( 0, input );
}
void mitk::ContourModelSubDivisionFilter::SetInput ( unsigned int idx, const mitk::ContourModelSubDivisionFilter::InputType* input )
{
if ( idx + 1 > this->GetNumberOfInputs() )
{
this->SetNumberOfRequiredInputs(idx + 1);
}
if ( input != static_cast ( this->ProcessObject::GetInput ( idx ) ) )
{
this->ProcessObject::SetNthInput ( idx, const_cast ( input ) );
this->Modified();
}
}
const mitk::ContourModelSubDivisionFilter::InputType* mitk::ContourModelSubDivisionFilter::GetInput( void )
{
if (this->GetNumberOfInputs() < 1)
return NULL;
return static_cast(this->ProcessObject::GetInput(0));
}
const mitk::ContourModelSubDivisionFilter::InputType* mitk::ContourModelSubDivisionFilter::GetInput( unsigned int idx )
{
if (this->GetNumberOfInputs() < 1)
return NULL;
return static_cast(this->ProcessObject::GetInput(idx));
}
void mitk::ContourModelSubDivisionFilter::GenerateData()
{
mitk::ContourModel::Pointer input = const_cast(this->GetInput(0));
mitk::ContourModelSubDivisionFilter::OutputType::Pointer outputContour = this->GetOutput();
mitk::ContourModel::Pointer contour(input);
unsigned int timestep = input->GetTimeSteps();
for ( int currentTimestep = 0; currentTimestep < timestep; currentTimestep++)
{
if( input->GetNumberOfVertices(currentTimestep) >= 4)
{
for( int iterations = 0; iterations < this->m_InterpolationIterations; iterations++)
{
InputType::VertexIterator it = contour->IteratorBegin();
InputType::VertexIterator end = contour->IteratorEnd();
InputType::VertexIterator first = contour->IteratorBegin();
InputType::VertexIterator last = contour->IteratorEnd()-1;
//tempory contour to store result of a subdivision iteration
mitk::ContourModel::Pointer tempContour = mitk::ContourModel::New();
//insert subpoints
while ( it != end )
{
//add the current point to the temp contour
tempContour->AddVertex((*it)->Coordinates, (*it)->IsControlPoint, currentTimestep);
//control points for interpolation
InputType::VertexIterator Ci = it;
InputType::VertexIterator CiPlus1;
InputType::VertexIterator CiPlus2;
InputType::VertexIterator CiMinus1;
//consider all possible cases
if( it == first)
{
if( input->IsClosed(currentTimestep) )
{
CiPlus1 = it + 1;
CiPlus2 = it + 2;
CiMinus1 = last;
}
else
{
CiPlus1 = it + 1;
CiPlus2 = it + 2;
CiMinus1 = it;
}
}
else if( it == last )
{
if( input->IsClosed(currentTimestep) )
{
CiPlus1 = first;
CiPlus2 = first + 1;
CiMinus1 = it -1;
}
else
{
//don't add point after last
break;
}
}
else if( it == (last - 1) )
{
if( input->IsClosed(currentTimestep) )
{
CiPlus1 = it + 1;
CiPlus2 = first;
CiMinus1 = it -1;
}
else
{
CiPlus1 = it + 1;
CiPlus2 = it + 1;
CiMinus1 = it -1;
}
}
else
{
CiPlus1 = it + 1;
CiPlus2 = it + 2;
CiMinus1 = it -1;
}
/* F2i = Ci
* F2i+1 = -1/16Ci-1 + 9/16Ci + 9/16Ci+1 - 1/16Ci+2
*/
mitk::Point3D subpoint;
mitk::Point3D a;
a[0]=(-1.0/16.0) * (*CiMinus1)->Coordinates[0];
a[1]=(-1.0/16.0) * (*CiMinus1)->Coordinates[1];
a[2]= (-1.0/16.0) * (*CiMinus1)->Coordinates[2];
mitk::Point3D b;
b[0]=(9.0/16.0) * (*Ci)->Coordinates[0];
b[1]=(9.0/16.0) * (*Ci)->Coordinates[1];
b[2]= (9.0/16.0) * (*Ci)->Coordinates[2];
mitk::Point3D c;
c[0]=(9.0/16.0) * (*CiPlus1)->Coordinates[0];
c[1]=(9.0/16.0) * (*CiPlus1)->Coordinates[1];
c[2]= (9.0/16.0) * (*CiPlus1)->Coordinates[2];
mitk::Point3D d;
d[0]=(-1.0/16.0) * (*CiPlus2)->Coordinates[0];
d[1]=(-1.0/16.0) * (*CiPlus2)->Coordinates[1];
d[2]= (-1.0/16.0) * (*CiPlus2)->Coordinates[2];
subpoint[0] = a[0] + b[0] + c[0] + d[0];
subpoint[1] = a[1] + b[1] + c[1] + d[1];
subpoint[2] = a[2] + b[2] + c[2] + d[2];
InputType::VertexType subdivisionPoint(subpoint,false);
//add the new subdivision point to our tempContour
tempContour->AddVertex(subdivisionPoint.Coordinates, currentTimestep);
it++;
}
//set the interpolated contour as the contour for the next iteration
contour = tempContour;
}
}
else
{
//filter not executeable - set input to output
contour = input;
}
}
//somehow the isClosed property is not set via copy constructor
contour->SetIsClosed(input->IsClosed());
this->SetOutput(0, contour);
}
diff --git a/Modules/Segmentation/Algorithms/mitkContourModelToSurfaceFilter.h b/Modules/Segmentation/Algorithms/mitkContourModelToSurfaceFilter.h
index 52ce1eef5b..0ffade6471 100644
--- a/Modules/Segmentation/Algorithms/mitkContourModelToSurfaceFilter.h
+++ b/Modules/Segmentation/Algorithms/mitkContourModelToSurfaceFilter.h
@@ -1,63 +1,63 @@
/*===================================================================
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 _MITK_CONTOURMODEL_TO_Surface_FILTER_H_
#define _MITK_CONTOURMODEL_TO_Surface_FILTER_H_
#include "mitkCommon.h"
#include "SegmentationExports.h"
#include "mitkContourModel.h"
#include "mitkContourModelSource.h"
#include
namespace mitk {
class Segmentation_EXPORT ContourModelToSurfaceFilter : public SurfaceSource
{
public:
/** Standard class typedefs. */
- mitkClassMacro( ContourModelToSurfaceFilter,BaseProcess );
+ mitkClassMacro( ContourModelToSurfaceFilter, SurfaceSource );
/** Method for creation through the object factory. */
itkNewMacro(Self);
typedef mitk::Surface OutputType;
typedef mitk::ContourModel InputType;
/** Set/Get the image input of this process object. */
virtual void SetInput( const InputType *input);
virtual void SetInput( unsigned int idx, const InputType * input);
const InputType * GetInput(void);
const InputType * GetInput(unsigned int idx);
protected:
ContourModelToSurfaceFilter();
~ContourModelToSurfaceFilter();
virtual void GenerateData();
};
}
#endif
diff --git a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp
index 69094bfa56..c2e422c56f 100644
--- a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp
+++ b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp
@@ -1,416 +1,444 @@
/*===================================================================
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 "mitkImageLiveWireContourModelFilter.h"
#include
#include
#include
+#include "mitkIOUtil.h"
mitk::ImageLiveWireContourModelFilter::ImageLiveWireContourModelFilter()
{
OutputType::Pointer output = dynamic_cast ( this->MakeOutput( 0 ).GetPointer() );
this->SetNumberOfRequiredInputs(1);
- this->SetNumberOfOutputs( 1 );
+ this->SetNumberOfIndexedOutputs( 1 );
this->SetNthOutput(0, output.GetPointer());
- m_CostFunction = ImageLiveWireContourModelFilter::CostFunctionType::New();
+ m_CostFunction = CostFunctionType::New();
m_ShortestPathFilter = ShortestPathImageFilterType::New();
m_ShortestPathFilter->SetCostFunction(m_CostFunction);
m_UseDynamicCostMap = false;
- m_ImageModified = false;
- m_Timestep = 0;
+ m_TimeStep = 0;
}
mitk::ImageLiveWireContourModelFilter::~ImageLiveWireContourModelFilter()
{
-
}
-
mitk::ImageLiveWireContourModelFilter::OutputType* mitk::ImageLiveWireContourModelFilter::GetOutput()
{
return Superclass::GetOutput();
}
void mitk::ImageLiveWireContourModelFilter::SetInput ( const mitk::ImageLiveWireContourModelFilter::InputType* input )
{
this->SetInput( 0, input );
}
void mitk::ImageLiveWireContourModelFilter::SetInput ( unsigned int idx, const mitk::ImageLiveWireContourModelFilter::InputType* input )
{
if ( idx + 1 > this->GetNumberOfInputs() )
{
this->SetNumberOfRequiredInputs(idx + 1);
}
if ( input != static_cast ( this->ProcessObject::GetInput ( idx ) ) )
{
this->ProcessObject::SetNthInput ( idx, const_cast ( input ) );
this->Modified();
- this->m_ImageModified = true;
- m_ShortestPathFilter = ShortestPathImageFilterType::New();
- m_ShortestPathFilter->SetCostFunction(m_CostFunction);
+
+ AccessFixedDimensionByItk(input, ItkPreProcessImage, 2);
}
}
-
-
const mitk::ImageLiveWireContourModelFilter::InputType* mitk::ImageLiveWireContourModelFilter::GetInput( void )
{
if (this->GetNumberOfInputs() < 1)
return NULL;
return static_cast(this->ProcessObject::GetInput(0));
}
-
const mitk::ImageLiveWireContourModelFilter::InputType* mitk::ImageLiveWireContourModelFilter::GetInput( unsigned int idx )
{
if (this->GetNumberOfInputs() < 1)
return NULL;
return static_cast(this->ProcessObject::GetInput(idx));
}
-
void mitk::ImageLiveWireContourModelFilter::GenerateData()
{
mitk::Image::ConstPointer input = dynamic_cast(this->GetInput());
if(!input)
{
MITK_ERROR << "No input available.";
itkExceptionMacro("mitk::ImageToLiveWireContourFilter: No input available. Please set the input!");
return;
}
if( input->GetDimension() != 2 )
{
MITK_ERROR << "Filter is only working on 2D images.";
itkExceptionMacro("mitk::ImageToLiveWireContourFilter: Filter is only working on 2D images.. Please make sure that the input is 2D!");
return;
}
-
input->GetGeometry()->WorldToIndex(m_StartPoint, m_StartPointInIndex);
input->GetGeometry()->WorldToIndex(m_EndPoint, m_EndPointInIndex);
//only start calculating if both indices are inside image geometry
if( input->GetGeometry()->IsIndexInside(this->m_StartPointInIndex) && input->GetGeometry()->IsIndexInside(this->m_EndPointInIndex) )
{
- AccessFixedDimensionByItk(input, ItkProcessImage, 2);
- m_ImageModified = false;
+ try
+ {
+ this->UpdateLiveWire();
+ }
+ catch( itk::ExceptionObject & e )
+ {
+ MITK_INFO << "Exception caught during live wiring calculation: " << e;
+ return;
+ }
}
}
-
template
-void mitk::ImageLiveWireContourModelFilter::ItkProcessImage (itk::Image* inputImage)
+void mitk::ImageLiveWireContourModelFilter::ItkPreProcessImage (itk::Image* inputImage)
+{
+ typedef itk::Image< TPixel, VImageDimension > InputImageType;
+ typedef itk::CastImageFilter< InputImageType, InternalImageType > CastFilterType;
+
+ typename CastFilterType::Pointer castFilter = CastFilterType::New();
+ castFilter->SetInput(inputImage);
+ castFilter->Update();
+ m_InternalImage = castFilter->GetOutput();
+ m_CostFunction->SetImage( m_InternalImage );
+ m_ShortestPathFilter->SetInput( m_InternalImage );
+}
+
+void mitk::ImageLiveWireContourModelFilter::ClearRepulsivePoints()
+{
+ m_CostFunction->ClearRepulsivePoints();
+}
+
+void mitk::ImageLiveWireContourModelFilter::AddRepulsivePoint( const itk::Index<2>& idx )
+{
+ m_CostFunction->AddRepulsivePoint(idx);
+}
+
+void mitk::ImageLiveWireContourModelFilter::DumpMaskImage()
{
- typedef itk::Image< TPixel, VImageDimension > InputImageType;
- typedef typename InputImageType::IndexType IndexType;
+ mitk::Image::Pointer mask = mitk::Image::New();
+ mask->InitializeByItk( this->m_CostFunction->GetMaskImage() );
+ mask->SetVolume( this->m_CostFunction->GetMaskImage()->GetBufferPointer() );
+ mitk::IOUtil::SaveImage(mask, "G:\\Data\\mask.nrrd");
+/*
+ mitk::Image::Pointer slice = mitk::Image::New();
+ slice->InitializeByItk( this->m_CostFunction->m_MaskImage.GetPointer() );
+ slice->SetVolume(this->m_CostFunction->m_MaskImage->GetBufferPointer());
+ */
+}
- /* compute the requested region for itk filters */
+void mitk::ImageLiveWireContourModelFilter::RemoveRepulsivePoint( const itk::Index<2>& idx )
+{
+ m_CostFunction->RemoveRepulsivePoint(idx);
+}
- IndexType startPoint, endPoint;
+void mitk::ImageLiveWireContourModelFilter::SetRepulsivePoints(const ShortestPathType& points)
+{
+ m_CostFunction->ClearRepulsivePoints();
+
+ ShortestPathType::const_iterator iter = points.begin();
+ for (;iter != points.end(); iter++)
+ {
+ m_CostFunction->AddRepulsivePoint( (*iter) );
+ }
+}
+
+void mitk::ImageLiveWireContourModelFilter::UpdateLiveWire()
+{
+// compute the requested region for itk filters
+ InternalImageType::IndexType startPoint, endPoint;
startPoint[0] = m_StartPointInIndex[0];
startPoint[1] = m_StartPointInIndex[1];
endPoint[0] = m_EndPointInIndex[0];
endPoint[1] = m_EndPointInIndex[1];
- //minimum value in each direction for startRegion
- IndexType startRegion;
+ // minimum value in each direction for startRegion
+ InternalImageType::IndexType startRegion;
startRegion[0] = startPoint[0] < endPoint[0] ? startPoint[0] : endPoint[0];
startRegion[1] = startPoint[1] < endPoint[1] ? startPoint[1] : endPoint[1];
- //maximum value in each direction for size
- typename InputImageType::SizeType size;
- size[0] = abs( startPoint[0] - endPoint[0] );
- size[1] = abs( startPoint[1] - endPoint[1] );
-
+ // maximum value in each direction for size
+ InternalImageType::SizeType size;
+ size[0] = abs( startPoint[0] - endPoint[0] ) + 1;
+ size[1] = abs( startPoint[1] - endPoint[1] ) + 1;
- typename CostFunctionType::RegionType region;
+ CostFunctionType::RegionType region;
region.SetSize( size );
region.SetIndex( startRegion );
- /*---------------------------------------------*/
//inputImage->SetRequestedRegion(region);
- typedef itk::CastImageFilter< InputImageType, FloatImageType > CastFilterType;
- typename CastFilterType::Pointer castFilter = CastFilterType::New();
- castFilter->SetInput(inputImage);
- castFilter->Update();
- /* extracts features from image and calculates costs */
- if( m_ImageModified )
- m_CostFunction->SetImage(castFilter->GetOutput());
+ // extracts features from image and calculates costs
+ //m_CostFunction->SetImage(m_InternalImage);
m_CostFunction->SetStartIndex(startPoint);
m_CostFunction->SetEndIndex(endPoint);
m_CostFunction->SetRequestedRegion(region);
m_CostFunction->SetUseCostMap(m_UseDynamicCostMap);
- /*---------------------------------------------*/
-
- /* calculate shortest path between start and end point */
+ // calculate shortest path between start and end point
m_ShortestPathFilter->SetFullNeighborsMode(true);
- m_ShortestPathFilter->SetInput(castFilter->GetOutput());
+ //m_ShortestPathFilter->SetInput( m_CostFunction->SetImage(m_InternalImage) );
m_ShortestPathFilter->SetMakeOutputImage(false);
//m_ShortestPathFilter->SetCalcAllDistances(true);
m_ShortestPathFilter->SetStartIndex(startPoint);
m_ShortestPathFilter->SetEndIndex(endPoint);
-
m_ShortestPathFilter->Update();
- /*---------------------------------------------*/
-
-
- /* construct contour from path image */
+ // construct contour from path image
//get the shortest path as vector
- typename std::vector< ShortestPathImageFilterType::IndexType> shortestPath = m_ShortestPathFilter->GetVectorPath();
+ ShortestPathType shortestPath = m_ShortestPathFilter->GetVectorPath();
- //fill the output contour with controll points from the path
+ //fill the output contour with control points from the path
OutputType::Pointer output = dynamic_cast ( this->MakeOutput( 0 ).GetPointer() );
this->SetNthOutput(0, output.GetPointer());
- output->Expand(m_Timestep+1);
+// OutputType::Pointer output = dynamic_cast ( this->GetOutput() );
+ output->Expand(m_TimeStep+1);
+
+// output->Clear();
mitk::Image::ConstPointer input = dynamic_cast(this->GetInput());
- typename std::vector< ShortestPathImageFilterType::IndexType>::iterator pathIterator = shortestPath.begin();
+ ShortestPathType::const_iterator pathIterator = shortestPath.begin();
while(pathIterator != shortestPath.end())
{
mitk::Point3D currentPoint;
- currentPoint[0] = (*pathIterator)[0];
- currentPoint[1] = (*pathIterator)[1];
- currentPoint[2] = 0;
-
+ currentPoint[0] = static_cast( (*pathIterator)[0] );
+ currentPoint[1] = static_cast( (*pathIterator)[1] );
+ currentPoint[2] = 0.0;
input->GetGeometry()->IndexToWorld(currentPoint, currentPoint);
- output->AddVertex(currentPoint, false, m_Timestep);
+ output->AddVertex(currentPoint, false, m_TimeStep);
pathIterator++;
}
- /*---------------------------------------------*/
}
+
bool mitk::ImageLiveWireContourModelFilter::CreateDynamicCostMap(mitk::ContourModel* path)
{
mitk::Image::ConstPointer input = dynamic_cast(this->GetInput());
- if(input)
+ if(!input) return false;
+
+ try
{
AccessFixedDimensionByItk_1(input,CreateDynamicCostMapByITK, 2, path);
- return true;
}
- else
+ catch( itk::ExceptionObject & e )
{
+ MITK_INFO << "Exception caught during dynamic cost map alculation: " << e;
return false;
}
-}
-
+ return true;
+}
template
void mitk::ImageLiveWireContourModelFilter::CreateDynamicCostMapByITK( itk::Image* inputImage, mitk::ContourModel* path )
{
/*++++++++++ create dynamic cost transfer map ++++++++++*/
/* Compute the costs of the gradient magnitude dynamically.
* using a map of the histogram of gradient magnitude image.
* Use the histogram gradient map to interpolate the costs
* with gaussing function including next two bins right and left
* to current position x. With the histogram gradient costs are interpolated
* with a gaussing function summation of next two bins right and left
* to current position x.
*/
std::vector< itk::Index > shortestPath;
mitk::Image::ConstPointer input = dynamic_cast(this->GetInput());
if(path == NULL)
{
OutputType::Pointer output = this->GetOutput();
mitk::ContourModel::VertexIterator it = output->IteratorBegin();
while( it != output->IteratorEnd() )
{
itk::Index cur;
mitk::Point3D c = (*it)->Coordinates;
input->GetGeometry()->WorldToIndex(c, c);
cur[0] = c[0];
cur[1] = c[1];
shortestPath.push_back( cur);
it++;
}
}
else
{
mitk::ContourModel::VertexIterator it = path->IteratorBegin();
while( it != path->IteratorEnd() )
{
itk::Index cur;
mitk::Point3D c = (*it)->Coordinates;
input->GetGeometry()->WorldToIndex(c, c);
cur[0] = c[0];
cur[1] = c[1];
shortestPath.push_back( cur);
it++;
}
}
-
- /*+++ filter image gradient magnitude +++*/
+ // filter image gradient magnitude
typedef itk::GradientMagnitudeImageFilter< itk::Image, itk::Image > GradientMagnitudeFilterType;
typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New();
gradientFilter->SetInput(inputImage);
gradientFilter->Update();
typename itk::Image::Pointer gradientMagnImage = gradientFilter->GetOutput();
//get the path
-
//iterator of path
typename std::vector< itk::Index >::iterator pathIterator = shortestPath.begin();
std::map< int, int > histogram;
//create histogram within path
while(pathIterator != shortestPath.end())
{
//count pixel values
//use scale factor to avoid mapping gradients between 0.0 and 1.0 to same bin
histogram[ static_cast( gradientMagnImage->GetPixel((*pathIterator)) * ImageLiveWireContourModelFilter::CostFunctionType::MAPSCALEFACTOR ) ] += 1;
pathIterator++;
}
double max = 1.0;
if( !histogram.empty() )
{
-
std::map< int, int >::iterator itMAX;
//get max of histogramm
int currentMaxValue = 0;
std::map< int, int >::iterator it = histogram.begin();
while( it != histogram.end())
{
if((*it).second > currentMaxValue)
{
itMAX = it;
currentMaxValue = (*it).second;
}
it++;
}
-
std::map< int, int >::key_type keyOfMax = itMAX->first;
-
- /*+++++++++++++++++++++++++ compute the to max of gaussian summation ++++++++++++++++++++++++*/
+ // compute the to max of gaussian summation
std::map< int, int >::iterator end = histogram.end();
std::map< int, int >::iterator last = --(histogram.end());
std::map< int, int >::iterator left2;
std::map< int, int >::iterator left1;
std::map< int, int >::iterator right1;
std::map< int, int >::iterator right2;
right1 = itMAX;
-
if(right1 == end || right1 == last )
{
right2 = end;
}
else//( right1 <= last )
{
std::map< int, int >::iterator temp = right1;
right2 = ++right1;//rght1 + 1
right1 = temp;
}
-
if( right1 == histogram.begin() )
{
left1 = end;
left2 = end;
}
else if( right1 == (++(histogram.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 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, left2->first, left2->second);
}
if( left1 != end )
{
partLeft1 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, left1->first, left1->second);
}
if( right1 != end )
{
partRight1 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, right1->first, right1->second);
}
if( right2 != end )
{
partRight2 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, right2->first, right2->second);
}
- /*----------------------------------------------------------------------------*/
max = (partRight1 + partRight2 + partLeft1 + partLeft2);
}
this->m_CostFunction->SetDynamicCostMap(histogram);
this->m_CostFunction->SetCostMapMaximum(max);
-
}
diff --git a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.h b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.h
index 74ff4fa4e8..8d546ecc8e 100644
--- a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.h
+++ b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.h
@@ -1,153 +1,166 @@
/*===================================================================
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 _mitkImageLiveWireContourModelFilter_h__
#define _mitkImageLiveWireContourModelFilter_h__
#include "mitkCommon.h"
#include "SegmentationExports.h"
#include "mitkContourModel.h"
#include "mitkContourModelSource.h"
#include
#include
#include
#include
#include
namespace mitk {
/**
\brief Calculates a LiveWire contour between two points in an image.
For defining costs between two pixels specific features are extraced from the image and tranformed into a single cost value.
\sa ShortestPathCostFunctionLiveWire
The filter is able to create dynamic cost tranfer map and thus use on the fly training.
\Note On the fly training will only be used for next update.
The computation uses the last calculated segment to map cost according to features in the area of the segment.
For time resolved purposes use ImageLiveWireContourModelFilter::SetTimestep( unsigned int ) to create the LiveWire contour
at a specific timestep.
\ingroup ContourModelFilters
\ingroup Process
*/
class Segmentation_EXPORT ImageLiveWireContourModelFilter : public ContourModelSource
{
public:
mitkClassMacro(ImageLiveWireContourModelFilter, ContourModelSource);
itkNewMacro(Self);
-
typedef ContourModel OutputType;
typedef OutputType::Pointer OutputTypePointer;
typedef mitk::Image InputType;
- typedef itk::Image< float, 2 > FloatImageType;
- typedef itk::ShortestPathImageFilter< FloatImageType, FloatImageType > ShortestPathImageFilterType;
- typedef itk::ShortestPathCostFunctionLiveWire< FloatImageType > CostFunctionType;
-
+ typedef itk::Image< float, 2 > InternalImageType;
+ typedef itk::ShortestPathImageFilter< InternalImageType, InternalImageType > ShortestPathImageFilterType;
+ typedef itk::ShortestPathCostFunctionLiveWire< InternalImageType > CostFunctionType;
+ typedef std::vector< itk::Index<2> > ShortestPathType;
- /** \brief start point in worldcoordinates*/
+ /** \brief start point in world coordinates*/
itkSetMacro(StartPoint, mitk::Point3D);
itkGetMacro(StartPoint, mitk::Point3D);
- /** \brief end point in woorldcoordinates*/
+ /** \brief end point in woorld coordinates*/
itkSetMacro(EndPoint, mitk::Point3D);
itkGetMacro(EndPoint, mitk::Point3D);
/** \brief Create dynamic cost tranfer map - use on the fly training.
\Note On the fly training will be used for next update only.
The computation uses the last calculated segment to map cost according to features in the area of the segment.
*/
itkSetMacro(UseDynamicCostMap, bool);
itkGetMacro(UseDynamicCostMap, bool);
+ /** \brief Actual time step
+ */
+ itkSetMacro(TimeStep, unsigned int);
+ itkGetMacro(TimeStep, unsigned int);
+
+ /** \brief Clear all repulsive points used in the cost function
+ */
+ void ClearRepulsivePoints();
+
+ /** \brief Set a vector with repulsive points to use in the cost function
+ */
+ void SetRepulsivePoints(const ShortestPathType& points);
+
+ /** \brief Add a single repulsive point to the cost function
+ */
+ void AddRepulsivePoint( const itk::Index<2>& idx );
+
+ /** \brief Remove a single repulsive point from the cost function
+ */
+ void RemoveRepulsivePoint( const itk::Index<2>& idx );
virtual void SetInput( const InputType *input);
virtual void SetInput( unsigned int idx, const InputType * input);
const InputType* GetInput(void);
const InputType* GetInput(unsigned int idx);
virtual OutputType* GetOutput();
+ virtual void DumpMaskImage();
/** \brief Create dynamic cost tranfer map - on the fly training*/
bool CreateDynamicCostMap(mitk::ContourModel* path=NULL);
- void SetTimestep( unsigned int timestep )
- {
- m_Timestep = timestep;
- }
-
- unsigned int GetTimestep()
- {
- return m_Timestep;
- }
-
protected:
ImageLiveWireContourModelFilter();
virtual ~ImageLiveWireContourModelFilter();
void GenerateOutputInformation() {};
void GenerateData();
+ void UpdateLiveWire();
+
/** \brief start point in worldcoordinates*/
mitk::Point3D m_StartPoint;
/** \brief end point in woorldcoordinates*/
mitk::Point3D m_EndPoint;
/** \brief Start point in index*/
mitk::Point3D m_StartPointInIndex;
/** \brief End point in index*/
mitk::Point3D m_EndPointInIndex;
/** \brief The cost function to compute costs between two pixels*/
CostFunctionType::Pointer m_CostFunction;
/** \brief Shortest path filter according to cost function m_CostFunction*/
ShortestPathImageFilterType::Pointer m_ShortestPathFilter;
/** \brief Flag to use a dynmic cost map or not*/
bool m_UseDynamicCostMap;
- bool m_ImageModified;
-
- unsigned int m_Timestep;
+ unsigned int m_TimeStep;
template
- void ItkProcessImage (itk::Image* inputImage);
+ void ItkPreProcessImage (itk::Image* inputImage);
template
void CreateDynamicCostMapByITK(itk::Image* inputImage, mitk::ContourModel* path=NULL);
+
+ InternalImageType::Pointer m_InternalImage;
+
};
}
#endif
diff --git a/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.cpp b/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.cpp
index a9b7a18f0d..9a85d4c4c9 100644
--- a/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.cpp
+++ b/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.cpp
@@ -1,194 +1,194 @@
/*===================================================================
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 "mitkImageToLiveWireContourFilter.h"
#include
#include
#include
mitk::ImageToLiveWireContourFilter::ImageToLiveWireContourFilter()
{
OutputType::Pointer output = dynamic_cast ( this->MakeOutput( 0 ).GetPointer() );
this->SetNumberOfRequiredInputs(1);
- this->SetNumberOfOutputs( 1 );
+ this->SetNumberOfIndexedOutputs( 1 );
this->SetNthOutput(0, output.GetPointer());
}
mitk::ImageToLiveWireContourFilter::~ImageToLiveWireContourFilter()
{
}
void mitk::ImageToLiveWireContourFilter::SetInput ( const mitk::ImageToLiveWireContourFilter::InputType* input )
{
this->SetInput( 0, input );
}
void mitk::ImageToLiveWireContourFilter::SetInput ( unsigned int idx, const mitk::ImageToLiveWireContourFilter::InputType* input )
{
if ( idx + 1 > this->GetNumberOfInputs() )
{
this->SetNumberOfRequiredInputs(idx + 1);
}
if ( input != static_cast ( this->ProcessObject::GetInput ( idx ) ) )
{
this->ProcessObject::SetNthInput ( idx, const_cast ( input ) );
this->Modified();
}
}
const mitk::ImageToLiveWireContourFilter::InputType* mitk::ImageToLiveWireContourFilter::GetInput( void )
{
if (this->GetNumberOfInputs() < 1)
return NULL;
return static_cast(this->ProcessObject::GetInput(0));
}
const mitk::ImageToLiveWireContourFilter::InputType* mitk::ImageToLiveWireContourFilter::GetInput( unsigned int idx )
{
if (this->GetNumberOfInputs() < 1)
return NULL;
return static_cast(this->ProcessObject::GetInput(idx));
}
void mitk::ImageToLiveWireContourFilter::GenerateData()
{
mitk::Image::ConstPointer input = dynamic_cast(this->GetInput());
if(!input)
{
MITK_ERROR << "No input available.";
itkExceptionMacro("mitk::ImageToLiveWireContourFilter: No input available. Please set the input!");
return;
}
if( input->GetDimension() != 2 )
{
MITK_ERROR << "Filter is only working on 2D images.";
itkExceptionMacro("mitk::ImageToLiveWireContourFilter: Filter is only working on 2D images.. Please make sure that the input is 2D!");
return;
}
input->GetGeometry()->WorldToIndex(m_StartPoint, m_StartPointInIndex);
input->GetGeometry()->WorldToIndex(m_EndPoint, m_EndPointInIndex);
AccessFixedDimensionByItk(input, ItkProcessImage, 2);
}
template
void mitk::ImageToLiveWireContourFilter::ItkProcessImage (itk::Image* inputImage)
{
//typedef itk::Image< TPixel, VImageDimension > InputImageType;
//typedef itk::Image< float, 2 > FloatImageType;
//typedef typename itk::ShortestPathImageFilter< InputImageType, InputImageType > ShortestPathImageFilterType;
//typedef typename itk::ShortestPathCostFunctionLiveWire< InputImageType > CostFunctionType;
//typedef InputImageType::IndexType IndexType;
///* compute the requested region for itk filters */
//typename IndexType startPoint, endPoint;
//
//startPoint[0] = m_StartPointInIndex[0];
//startPoint[1] = m_StartPointInIndex[1];
//endPoint[0] = m_EndPointInIndex[0];
//endPoint[1] = m_EndPointInIndex[1];
////minimum value in each direction for startRegion
//typename IndexType startRegion;
//startRegion[0] = startPoint[0] < endPoint[0] ? startPoint[0] : endPoint[0];
//startRegion[1] = startPoint[1] < endPoint[1] ? startPoint[1] : endPoint[1];
////maximum value in each direction for size
//typename InputImageType::SizeType size;
//size[0] = startPoint[0] > endPoint[0] ? startPoint[0] : endPoint[0];
//size[1] = startPoint[1] > endPoint[1] ? startPoint[1] : endPoint[1];
//typename InputImageType::RegionType region;
//region.SetSize( size );
//region.SetIndex( startRegion );
///*---------------------------------------------*/
///* extracts features from image and calculates costs */
//typename CostFunctionType::Pointer costFunction = CostFunctionType::New();
//costFunction->SetImage(inputImage);
//costFunction->SetStartIndex(startPoint);
//costFunction->SetEndIndex(endPoint);
//costFunction->SetRequestedRegion(region);
///*---------------------------------------------*/
///* calculate shortest path between start and end point */
//ShortestPathImageFilterType::Pointer shortestPathFilter = ShortestPathImageFilterType::New();
//shortestPathFilter->SetFullNeighborsMode(true);
//shortestPathFilter->SetInput(inputImage);
//shortestPathFilter->SetMakeOutputImage(true);
//shortestPathFilter->SetStoreVectorOrder(false);
////shortestPathFilter->SetActivateTimeOut(true);
//shortestPathFilter->SetStartIndex(startPoint);
//shortestPathFilter->SetEndIndex(endPoint);
//shortestPathFilter->Update();
///*---------------------------------------------*/
///* construct contour from path image */
////get the shortest path as vector
//std::vector< itk::Index<3> > shortestPath = shortestPathFilter->GetVectorPath();
////fill the output contour with controll points from the path
//OutputType::Pointer outputContour = this->GetOutput();
//mitk::Image::ConstPointer input = dynamic_cast(this->GetInput());
//std::vector< itk::Index<3> >::iterator pathIterator = shortestPath.begin();
//while(pathIterator != shortestPath.end())
//{
// mitk::Point3D currentPoint;
// currentPoint[0] = (*pathIterator)[0];
// currentPoint[1] = (*pathIterator)[1];
// input->GetGeometry(0)->IndexToWorld(currentPoint, currentPoint);
// outputContour->AddVertex(currentPoint);
//
// pathIterator++;
//}
/*---------------------------------------------*/
}
diff --git a/Modules/Segmentation/DataManagement/mitkContourElement.cpp b/Modules/Segmentation/DataManagement/mitkContourElement.cpp
index 747103e930..552cbac83f 100644
--- a/Modules/Segmentation/DataManagement/mitkContourElement.cpp
+++ b/Modules/Segmentation/DataManagement/mitkContourElement.cpp
@@ -1,345 +1,468 @@
/*===================================================================
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
+#include
+#include
mitk::ContourElement::ContourElement()
{
this->m_Vertices = new VertexListType();
this->m_IsClosed = false;
}
mitk::ContourElement::ContourElement(const mitk::ContourElement &other) :
m_Vertices(other.m_Vertices), m_IsClosed(other.m_IsClosed)
{
}
mitk::ContourElement::~ContourElement()
{
delete this->m_Vertices;
}
void mitk::ContourElement::AddVertex(mitk::Point3D &vertex, bool isControlPoint)
{
this->m_Vertices->push_back(new VertexType(vertex, isControlPoint));
}
void mitk::ContourElement::AddVertex(VertexType &vertex)
{
this->m_Vertices->push_back(&vertex);
}
void mitk::ContourElement::AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint)
{
this->m_Vertices->push_front(new VertexType(vertex, isControlPoint));
}
void mitk::ContourElement::AddVertexAtFront(VertexType &vertex)
{
this->m_Vertices->push_front(&vertex);
}
void mitk::ContourElement::InsertVertexAtIndex(mitk::Point3D &vertex, bool isControlPoint, int index)
{
if(index > 0 && this->GetSize() > index)
{
VertexIterator _where = this->m_Vertices->begin();
_where += index;
this->m_Vertices->insert(_where, new VertexType(vertex, isControlPoint));
}
}
mitk::ContourElement::VertexType* mitk::ContourElement::GetVertexAt(int index)
{
return this->m_Vertices->at(index);
}
+bool mitk::ContourElement::IsEmpty()
+{
+ return this->m_Vertices->empty();
+}
mitk::ContourElement::VertexType* mitk::ContourElement::GetVertexAt(const mitk::Point3D &point, float eps)
{
/* current version iterates over the whole deque - should some kind of an octree with spatial query*/
if(eps > 0)
{
//currently no method with better performance is available
return BruteForceGetVertexAt(point, eps);
}//if eps < 0
return NULL;
}
mitk::ContourElement::VertexType* mitk::ContourElement::BruteForceGetVertexAt(const mitk::Point3D &point, float eps)
{
if(eps > 0)
{
std::deque< std::pair > nearestlist;
ConstVertexIterator it = this->m_Vertices->begin();
ConstVertexIterator end = this->m_Vertices->end();
while(it != end)
{
mitk::Point3D currentPoint = (*it)->Coordinates;
double distance = currentPoint.EuclideanDistanceTo(point);
if(distance < eps)
{
//if list is emtpy, add point to list
if(nearestlist.size() < 1)
{
nearestlist.push_front(std::pair( (*it)->Coordinates.EuclideanDistanceTo(point), (*it) ));
}
//found an approximate point - check if current is closer then first in nearestlist
else if( distance < nearestlist.front().first )
{
//found even closer vertex
nearestlist.push_front(std::pair( (*it)->Coordinates.EuclideanDistanceTo(point), (*it) ));
}
}//if distance > eps
it++;
}//while
if(nearestlist.size() > 0)
{
/*++++++++++++++++++++ return the nearest active point if one was found++++++++++++++++++*/
std::deque< std::pair >::iterator it = nearestlist.begin();
std::deque< std::pair >::iterator end = nearestlist.end();
while(it != end)
{
if( (*it).second->IsControlPoint )
{
return (*it).second;
}
it++;
}
/*---------------------------------------------------------------------------------------*/
//return closest point
return nearestlist.front().second;
}
}
return NULL;
}
mitk::ContourElement::VertexType* mitk::ContourElement::OptimizedGetVertexAt(const mitk::Point3D &point, float eps)
{
if( (eps > 0) && (this->m_Vertices->size()>0) )
{
int k = 1;
int dim = 3;
int nPoints = this->m_Vertices->size();
ANNpointArray pointsArray;
ANNpoint queryPoint;
ANNidxArray indexArray;
ANNdistArray distanceArray;
ANNkd_tree* kdTree;
queryPoint = annAllocPt(dim);
pointsArray = annAllocPts(nPoints, dim);
indexArray = new ANNidx[k];
distanceArray = new ANNdist[k];
int i = 0;
//fill points array with our control points
for(VertexIterator it = this->m_Vertices->begin(); it != this->m_Vertices->end(); it++, i++)
{
mitk::Point3D cur = (*it)->Coordinates;
pointsArray[i][0]= cur[0];
pointsArray[i][1]= cur[1];
pointsArray[i][2]= cur[2];
}
//create the kd tree
kdTree = new ANNkd_tree(pointsArray,nPoints, dim);
//fill mitk::Point3D into ANN query point
queryPoint[0] = point[0];
queryPoint[1] = point[1];
queryPoint[2] = point[2];
//k nearest neighbour search
kdTree->annkSearch(queryPoint, k, indexArray, distanceArray, eps);
VertexType* ret = NULL;
try
{
ret = this->m_Vertices->at(indexArray[0]);
}
catch(std::out_of_range ex)
{
//ret stays NULL
return ret;
}
//clean up ANN
delete [] indexArray;
delete [] distanceArray;
delete kdTree;
annClose();
return ret;
}
return NULL;
}
mitk::ContourElement::VertexListType* mitk::ContourElement::GetVertexList()
{
return this->m_Vertices;
}
bool mitk::ContourElement::IsClosed()
{
return this->m_IsClosed;
}
+bool mitk::ContourElement::IsNearContour(const mitk::Point3D &point, float eps)
+{
+ ConstVertexIterator it1 = this->m_Vertices->begin();
+ ConstVertexIterator it2 = this->m_Vertices->begin();
+ it2 ++; // it2 runs one position ahead
+
+ ConstVertexIterator end = this->m_Vertices->end();
+
+ int counter = 0;
+
+ for (; it1 != end; it1++, it2++, counter++)
+ {
+ if (it2 == end)
+ it2 = this->m_Vertices->begin();
+
+ mitk::Point3D v1 = (*it1)->Coordinates;
+ mitk::Point3D v2 = (*it2)->Coordinates;
+
+ const float l2 = v1.SquaredEuclideanDistanceTo(v2);
+
+ mitk::Vector3D p_v1 = point - v1;
+ mitk::Vector3D v2_v1 = v2 - v1;
+
+ double tc = (p_v1 * v2_v1) / l2;
+
+ // take into account we have line segments and not (infinite) lines
+ if (tc < 0.0) tc = 0.0;
+ if (tc > 1.0) tc = 1.0;
+
+ mitk::Point3D crossPoint = v1 + v2_v1 * tc;
+
+ double distance = point.SquaredEuclideanDistanceTo(crossPoint);
+
+ if (distance < eps)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
void mitk::ContourElement::Close()
{
this->m_IsClosed = true;
}
void mitk::ContourElement::Open()
{
this->m_IsClosed = false;
}
void mitk::ContourElement::SetIsClosed( bool isClosed)
{
isClosed ? this->Close() : this->Open();
}
+mitk::ContourElement::VertexListType*
+mitk::ContourElement::GetControlVertices()
+{
+ VertexListType* newVertices = new VertexListType();
+
+ VertexIterator it = this->m_Vertices->begin();
+ VertexIterator end = this->m_Vertices->end();
+
+ while(it != end)
+ {
+ if((*it)->IsControlPoint)
+ {
+ newVertices->push_back((*it));
+ }
+ it++;
+ }
+ return newVertices;
+}
-void mitk::ContourElement::Concatenate(mitk::ContourElement* other)
+void mitk::ContourElement::Concatenate(mitk::ContourElement* other, bool check)
{
if( other->GetSize() > 0)
{
- ConstVertexIterator it = other->m_Vertices->begin();
- ConstVertexIterator end = other->m_Vertices->end();
- //add all vertices of other after last vertex
- while(it != end)
+ ConstVertexIterator otherIt = other->m_Vertices->begin();
+ ConstVertexIterator otherEnd = other->m_Vertices->end();
+ while(otherIt != otherEnd)
{
- this->m_Vertices->push_back(*it);
- it++;
+ if (check)
+ {
+ ConstVertexIterator thisIt = this->m_Vertices->begin();
+ ConstVertexIterator thisEnd = this->m_Vertices->end();
+
+ bool found = false;
+ while(thisIt != thisEnd)
+ {
+ if ( (*thisIt)->Coordinates == (*otherIt)->Coordinates )
+ {
+ found = true;
+ break;
+ }
+
+ thisIt++;
+ }
+ if (!found)
+ this->m_Vertices->push_back(*otherIt);
+ }
+ else
+ {
+ this->m_Vertices->push_back(*otherIt);
+ }
+ otherIt++;
}
}
}
-
-
bool mitk::ContourElement::RemoveVertex(mitk::ContourElement::VertexType* vertex)
{
VertexIterator it = this->m_Vertices->begin();
VertexIterator end = this->m_Vertices->end();
//search for vertex and remove it if exists
while(it != end)
{
if((*it) == vertex)
{
this->m_Vertices->erase(it);
return true;
}
it++;
}
return false;
}
bool mitk::ContourElement::RemoveVertexAt(int index)
{
if( index >= 0 && index < this->m_Vertices->size() )
{
this->m_Vertices->erase(this->m_Vertices->begin()+index);
return true;
}
else
{
return false;
}
}
bool mitk::ContourElement::RemoveVertexAt(mitk::Point3D &point, float eps)
{
/* current version iterates over the whole deque - should be some kind of an octree with spatial query*/
if(eps > 0){
VertexIterator it = this->m_Vertices->begin();
VertexIterator end = this->m_Vertices->end();
while(it != end)
{
mitk::Point3D currentPoint = (*it)->Coordinates;
if(currentPoint.EuclideanDistanceTo(point) < eps)
{
//approximate point found
//now erase it
this->m_Vertices->erase(it);
return true;
}
it++;
}
}
return false;
}
void mitk::ContourElement::Clear()
{
this->m_Vertices->clear();
}
+//----------------------------------------------------------------------
+void mitk::ContourElement::RedistributeControlVertices(const VertexType* selected, int period)
+{
+ int counter = 0;
+ VertexIterator _where = this->m_Vertices->begin();
+
+ if (selected != NULL)
+ {
+ while (_where != this->m_Vertices->end())
+ {
+ if ((*_where) == selected)
+ {
+ break;
+ }
+ _where++;
+ }
+ }
+
+ VertexIterator _iter = _where;
+ while (_iter != this->m_Vertices->end())
+ {
+ div_t divresult;
+ divresult = div (counter,period);
+ (*_iter)->IsControlPoint = (divresult.rem == 0);
+ counter++;
+ _iter++;
+ }
+
+ _iter = _where;
+ counter = 0;
+ while (_iter != this->m_Vertices->begin())
+ {
+ div_t divresult;
+ divresult = div (counter,period);
+ (*_iter)->IsControlPoint = (divresult.rem == 0);
+ counter++;
+ _iter--;
+ }
+}
diff --git a/Modules/Segmentation/DataManagement/mitkContourElement.h b/Modules/Segmentation/DataManagement/mitkContourElement.h
index 33041efd38..405ab4649a 100644
--- a/Modules/Segmentation/DataManagement/mitkContourElement.h
+++ b/Modules/Segmentation/DataManagement/mitkContourElement.h
@@ -1,229 +1,247 @@
/*===================================================================
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 _MITK_ContourElement_H_
-#define _MITK_ContourElement_H_
+#ifndef _mitkContourElement_H_
+#define _mitkContourElement_H_
#include "mitkCommon.h"
#include "SegmentationExports.h"
#include
#include
#include
namespace mitk
{
/** \brief Represents a contour in 3D space.
A ContourElement is consisting of linked vertices implicitely defining the contour.
They are stored in a double ended queue making it possible to add vertices at front and
end of the contour and to iterate in both directions.
To mark a vertex as a special one it can be set as a control point.
\Note It is highly not recommend to use this class directly as no secure mechanism is used here.
Use mitk::ContourModel instead providing some additional features.
*/
class Segmentation_EXPORT ContourElement : public itk::LightObject
{
public:
mitkClassMacro(ContourElement, itk::LightObject);
itkNewMacro(Self);
mitkCloneMacro(Self);
-/*+++++++++++++++++++++ Data container representing vertices +++++++++++++++++*/
-
+// Data container representing vertices
/** \brief Represents a single vertex of contour.
*/
struct ContourModelVertex
{
ContourModelVertex(mitk::Point3D &point, bool active=false)
: Coordinates(point), IsControlPoint(active)
{
};
/** \brief Treat point special. */
bool IsControlPoint;
/** \brief Coordinates in 3D space. */
mitk::Point3D Coordinates;
};
-/*+++++++++++++++++++++ END Data container representing vertices ++++++++++++++*/
-
+// END Data container representing vertices
-/*+++++++++++++++ typedefs +++++++++++++++++++++++++++++++*/
typedef ContourModelVertex VertexType;
typedef std::deque VertexListType;
typedef VertexListType::iterator VertexIterator;
typedef VertexListType::const_iterator ConstVertexIterator;
-/*+++++++++++++++ END typedefs ++++++++++++++++++++++++++++*/
-
+ // start of inline methods
-/*++++++++++++++++ inline methods +++++++++++++++++++++++*/
-
- /** \brief Return a const iterator a the front. */
+ /** \brief Return a const iterator a the front.
+ */
virtual ConstVertexIterator ConstIteratorBegin()
{
return this->m_Vertices->begin();
}
- /** \brief Return a const iterator a the end. */
+ /** \brief Return a const iterator a the end.
+ */
virtual ConstVertexIterator ConstIteratorEnd()
{
return this->m_Vertices->end();
}
- /** \brief Return an iterator a the front. */
+ /** \brief Return an iterator a the front.
+ */
virtual VertexIterator IteratorBegin()
{
return this->m_Vertices->begin();
}
- /** \brief Return an iterator a the end. */
+ /** \brief Return an iterator a the end.
+ */
virtual VertexIterator IteratorEnd()
{
return this->m_Vertices->end();
}
- /** \brief Returns the number of contained vertices. */
+ /** \brief Returns the number of contained vertices.
+ */
virtual int GetSize()
{
return this->m_Vertices->size();
}
-/*++++++++++++++++ END inline methods +++++++++++++++++++++++*/
-
-
+ // end of inline methods
/** \brief Add a vertex at the end of the contour
- \param vertex - coordinates in 3D space.
- \param isControlPoint - is the vertex a special control point.*/
- virtual void AddVertex(mitk::Point3D &vertex, bool isControlPoint);
+ \param point - coordinates in 3D space.
+ \param isControlPoint - is the vertex a special control point.
+ */
+ virtual void AddVertex(mitk::Point3D &point, bool isControlPoint);
/** \brief Add a vertex at the end of the contour
- \param vertex - a ContourModelVertex.
+ \param vertex - a contour element vertex.
*/
virtual void AddVertex(VertexType &vertex);
/** \brief Add a vertex at the front of the contour
- \param vertex - coordinates in 3D space.
- \param isControlPoint - is the vertex a special control point.*/
- virtual void AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint);
+ \param point - coordinates in 3D space.
+ \param isControlPoint - is the vertex a control point.
+ */
+ virtual void AddVertexAtFront(mitk::Point3D &point, bool isControlPoint);
/** \brief Add a vertex at the front of the contour
- \param vertex - a ContourModelVertex.
+ \param vertex - a contour element vertex.
*/
virtual void AddVertexAtFront(VertexType &vertex);
/** \brief Add a vertex at a given index of the contour
- \param vertex - coordinates in 3D space.
+ \param point - coordinates in 3D space.
\param isControlPoint - is the vertex a special control point.
\param index - the index to be inserted at.
*/
- virtual void InsertVertexAtIndex(mitk::Point3D &vertex, bool isControlPoint, int index);
+ virtual void InsertVertexAtIndex(mitk::Point3D &point, bool isControlPoint, int index);
/** \brief Returns the vertex a given index
\param index
*/
virtual VertexType* GetVertexAt(int index);
/** \brief Returns the approximate nearest vertex a given posoition in 3D space
\param point - query position in 3D space.
\param eps - the error bound for search algorithm.
*/
virtual VertexType* GetVertexAt(const mitk::Point3D &point, float eps);
/** \brief Returns the container of the vertices.
*/
VertexListType* GetVertexList();
+ /** \brief Returns whether the contour element is empty.
+ */
+ bool IsEmpty();
+
/** \brief Returns if the conour is closed or not.
*/
virtual bool IsClosed();
+ /** \brief Returns whether a given point is near a contour, according to eps.
+ \param point - query position in 3D space.
+ \param eps - the error bound for search algorithm.
+ */
+ virtual bool IsNearContour(const mitk::Point3D &point, float eps);
+
/** \brief Close the contour.
Connect first with last element.
*/
virtual void Close();
/** \brief Open the contour.
Disconnect first and last element.
*/
virtual void Open();
/** \brief Set the contours IsClosed property.
\param isClosed - true = closed; false = open;
*/
virtual void SetIsClosed(bool isClosed);
/** \brief Concatenate the contuor with a another contour.
- All vertices of the other contour will be add after last vertex.
+ All vertices of the other contour will be added after last vertex.
+ \param other - the other contour
+ \param check - set it true to avoid intersections
*/
- void Concatenate(mitk::ContourElement* other);
+ void Concatenate(mitk::ContourElement* other, bool check);
/** \brief Remove the given vertex from the container if exists.
\param vertex - the vertex to be removed.
*/
virtual bool RemoveVertex(VertexType* vertex);
/** \brief Remove a vertex at given index within the container if exists.
- \param index - the index to be removed at.
+ \param index - the index where the vertex should be removed.
*/
virtual bool RemoveVertexAt(int index);
/** \brief Remove the approximate nearest vertex at given position in 3D space if one exists.
\param point - query point in 3D space.
\param eps - error bound for search algorithm.
*/
virtual bool RemoveVertexAt(mitk::Point3D &point, float eps);
/** \brief Clear the storage container.
*/
virtual void Clear();
/** \brief Returns the approximate nearest vertex a given posoition in 3D space
\param point - query position in 3D space.
\param eps - the error bound for search algorithm.
*/
VertexType* BruteForceGetVertexAt(const mitk::Point3D &point, float eps);
/** \brief Returns the approximate nearest vertex a given posoition in 3D space
\param point - query position in 3D space.
\param eps - the error bound for search algorithm.
*/
VertexType* OptimizedGetVertexAt(const mitk::Point3D &point, float eps);
+ VertexListType* GetControlVertices();
+
+ /** \brief Uniformly redistribute control points with a given period (in number of vertices)
+ \param vertex - the vertex around which the redistribution is done.
+ \param period - number of vertices between control points.
+ */
+ void RedistributeControlVertices(const VertexType* vertex, int period);
protected:
ContourElement();
ContourElement(const mitk::ContourElement &other);
virtual ~ContourElement();
VertexListType* m_Vertices; //double ended queue with vertices
bool m_IsClosed;
};
-}
+} // namespace mitk
-#endif
+#endif // _mitkContourElement_H_
diff --git a/Modules/Segmentation/DataManagement/mitkContourModel.cpp b/Modules/Segmentation/DataManagement/mitkContourModel.cpp
index a7da7afaad..e1f9a36c4c 100644
--- a/Modules/Segmentation/DataManagement/mitkContourModel.cpp
+++ b/Modules/Segmentation/DataManagement/mitkContourModel.cpp
@@ -1,552 +1,588 @@
/*===================================================================
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
#include
mitk::ContourModel::ContourModel()
{
//set to initial state
this->InitializeEmpty();
}
mitk::ContourModel::ContourModel(const mitk::ContourModel &other) :
m_ContourSeries(other.m_ContourSeries), m_lineInterpolation(other.m_lineInterpolation)
{
m_SelectedVertex = NULL;
}
mitk::ContourModel::~ContourModel()
{
m_SelectedVertex = NULL;
this->m_ContourSeries.clear();//TODO check destruction
}
void mitk::ContourModel::AddVertex(mitk::Point3D &vertex, int timestep)
{
if(!this->IsEmptyTimeStep(timestep) )
{
this->AddVertex(vertex, false, timestep);
}
}
void mitk::ContourModel::AddVertex(mitk::Point3D &vertex, bool isControlPoint, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
this->m_ContourSeries[timestep]->AddVertex(vertex, isControlPoint);
this->InvokeEvent( ContourModelSizeChangeEvent() );
this->Modified();
}
}
void mitk::ContourModel::AddVertex(VertexType &vertex, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
this->m_ContourSeries[timestep]->AddVertex(vertex);
this->InvokeEvent( ContourModelSizeChangeEvent() );
this->Modified();
}
}
void mitk::ContourModel::AddVertexAtFront(mitk::Point3D &vertex, int timestep)
{
if(!this->IsEmptyTimeStep(timestep) )
{
this->AddVertexAtFront(vertex, false, timestep);
}
}
void mitk::ContourModel::AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
this->m_ContourSeries[timestep]->AddVertexAtFront(vertex, isControlPoint);
this->InvokeEvent( ContourModelSizeChangeEvent() );
this->Modified();
}
}
void mitk::ContourModel::AddVertexAtFront(VertexType &vertex, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
this->m_ContourSeries[timestep]->AddVertexAtFront(vertex);
this->InvokeEvent( ContourModelSizeChangeEvent() );
this->Modified();
}
}
void mitk::ContourModel::InsertVertexAtIndex(mitk::Point3D &vertex, int index, bool isControlPoint, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
if(index > 0 && this->m_ContourSeries[timestep]->GetSize() > index)
{
this->m_ContourSeries[timestep]->InsertVertexAtIndex(vertex, isControlPoint, index);
this->InvokeEvent( ContourModelSizeChangeEvent() );
this->Modified();
}
}
}
+bool mitk::ContourModel::IsEmpty( int timestep)
+{
+ if(!this->IsEmptyTimeStep(timestep))
+ {
+ return this->m_ContourSeries[timestep]->IsEmpty();
+ }
+ return true;
+}
+
int mitk::ContourModel::GetNumberOfVertices( int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
return this->m_ContourSeries[timestep]->GetSize();
}
return -1;
}
const mitk::ContourModel::VertexType* mitk::ContourModel::GetVertexAt(int index, int timestep) const
{
if(!this->IsEmptyTimeStep(timestep))
{
return this->m_ContourSeries[timestep]->GetVertexAt(index);
}
return NULL;
}
void mitk::ContourModel::Close( int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
this->m_ContourSeries[timestep]->Close();
this->InvokeEvent( ContourModelClosedEvent() );
this->Modified();
}
}
void mitk::ContourModel::Open( int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
this->m_ContourSeries[timestep]->Open();
this->InvokeEvent( ContourModelClosedEvent() );
this->Modified();
}
}
void mitk::ContourModel::SetIsClosed(bool isClosed, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
this->m_ContourSeries[timestep]->SetIsClosed(isClosed);
this->InvokeEvent( ContourModelClosedEvent() );
this->Modified();
}
}
bool mitk::ContourModel::IsEmptyTimeStep( int t) const
{
return (t < 0) || (this->m_ContourSeries.size() <= t);
}
+bool mitk::ContourModel::IsNearContour(mitk::Point3D &point, float eps, int timestep)
+{
+ if(!this->IsEmptyTimeStep(timestep))
+ {
+ return this->m_ContourSeries[timestep]->IsNearContour(point, eps);
+ }
+ return false;
+}
-void mitk::ContourModel::Concatenate(mitk::ContourModel* other, int timestep)
+void mitk::ContourModel::Concatenate(mitk::ContourModel* other, int timestep, bool check)
{
if(!this->IsEmptyTimeStep(timestep))
{
if( !this->m_ContourSeries[timestep]->IsClosed() )
{
- this->m_ContourSeries[timestep]->Concatenate(other->m_ContourSeries[timestep]);
+ this->m_ContourSeries[timestep]->Concatenate(other->m_ContourSeries[timestep], check);
this->InvokeEvent( ContourModelSizeChangeEvent() );
this->Modified();
}
}
}
-
-
mitk::ContourModel::VertexIterator mitk::ContourModel::IteratorBegin( int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
return this->m_ContourSeries[timestep]->IteratorBegin();
}
else
{
mitkThrow() << "No iterator at invalid timestep " << timestep << ". There are only " << this->GetTimeSteps() << " timesteps available.";
}
}
-
-
mitk::ContourModel::VertexIterator mitk::ContourModel::IteratorEnd( int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
return this->m_ContourSeries[timestep]->IteratorEnd();
}
else
{
mitkThrow() << "No iterator at invalid timestep " << timestep << ". There are only " << this->GetTimeSteps() << " timesteps available.";
}
}
bool mitk::ContourModel::IsClosed( int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
return this->m_ContourSeries[timestep]->IsClosed();
}
return false;
}
+bool mitk::ContourModel::SelectVertexAt(mitk::Point3D &point, float eps, int timestep)
+{
+ if(!this->IsEmptyTimeStep(timestep))
+ {
+ this->m_SelectedVertex = this->m_ContourSeries[timestep]->GetVertexAt(point, eps);
+ }
+ return this->m_SelectedVertex != NULL;
+}
bool mitk::ContourModel::SelectVertexAt(int index, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
return (this->m_SelectedVertex = this->m_ContourSeries[timestep]->GetVertexAt(index));
}
return false;
}
-
-
-bool mitk::ContourModel::SelectVertexAt(mitk::Point3D &point, float eps, int timestep)
+bool mitk::ContourModel::SetControlVertexAt(mitk::Point3D &point, float eps, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
- this->m_SelectedVertex = this->m_ContourSeries[timestep]->GetVertexAt(point, eps);
+ VertexType* vertex = this->m_ContourSeries[timestep]->GetVertexAt(point, eps);
+ if (vertex != NULL)
+ {
+ vertex->IsControlPoint = true;
+ return true;
+ }
}
- return this->m_SelectedVertex != NULL;
+ return false;
}
-
+bool mitk::ContourModel::SetControlVertexAt(int index, int timestep)
+{
+ if(!this->IsEmptyTimeStep(timestep))
+ {
+ VertexType* vertex = this->m_ContourSeries[timestep]->GetVertexAt(index);
+ if (vertex != NULL)
+ {
+ vertex->IsControlPoint = true;
+ return true;
+ }
+ }
+ return false;
+}
bool mitk::ContourModel::RemoveVertex(VertexType* vertex, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
if(this->m_ContourSeries[timestep]->RemoveVertex(vertex))
{
this->Modified();
this->InvokeEvent( ContourModelSizeChangeEvent() );
return true;
}
}
return false;
}
bool mitk::ContourModel::RemoveVertexAt(int index, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
if(this->m_ContourSeries[timestep]->RemoveVertexAt(index))
{
this->Modified();
this->InvokeEvent( ContourModelSizeChangeEvent() );
return true;
}
}
return false;
}
bool mitk::ContourModel::RemoveVertexAt(mitk::Point3D &point, float eps, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
if(this->m_ContourSeries[timestep]->RemoveVertexAt(point, eps))
{
this->Modified();
this->InvokeEvent( ContourModelSizeChangeEvent() );
return true;
}
}
return false;
}
void mitk::ContourModel::ShiftSelectedVertex(mitk::Vector3D &translate)
{
if(this->m_SelectedVertex)
{
this->ShiftVertex(this->m_SelectedVertex,translate);
this->Modified();
}
}
void mitk::ContourModel::ShiftContour(mitk::Vector3D &translate, int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
VertexListType* vList = this->m_ContourSeries[timestep]->GetVertexList();
VertexIterator it = vList->begin();
VertexIterator end = vList->end();
//shift all vertices
while(it != end)
{
this->ShiftVertex((*it),translate);
it++;
}
this->Modified();
this->InvokeEvent( ContourModelShiftEvent() );
}
}
void mitk::ContourModel::ShiftVertex(VertexType* vertex, mitk::Vector3D &vector)
{
vertex->Coordinates[0] += vector[0];
vertex->Coordinates[1] += vector[1];
vertex->Coordinates[2] += vector[2];
}
void mitk::ContourModel::Clear(int timestep)
{
if(!this->IsEmptyTimeStep(timestep))
{
//clear data at timestep
this->m_ContourSeries[timestep]->Clear();
this->InitializeEmpty();
this->Modified();
}
}
void mitk::ContourModel::Expand( int timeSteps )
{
int oldSize = this->m_ContourSeries.size();
if( timeSteps > 0 && timeSteps > oldSize )
{
Superclass::Expand(timeSteps);
//insert contours for each new timestep
for( int i = oldSize; i < timeSteps; i++)
{
m_ContourSeries.push_back(mitk::ContourElement::New());
}
this->InvokeEvent( ContourModelExpandTimeBoundsEvent() );
}
}
void mitk::ContourModel::SetRequestedRegionToLargestPossibleRegion ()
{
//no support for regions
}
bool mitk::ContourModel::RequestedRegionIsOutsideOfTheBufferedRegion ()
{
//no support for regions
return false;
}
bool mitk::ContourModel::VerifyRequestedRegion ()
{
//no support for regions
return true;
}
const mitk::Geometry3D * mitk::ContourModel::GetUpdatedGeometry (int t)
{
return Superclass::GetUpdatedGeometry(t);
}
mitk::Geometry3D* mitk::ContourModel::GetGeometry (int t)const
{
return Superclass::GetGeometry(t);
}
-
void mitk::ContourModel::SetRequestedRegion( const itk::DataObject *data)
{
//no support for regions
}
void mitk::ContourModel::Clear()
{
//clear data and set to initial state again
this->ClearData();
this->InitializeEmpty();
this->Modified();
}
+void mitk::ContourModel::RedistributeControlVertices(int period, int timestep)
+{
+ if(!this->IsEmptyTimeStep(timestep))
+ {
+ this->m_ContourSeries[timestep]->RedistributeControlVertices(this->GetSelectedVertex(), period);
+ this->InvokeEvent( ContourModelClosedEvent() );
+ this->Modified();
+ }
+}
+
void mitk::ContourModel::ClearData()
{
//call the superclass, this releases the data of BaseData
Superclass::ClearData();
//clear out the time resolved contours
this->m_ContourSeries.clear();
}
-
void mitk::ContourModel::InitializeEmpty()
{
//clear data at timesteps
this->m_ContourSeries.resize(0);
this->m_ContourSeries.push_back(mitk::ContourElement::New());
//set number of timesteps to one
this->InitializeTimeSlicedGeometry(1);
m_SelectedVertex = NULL;
this->m_lineInterpolation = ContourModel::LINEAR;
}
-
void mitk::ContourModel::UpdateOutputInformation()
{
-
if ( this->GetSource() )
{
this->GetSource()->UpdateOutputInformation();
}
-
-
//update the bounds of the geometry according to the stored vertices
float mitkBounds[6];
-
//calculate the boundingbox at each timestep
-
typedef itk::BoundingBox BoundingBoxType;
typedef BoundingBoxType::PointsContainer PointsContainer;
int timesteps = this->GetTimeSteps();
//iterate over the timesteps
for(int currenTimeStep = 0; currenTimeStep < timesteps; currenTimeStep++)
{
if( dynamic_cast< mitk::PlaneGeometry* >(this->GetGeometry(currenTimeStep)) )
{
//do not update bounds for 2D geometries, as they are unfortunately defined with min bounds 0!
return;
}
else
{//we have a 3D geometry -> let's update bounds
//only update bounds if the contour was modified
if (this->GetMTime() > this->GetGeometry(currenTimeStep)->GetBoundingBox()->GetMTime())
{
mitkBounds[0] = 0.0;
mitkBounds[1] = 0.0;
mitkBounds[2] = 0.0;
mitkBounds[3] = 0.0;
mitkBounds[4] = 0.0;
mitkBounds[5] = 0.0;
BoundingBoxType::Pointer boundingBox = BoundingBoxType::New();
PointsContainer::Pointer points = PointsContainer::New();
VertexIterator it = this->IteratorBegin(currenTimeStep);
VertexIterator end = this->IteratorEnd(currenTimeStep);
//fill the boundingbox with the points
while(it != end)
{
Point3D currentP = (*it)->Coordinates;
BoundingBoxType::PointType p;
p.CastFrom(currentP);
points->InsertElement(points->Size(), p);
it++;
}
//construct the new boundingBox
boundingBox->SetPoints(points);
boundingBox->ComputeBoundingBox();
BoundingBoxType::BoundsArrayType tmp = boundingBox->GetBounds();
mitkBounds[0] = tmp[0];
mitkBounds[1] = tmp[1];
mitkBounds[2] = tmp[2];
mitkBounds[3] = tmp[3];
mitkBounds[4] = tmp[4];
mitkBounds[5] = tmp[5];
//set boundingBox at current timestep
Geometry3D* geometry3d = this->GetGeometry(currenTimeStep);
geometry3d->SetBounds(mitkBounds);
}
}
}
GetTimeSlicedGeometry()->UpdateInformation();
}
-
-
void mitk::ContourModel::ExecuteOperation(mitk::Operation* operation)
{
//not supported yet
}
diff --git a/Modules/Segmentation/DataManagement/mitkContourModel.h b/Modules/Segmentation/DataManagement/mitkContourModel.h
index 2530d1cef7..83be3f048b 100644
--- a/Modules/Segmentation/DataManagement/mitkContourModel.h
+++ b/Modules/Segmentation/DataManagement/mitkContourModel.h
@@ -1,397 +1,426 @@
/*===================================================================
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 _MITK_CONTOURMODEL_H_
#define _MITK_CONTOURMODEL_H_
#include "mitkCommon.h"
#include "SegmentationExports.h"
#include "mitkBaseData.h"
#include
namespace mitk
{
/**
\brief ContourModel is a structure of linked vertices defining a contour in 3D space.
The vertices are stored in a mitk::ContourElement is stored for each timestep.
The contour line segments are implicitly defined by the given linked vertices.
By default two control points are are linked by a straight line.It is possible to add
vertices at front and end of the contour and to iterate in both directions.
Points are specified containing coordinates and additional (data) information,
see mitk::ContourElement.
For accessing a specific vertex either an index or a position in 3D Space can be used.
The vertices are best accessed by using a VertexIterator.
Interaction with the contour is thus available without any mitk interactor class using the
api of ContourModel. It is possible to shift single vertices also as shifting the whole
contour.
A contour can be either open like a single curved line segment or
closed. A closed contour can for example represent a jordan curve.
\section mitkContourModelDisplayOptions Display Options
The default mappers for this data structure are mitk::ContourModelGLMapper2D and
mitk::ContourModelMapper3D. See these classes for display options which can
can be set via properties.
*/
class Segmentation_EXPORT ContourModel : public BaseData
{
public:
mitkClassMacro(ContourModel, BaseData);
itkNewMacro(Self);
mitkCloneMacro(Self);
/*+++++++++++++++ typedefs +++++++++++++++++++++++++++++++*/
typedef mitk::ContourElement::VertexType VertexType;
typedef mitk::ContourElement::VertexListType VertexListType;
typedef mitk::ContourElement::VertexIterator VertexIterator;
+ typedef mitk::ContourElement::ConstVertexIterator ConstVertexIterator;
typedef std::vector< mitk::ContourElement::Pointer > ContourModelSeries;
/*+++++++++++++++ END typedefs ++++++++++++++++++++++++++++*/
/** \brief Possible interpolation of the line segments between control points */
enum LineSegmentInterpolation{
LINEAR, B_SPLINE
};
/*++++++++++++++++ inline methods +++++++++++++++++++++++*/
/** \brief Get the current selected vertex.
*/
VertexType* GetSelectedVertex()
{
return this->m_SelectedVertex;
}
/** \brief Deselect vertex.
*/
void Deselect()
{
this->m_SelectedVertex = NULL;
}
- /** \brief Deselect vertex.
+ /** \brief Set selected vertex as control point
*/
void SetSelectedVertexAsControlPoint(bool isControlPoint=true)
{
- if(this->m_SelectedVertex && (this->m_SelectedVertex->IsControlPoint != isControlPoint) )
+ if (this->m_SelectedVertex)
{
m_SelectedVertex->IsControlPoint = isControlPoint;
this->Modified();
}
}
/** \brief Set the interpolation of the line segments between control points.
*/
void SetLineSegmentInterpolation(LineSegmentInterpolation interpolation)
{
this->m_lineInterpolation = interpolation;
this->Modified();
}
/** \brief Get the interpolation of the line segments between control points.
*/
LineSegmentInterpolation GetLineSegmentInterpolation()
{
return this->m_lineInterpolation;
}
/*++++++++++++++++ END inline methods +++++++++++++++++++++++*/
/** \brief Add a vertex to the contour at given timestep.
The vertex is added at the end of contour.
\pararm vertex - coordinate representation of a control point
\pararm timestep - the timestep at which the vertex will be add ( default 0)
@Note Adding a vertex to a timestep which exceeds the timebounds of the contour
will not be added, the TimeSlicedGeometry will not be expanded.
*/
void AddVertex(mitk::Point3D &vertex, int timestep=0);
/** \brief Add a vertex to the contour at given timestep.
The vertex is added at the end of contour.
\param vertex - coordinate representation of a control point
\param timestep - the timestep at which the vertex will be add ( default 0)
@Note Adding a vertex to a timestep which exceeds the timebounds of the contour
will not be added, the TimeSlicedGeometry will not be expanded.
*/
void AddVertex(VertexType &vertex, int timestep=0);
/** \brief Add a vertex to the contour.
\pararm vertex - coordinate representation of a control point
\pararm timestep - the timestep at which the vertex will be add ( default 0)
\pararm isControlPoint - specifies the vertex to be handled in a special way (e.g. control points
will be rendered).
@Note Adding a vertex to a timestep which exceeds the timebounds of the contour
will not be added, the TimeSlicedGeometry will not be expanded.
*/
void AddVertex(mitk::Point3D &vertex, bool isControlPoint, int timestep=0);
/** \brief Add a vertex to the contour at given timestep AT THE FRONT of the contour.
The vertex is added at the FRONT of contour.
\pararm vertex - coordinate representation of a control point
\pararm timestep - the timestep at which the vertex will be add ( default 0)
@Note Adding a vertex to a timestep which exceeds the timebounds of the contour
will not be added, the TimeSlicedGeometry will not be expanded.
*/
void AddVertexAtFront(mitk::Point3D &vertex, int timestep=0);
/** \brief Add a vertex to the contour at given timestep AT THE FRONT of the contour.
The vertex is added at the FRONT of contour.
\pararm vertex - coordinate representation of a control point
\pararm timestep - the timestep at which the vertex will be add ( default 0)
@Note Adding a vertex to a timestep which exceeds the timebounds of the contour
will not be added, the TimeSlicedGeometry will not be expanded.
*/
void AddVertexAtFront(VertexType &vertex, int timestep=0);
/** \brief Add a vertex to the contour at given timestep AT THE FRONT of the contour.
\pararm vertex - coordinate representation of a control point
\pararm timestep - the timestep at which the vertex will be add ( default 0)
\pararm isControlPoint - specifies the vertex to be handled in a special way (e.g. control points
will be rendered).
@Note Adding a vertex to a timestep which exceeds the timebounds of the contour
will not be added, the TimeSlicedGeometry will not be expanded.
*/
void AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint, int timestep=0);
/** \brief Insert a vertex at given index.
*/
void InsertVertexAtIndex(mitk::Point3D &vertex, int index, bool isControlPoint=false, int timestep=0);
/** \brief Return if the contour is closed or not.
*/
bool IsClosed( int timestep=0);
/** \brief Concatenate two contours.
The starting control point of the other will be added at the end of the contour.
+ \pararm timestep - the timestep at which the vertex will be add ( default 0)
+ \pararm check - check for intersections ( default false)
*/
- void Concatenate(mitk::ContourModel* other, int timestep=0);
+ void Concatenate(mitk::ContourModel* other, int timestep=0, bool check=false);
/** \brief Returns a const VertexIterator at the start element of the contour.
@throw mitk::Exception if the timestep is invalid.
*/
VertexIterator IteratorBegin( int timestep=0);
+ /** \brief Returns a const VertexIterator at the end element of the contour.
+ @throw mitk::Exception if the timestep is invalid.
+ */
+ VertexIterator IteratorEnd( int timestep=0);
+
/** \brief Close the contour.
The last control point will be linked with the first point.
*/
virtual void Close( int timestep=0);
/** \brief Set isClosed to false contour.
The link between the last control point the first point will be removed.
*/
virtual void Open( int timestep=0);
/** \brief Set isClosed to given boolean.
false - The link between the last control point the first point will be removed.
true - The last control point will be linked with the first point.
*/
virtual void SetIsClosed(bool isClosed, int timestep=0);
- /** \brief Returns a const VertexIterator at the end element of the contour.
- @throw mitk::Exception if the timestep is invalid.
- */
- VertexIterator IteratorEnd( int timestep=0);
-
/** \brief Returns the number of vertices at a given timestep.
\pararm timestep - default = 0
*/
int GetNumberOfVertices( int timestep=0);
+ /** \brief Returns whether the contour model is empty at a given timestep.
+
+ \pararm timestep - default = 0
+ */
+ bool IsEmpty( int timestep=0);
+
/** \brief Returns the vertex at the index position within the container.
*/
virtual const VertexType* GetVertexAt(int index, int timestep=0) const;
/** \brief Check if there isn't something at this timestep.
*/
virtual bool IsEmptyTimeStep( int t) const;
+ /** \brief Check if mouse cursor is near the contour.
+ */
+ virtual bool IsNearContour(mitk::Point3D &point, float eps, int timestep);
+
/** \brief Mark a vertex at an index in the container as selected.
*/
bool SelectVertexAt(int index, int timestep=0);
+ /** \brief Mark a vertex at an index in the container as control point.
+ */
+ bool SetControlVertexAt(int index, int timestep=0);
+
/** \brief Mark a vertex at a given position in 3D space.
\pararm point - query point in 3D space
\pararm eps - radius for nearest neighbour search (error bound).
\pararm timestep - search at this timestep
@return true = vertex found; false = no vertex found
*/
bool SelectVertexAt(mitk::Point3D &point, float eps, int timestep=0);
+/*
+ \pararm point - query point in 3D space
+ \pararm eps - radius for nearest neighbour search (error bound).
+ \pararm timestep - search at this timestep
+
+ @return true = vertex found; false = no vertex found
+ */
+ bool SetControlVertexAt(mitk::Point3D &point, float eps, int timestep=0);
/** \brief Remove a vertex at given index within the container.
@return true = the vertex was successfuly removed; false = wrong index.
*/
bool RemoveVertexAt(int index, int timestep=0);
/** \brief Remove a vertex at given timestep within the container.
@return true = the vertex was successfuly removed.
*/
bool RemoveVertex(VertexType* vertex, int timestep=0);
/** \brief Remove a vertex at a query position in 3D space.
The vertex to be removed will be search by nearest neighbour search.
Note that possibly no vertex at this position and eps is stored inside
the contour.
@return true = the vertex was successfuly removed; false = no vertex found.
*/
bool RemoveVertexAt(mitk::Point3D &point, float eps, int timestep=0);
/** \brief Shift the currently selected vertex by a translation vector.
\pararm translate - the translation vector.
*/
void ShiftSelectedVertex(mitk::Vector3D &translate);
/** \brief Shift the whole contour by a translation vector at given timestep.
\pararm translate - the translation vector.
\pararm timestep - at this timestep the contour will be shifted.
*/
void ShiftContour(mitk::Vector3D &translate, int timestep=0);
/** \brief Clear the storage container at given timestep.
All control points are removed at
timestep.
*/
virtual void Clear(int timestep);
/*++++++++++++++++++ method inherit from base data +++++++++++++++++++++++++++*/
/**
\brief Inherit from base data - no region support available for contourModel objects.
*/
virtual void SetRequestedRegionToLargestPossibleRegion ();
/**
\brief Inherit from base data - no region support available for contourModel objects.
*/
virtual bool RequestedRegionIsOutsideOfTheBufferedRegion ();
/**
\brief Inherit from base data - no region support available for contourModel objects.
*/
virtual bool VerifyRequestedRegion ();
/**
\brief Get the updated geometry with recomputed bounds.
*/
virtual const mitk::Geometry3D* GetUpdatedGeometry (int t=0);
/**
\brief Get the Geometry3D for timestep t.
*/
virtual mitk::Geometry3D* GetGeometry (int t=0) const;
/**
\brief Inherit from base data - no region support available for contourModel objects.
*/
virtual void SetRequestedRegion( const itk::DataObject *data);
/**
\brief Expand the timebounds of the TimeSlicedGeometry to given number of timesteps.
*/
virtual void Expand( int timeSteps );
/**
\brief Update the OutputInformation of a ContourModel object
The BoundingBox of the contour will be updated, if necessary.
*/
virtual void UpdateOutputInformation();
/**
\brief Clear the storage container.
The object is set to initial state. All control points are removed and the number of
timesteps are set to 1.
*/
virtual void Clear();
/**
\brief overwrite if the Data can be called by an Interactor (StateMachine).
*/
void ExecuteOperation(Operation* operation);
+ /** \brief Redistributes ontrol vertices with a given period (as number of vertices)
+ \param period - the number of vertices between control points.
+ \param timestep - at this timestep all lines will be rebuilt.
+ */
+ virtual void RedistributeControlVertices(int period, int timestep);
protected:
ContourModel();
ContourModel(const mitk::ContourModel &other);
virtual ~ContourModel();
//inherit from BaseData. called by Clear()
virtual void ClearData();
//inherit from BaseData. Initial state of a contour with no vertices and a single timestep.
virtual void InitializeEmpty();
//Shift a vertex
void ShiftVertex(VertexType* vertex, mitk::Vector3D &vector);
-
//Storage with time resolved support.
ContourModelSeries m_ContourSeries;
//The currently selected vertex.
VertexType* m_SelectedVertex;
//The interpolation of the line segment between control points.
LineSegmentInterpolation m_lineInterpolation;
};
itkEventMacro( ContourModelEvent, itk::AnyEvent );
itkEventMacro( ContourModelShiftEvent, ContourModelEvent );
itkEventMacro( ContourModelSizeChangeEvent, ContourModelEvent );
itkEventMacro( ContourModelAddEvent, ContourModelSizeChangeEvent );
itkEventMacro( ContourModelRemoveEvent, ContourModelSizeChangeEvent );
itkEventMacro( ContourModelExpandTimeBoundsEvent, ContourModelEvent );
itkEventMacro( ContourModelClosedEvent, ContourModelEvent );
}
#endif
diff --git a/Modules/Segmentation/IO/mitkContourModelReader.cpp b/Modules/Segmentation/IO/mitkContourModelReader.cpp
index 057084ce96..de15baaac0 100644
--- a/Modules/Segmentation/IO/mitkContourModelReader.cpp
+++ b/Modules/Segmentation/IO/mitkContourModelReader.cpp
@@ -1,215 +1,215 @@
/*===================================================================
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 "mitkContourModelReader.h"
#include
#include
#include
mitk::ContourModelReader::ContourModelReader()
{
m_Success = false;
}
mitk::ContourModelReader::~ContourModelReader()
{}
void mitk::ContourModelReader::GenerateData()
{
std::locale::global(std::locale("C"));
m_Success = false;
if ( m_FileName == "" )
{
itkWarningMacro( << "Sorry, filename has not been set!" );
return ;
}
if ( ! this->CanReadFile( m_FileName.c_str() ) )
{
itkWarningMacro( << "Sorry, can't read file " << m_FileName << "!" );
return ;
}
try{
TiXmlDocument doc(m_FileName.c_str());
bool loadOkay = doc.LoadFile();
if (loadOkay)
{
TiXmlHandle docHandle( &doc );
//handle geometry information
TiXmlElement* currentContourElement = docHandle.FirstChildElement("contourModel").FirstChildElement("head").FirstChildElement("geometryInformation").ToElement();
/*++++ handle n contourModels within data tags ++++*/
unsigned int contourCounter(0);
for( TiXmlElement* currentContourElement = docHandle.FirstChildElement("contourModel").FirstChildElement("data").ToElement();
currentContourElement != NULL; currentContourElement = currentContourElement->NextSiblingElement())
{
mitk::ContourModel::Pointer newContourModel = mitk::ContourModel::New();
if(currentContourElement->FirstChildElement("timestep") != NULL)
{
/*++++ handle n timesteps within timestep tags ++++*/
for( TiXmlElement* currentTimeSeries = currentContourElement->FirstChildElement("timestep")->ToElement();
currentTimeSeries != NULL; currentTimeSeries = currentTimeSeries->NextSiblingElement())
{
unsigned int currentTimeStep(0);
currentTimeStep = atoi(currentTimeSeries->Attribute("n"));
this->ReadPoints(newContourModel, currentTimeSeries, currentTimeStep);
int isClosed;
currentTimeSeries->QueryIntAttribute("isClosed", &isClosed);
if( isClosed )
{
newContourModel->Close(currentTimeStep);
}
}
/*++++ END handle n timesteps within timestep tags ++++*/
}
else
{
//this should not happen
MITK_WARN << "wrong file format!";
//newContourModel = this->ReadPoint(newContourModel, currentContourElement, 0);
}
this->SetNthOutput( contourCounter, newContourModel );
contourCounter++;
}
/*++++ END handle n contourModels within data tags ++++*/
}
else
{
MITK_WARN << "XML parser error!";
}
}catch(...)
{
MITK_ERROR << "Cannot read contourModel.";
m_Success = false;
}
m_Success = true;
}
void mitk::ContourModelReader::ReadPoints(mitk::ContourModel::Pointer newContourModel,
TiXmlElement* currentTimeSeries, unsigned int currentTimeStep)
{
//check if the timesteps in contourModel have to be expanded
if(currentTimeStep != newContourModel->GetTimeSteps())
{
newContourModel->Expand(currentTimeStep+1);
}
//read all points within controlPoints tag
if(currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point") != NULL)
{
for( TiXmlElement* currentPoint = currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point")->ToElement();
currentPoint != NULL; currentPoint = currentPoint->NextSiblingElement())
{
mitk::PointSpecificationType spec((mitk::PointSpecificationType) 0);
double x(0.0);
double y(0.0);
double z(0.0);
x = atof(currentPoint->FirstChildElement("x")->GetText());
y = atof(currentPoint->FirstChildElement("y")->GetText());
z = atof(currentPoint->FirstChildElement("z")->GetText());
int isActivePoint;
currentPoint->QueryIntAttribute("isActive", &isActivePoint);
mitk::Point3D point;
mitk::FillVector3D(point, x, y, z);
newContourModel->AddVertex(point, isActivePoint,currentTimeStep);
}
}
else
{
//nothing to read
}
}
void mitk::ContourModelReader::GenerateOutputInformation()
{
}
int mitk::ContourModelReader::CanReadFile ( const char *name )
{
std::ifstream in( name );
bool isGood = in.good();
in.close();
return isGood;
}
bool mitk::ContourModelReader::CanReadFile(const std::string filename, const std::string filePrefix, const std::string filePattern)
{
// First check the extension
if( filename == "" )
{
//MITK_INFO<<"No filename specified."<GetNumberOfOutputs();
- this->SetNumberOfOutputs( num );
+ this->SetNumberOfIndexedOutputs( num );
for ( unsigned int i = prevNum; i < num; ++i )
{
this->SetNthOutput( i, this->MakeOutput( i ).GetPointer() );
}
}
bool mitk::ContourModelReader::GetSuccess() const
{
return m_Success;
}
diff --git a/Modules/Segmentation/Interactions/mitkContourModelInteractor.cpp b/Modules/Segmentation/Interactions/mitkContourModelInteractor.cpp
index 3d550fdcad..cfa2eea6ea 100644
--- a/Modules/Segmentation/Interactions/mitkContourModelInteractor.cpp
+++ b/Modules/Segmentation/Interactions/mitkContourModelInteractor.cpp
@@ -1,267 +1,276 @@
/*===================================================================
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 "mitkContourModelInteractor.h"
#include "mitkToolManager.h"
#include "mitkBaseRenderer.h"
#include "mitkRenderingManager.h"
#include
#include
#include
mitk::ContourModelInteractor::ContourModelInteractor(DataNode* dataNode)
:Interactor("ContourModelInteractor", dataNode)
{
CONNECT_ACTION( AcCHECKPOINT, OnCheckPointClick );
CONNECT_ACTION( AcCHECKOBJECT, OnCheckContourClick );
CONNECT_ACTION( AcDELETEPOINT, OnDeletePoint );
CONNECT_ACTION( AcMOVEPOINT, OnMovePoint );
- CONNECT_ACTION( AcMOVE, OnMoveContour );
- CONNECT_ACTION( AcFINISH, OnFinish );
+// CONNECT_ACTION( AcMOVE, OnMoveContour );
+ CONNECT_ACTION( AcMOVE, OnMove );
+ CONNECT_ACTION( AcFINISH, OnFinishEditing );
}
mitk::ContourModelInteractor::~ContourModelInteractor()
{
}
float mitk::ContourModelInteractor::CanHandleEvent(StateEvent const* stateEvent) const
{
float returnValue = 0.0;
//if it is a key event that can be handled in the current state, then return 0.5
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;
}
}
int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep();
mitk::ContourModel *contour = dynamic_cast(
m_DataNode->GetData() );
if ( contour != NULL )
{
mitk::Point3D worldPoint3D = positionEvent->GetWorldPosition();
mitk::Geometry3D *contourGeometry =
dynamic_cast< Geometry3D * >( contour->GetGeometry( timestep ) );
if ( contourGeometry )
{
//if click is inside bounds the interactor can handle the event best
if( contourGeometry->IsInside(worldPoint3D) )
{
return 1.0;
}
return 0.9;
}
}
return returnValue;
}
-
-
void mitk::ContourModelInteractor::DataChanged()
{
//go to initial state
const mitk::Event* nullEvent = new mitk::Event(NULL, Type_User, BS_NoButton, BS_NoButton, Key_none);
mitk::StateEvent* newStateEvent = new mitk::StateEvent(AcFINISH, nullEvent);
this->HandleEvent( newStateEvent );
delete newStateEvent;
delete nullEvent;
return;
}
-
bool mitk::ContourModelInteractor::OnCheckPointClick( Action* action, const StateEvent* stateEvent)
{
const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
if (!positionEvent) return false;
mitk::StateEvent* newStateEvent = NULL;
int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep();
mitk::ContourModel *contour = dynamic_cast(
m_DataNode->GetData() );
-
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();
assert( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent());
m_lastMousePosition = click;
}
else
{
newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent());
}
this->HandleEvent( newStateEvent );
return true;
}
-
bool mitk::ContourModelInteractor::OnCheckContourClick( Action* action, const StateEvent* stateEvent)
{
const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
if (!positionEvent) return false;
int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep();
mitk::Point3D click = positionEvent->GetWorldPosition();
mitk::StateEvent* newStateEvent = NULL;
mitk::ContourModel *contour = dynamic_cast(
m_DataNode->GetData() );
mitk::Geometry3D *contourGeometry = dynamic_cast< Geometry3D * >( contour->GetGeometry( timestep ) );
if ( contourGeometry->IsInside(click) )
{
m_lastMousePosition = click;
newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent());
}
else
{
newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent());
}
this->HandleEvent( newStateEvent );
return true;
}
-
bool mitk::ContourModelInteractor::OnDeletePoint( Action* action, const StateEvent* stateEvent)
{
-
int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep();
mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() );
contour->RemoveVertex(contour->GetSelectedVertex());
-
return true;
}
+bool mitk::ContourModelInteractor::OnMove( Action* action, const StateEvent* stateEvent)
+{
+ const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
+ if (!positionEvent) return false;
+
+ int timestep = positionEvent->GetSender()->GetTimeStep();
+
+ mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() );
+
+ mitk::Point3D currentPosition = positionEvent->GetWorldPosition();
+
+ m_DataNode->SetBoolProperty("contour.hovering", contour->IsNearContour(currentPosition, 1.5, timestep) );
+
+ assert( positionEvent->GetSender()->GetRenderWindow() );
+ mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
+
+ return true;
+}
bool mitk::ContourModelInteractor::OnMovePoint( Action* action, const StateEvent* stateEvent)
{
const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
if (!positionEvent) return false;
-
mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() );
mitk::Vector3D translation;
mitk::Point3D currentPosition = positionEvent->GetWorldPosition();
translation[0] = currentPosition[0] - this->m_lastMousePosition[0];
translation[1] = currentPosition[1] - this->m_lastMousePosition[1];
translation[2] = currentPosition[2] - this->m_lastMousePosition[2];
contour->ShiftSelectedVertex(translation);
this->m_lastMousePosition = positionEvent->GetWorldPosition();
assert( positionEvent->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
return true;
}
bool mitk::ContourModelInteractor::OnMoveContour( Action* action, const StateEvent* stateEvent)
{
const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent());
if (!positionEvent) return false;
int timestep = positionEvent->GetSender()->GetTimeStep();
mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() );
mitk::Vector3D translation;
mitk::Point3D currentPosition = positionEvent->GetWorldPosition();
translation[0] = currentPosition[0] - this->m_lastMousePosition[0];
translation[1] = currentPosition[1] - this->m_lastMousePosition[1];
translation[2] = currentPosition[2] - this->m_lastMousePosition[2];
contour->ShiftContour(translation, timestep);
this->m_lastMousePosition = positionEvent->GetWorldPosition();
assert( positionEvent->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
return true;
}
-bool mitk::ContourModelInteractor::OnFinish( Action* action, const StateEvent* stateEvent)
+bool mitk::ContourModelInteractor::OnFinishEditing( Action* action, const StateEvent* stateEvent)
{
-
mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() );
contour->Deselect();
assert( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
return true;
}
diff --git a/Modules/Segmentation/Interactions/mitkContourModelInteractor.h b/Modules/Segmentation/Interactions/mitkContourModelInteractor.h
index 569f908c1b..dfbc5ad0b2 100644
--- a/Modules/Segmentation/Interactions/mitkContourModelInteractor.h
+++ b/Modules/Segmentation/Interactions/mitkContourModelInteractor.h
@@ -1,79 +1,80 @@
/*===================================================================
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 mitkContourModelInteractor_h_Included
#define mitkContourModelInteractor_h_Included
#include "mitkCommon.h"
#include "SegmentationExports.h"
#include "mitkInteractor.h"
#include
#include
namespace mitk
{
/**
\brief
\sa Interactor
\ingroup Interaction
\ingroup ToolManagerEtAl
*/
class Segmentation_EXPORT ContourModelInteractor : public Interactor
{
public:
mitkClassMacro(ContourModelInteractor, Interactor);
mitkNewMacro1Param(Self, DataNode*);
/**
* \brief calculates how good the data, this statemachine handles, is hit
* by the event.
*
* overwritten, cause we don't look at the boundingbox, we look at each point
*/
virtual float CanHandleEvent(StateEvent const* stateEvent) const;
/**
*@brief If data changed then initialize according to numbers of loaded points
**/
virtual void DataChanged();
protected:
ContourModelInteractor(DataNode* dataNode); // purposely hidden
virtual ~ContourModelInteractor();
virtual bool OnCheckPointClick (Action*, const StateEvent*);
virtual bool OnCheckContourClick (Action*, const StateEvent*);
virtual bool OnDeletePoint(Action*, const StateEvent*);
virtual bool OnMovePoint(Action*, const StateEvent*);
+ virtual bool OnMove(Action*, const StateEvent*);
virtual bool OnMoveContour(Action*, const StateEvent*);
- virtual bool OnFinish(Action*, const StateEvent*);
+ virtual bool OnFinishEditing(Action*, const StateEvent*);
mitk::Point3D m_lastMousePosition;
};
} // namespace
#endif
diff --git a/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp
index 71fdceeff9..1cbf067bf6 100644
--- a/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp
+++ b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp
@@ -1,349 +1,475 @@
/*===================================================================
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();
- mitk::ContourModel::Pointer m_ContourLeft = mitk::ContourModel::New();
- mitk::ContourModel::Pointer m_ContourRight = mitk::ContourModel::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) {
+
+ 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() );
-
+ 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
- */
+ // 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();
-
- assert( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
- mitk::RenderingManager::GetInstance()->RequestUpdate( stateEvent->GetEvent()->GetSender()->GetRenderWindow() );
- newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent());
- m_lastMousePosition = click;
+ contour->SetSelectedVertexAsControlPoint(false);
+ //m_lastMousePosition = click;
- mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() );
-
- //
m_ContourLeft = mitk::ContourModel::New();
//get coordinates of next active vertex downwards from selected vertex
- int downIndex = SplitContourFromSelectedVertex( contour, m_ContourLeft, false, timestep);
-
- mitk::ContourModel::VertexIterator itDown = contour->IteratorBegin() + downIndex;
- m_NextActiveVertexDown = (*itDown)->Coordinates;
+ 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 = SplitContourFromSelectedVertex( contour, m_ContourRight, true, timestep);
+ 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();
- mitk::ContourModel::VertexIterator itUp = contour->IteratorBegin() + upIndex;
- m_NextActiveVertexUp = (*itUp)->Coordinates;
+ // 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())
+ if (contour->GetSelectedVertex())
{
mitk::ContourModel::Pointer newContour = mitk::ContourModel::New();
newContour->Expand(contour->GetTimeSteps());
- newContour->Concatenate( m_ContourLeft, timestep );
+ newContour->Concatenate( m_ContourLeft, timestep );
//recompute contour between neighbored two active control points
- this->m_LiveWireFilter->SetStartPoint( m_NextActiveVertexDown );
- this->m_LiveWireFilter->SetEndPoint( m_NextActiveVertexUp );
+ this->m_LiveWireFilter->SetStartPoint( this->m_NextActiveVertexDown );
+ this->m_LiveWireFilter->SetEndPoint( this->m_NextActiveVertexUp );
+ // this->m_LiveWireFilter->ClearRepulsivePoints();
this->m_LiveWireFilter->Update();
- mitk::ContourModel::Pointer liveWireContour = mitk::ContourModel::New();
- liveWireContour = this->m_LiveWireFilter->GetOutput();
+ 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 liveWire computed points
+ //insert new live wire computed points
newContour->Concatenate( liveWireContour, timestep );
- newContour->Concatenate( m_ContourRight, 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 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 newContour = mitk::ContourModel::New();
- newContour->Expand(contour->GetTimeSteps());
-
- /*++++++++++++++ concatenate LEFT ++++++++++++++++++++++++++++++*/
- newContour->Concatenate( m_ContourLeft, timestep );
-
-
- mitk::Point3D currentPosition = positionEvent->GetWorldPosition();
+ // 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) );
+ }
+ }
- /*+++++++++++++++ start computation ++++++++++++++++++++*/
- //recompute contour between previous active vertex and selected vertex
- this->m_LiveWireFilter->SetStartPoint( m_NextActiveVertexDown );
- this->m_LiveWireFilter->SetEndPoint( currentPosition );
+ // 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 liveWireContour = mitk::ContourModel::New();
- liveWireContour = this->m_LiveWireFilter->GetOutput();
+ mitk::ContourModel::Pointer leftLiveWire = this->m_LiveWireFilter->GetOutput();
+ assert ( leftLiveWire );
+
+ if ( !leftLiveWire->IsEmpty(timestep) )
+ leftLiveWire->RemoveVertexAt(0, timestep);
- //remove point at current position because it is included in next livewire segment too.
- liveWireContour->RemoveVertexAt( liveWireContour->GetNumberOfVertices(timestep) - 1, timestep);
+ // at this point the container has to be empty
+ m_ContourBeingModified.clear();
- /*++++++++++++++ concatenate LIVEWIRE ++++++++++++++++++++++++++++++*/
- //insert new liveWire computed points
- newContour->Concatenate( liveWireContour, timestep );
+ // 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 contour between selected vertex and next active vertex
+ // 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();
- liveWireContour = this->m_LiveWireFilter->GetOutput();
+ 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);
+
+// 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);
+ }
+*/
- //make point at mouse position active again, so it is drawn
- const_cast( liveWireContour->GetVertexAt(0, timestep) )->IsControlPoint = true;
+ mitk::ContourModel::Pointer editingContour = mitk::ContourModel::New();
+ editingContour->Expand(contour->GetTimeSteps());
- /*++++++++++++++ concatenate RIGHT ++++++++++++++++++++++++++++++*/
- //insert new liveWire computed points
- newContour->Concatenate( liveWireContour, timestep );
- /*------------------------------------------------*/
+ editingContour->Concatenate( leftLiveWire, timestep );
+ editingContour->Concatenate( rightLiveWire, timestep );
+ m_EditingContourNode->SetData(editingContour);
- newContour->Concatenate( m_ContourRight, timestep );
+ 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);
+ }
+
+ // set last inserted vertex as selected
+ newContour->SelectVertexAt(newContour->GetNumberOfVertices()-1, timestep);
+
+ // 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);
- newContour->Deselect();//just to make sure
+
m_DataNode->SetData(newContour);
- this->m_lastMousePosition = positionEvent->GetWorldPosition();
+ //this->m_lastMousePosition = positionEvent->GetWorldPosition();
assert( positionEvent->GetSender()->GetRenderWindow() );
mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() );
return true;
}
-
-
-int mitk::ContourModelLiveWireInteractor::SplitContourFromSelectedVertex(mitk::ContourModel* sourceContour, mitk::ContourModel* destinationContour, bool fromSelectedUpwards, int timestep)
+int mitk::ContourModelLiveWireInteractor::SplitContourFromSelectedVertex(mitk::ContourModel* srcContour,
+ mitk::ContourModel* destContour,
+ bool fromSelectedUpwards, int timestep)
{
- mitk::ContourModel::VertexIterator end =sourceContour->IteratorEnd();
- mitk::ContourModel::VertexIterator begin =sourceContour->IteratorBegin();
+ 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 = sourceContour->IteratorBegin();
-
+ mitk::ContourModel::VertexIterator itSelected = begin;
- //move iterator to position
- while((*itSelected) != sourceContour->GetSelectedVertex())
+ // move iterator to position
+ while ((*itSelected) != srcContour->GetSelectedVertex())
{
itSelected++;
}
- //CASE search upwards for next control point
+ // CASE search upwards for next control point
if(fromSelectedUpwards)
{
mitk::ContourModel::VertexIterator itUp = itSelected;
if(itUp != end)
{
- itUp++;//step once up otherwise the the loop breaks immediately
+ itUp++;//step once up otherwise the loop breaks immediately
}
- while( itUp != end && !((*itUp)->IsControlPoint)){ itUp++; }
+ while( itUp != end && !((*itUp)->IsControlPoint))
+ {
+ itUp++;
+ }
mitk::ContourModel::VertexIterator it = itUp;
-
- if(itSelected != begin)
+ if (itSelected != begin)
{
//copy the rest of the original contour
- while(it != end)
+ while (it != end)
{
- destinationContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
+ 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 = sourceContour->IteratorBegin();
+ 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
- destinationContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
+ destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
it++;
}
//copy from begin to itDown
while(it <= itDown)
{
- destinationContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
+ 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
- destinationContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
+ destContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
it++;
}
}
-
-
+/*
//add vertex at itDown - it's not considered during while loop
if( it != begin && it != end)
{
- //destinationContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep);
+ //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/mitkContourModelLiveWireInteractor.h b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.h
index ae44899f95..c0964cbd7d 100644
--- a/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.h
+++ b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.h
@@ -1,89 +1,87 @@
/*===================================================================
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 mitkContourModelLiveWireInteractor_h_Included
#define mitkContourModelLiveWireInteractor_h_Included
#include "mitkCommon.h"
#include "SegmentationExports.h"
#include "mitkContourModelInteractor.h"
-#include
-#include
#include
namespace mitk
{
/**
\brief
\sa Interactor
\sa ContourModelInteractor
\ingroup Interaction
\warning Make sure the working image is properly set, otherwise the algorithm for computing livewire contour segments will not work!
*/
class Segmentation_EXPORT ContourModelLiveWireInteractor : public ContourModelInteractor
{
public:
mitkClassMacro(ContourModelLiveWireInteractor, ContourModelInteractor);
mitkNewMacro1Param(Self, DataNode*);
+ virtual void SetEditingContourModelNode (mitk::DataNode* _arg);
- virtual void SetWorkingImage (mitk::Image* _arg)
- {
- if (this->m_WorkingImage != _arg)
- {
- this->m_WorkingImage = _arg;
- this->m_LiveWireFilter->SetInput(this->m_WorkingImage);
- this->Modified();
- }
- }
+ virtual void SetWorkingImage (mitk::Image* _arg);
protected:
ContourModelLiveWireInteractor(DataNode* dataNode);
virtual ~ContourModelLiveWireInteractor();
-
virtual bool OnDeletePoint(Action*, const StateEvent*);
virtual bool OnMovePoint(Action*, const StateEvent*);
virtual bool OnCheckPointClick( Action* action, const StateEvent* stateEvent);
+ virtual bool OnFinishEditing( Action* action, const StateEvent* stateEvent);
- int SplitContourFromSelectedVertex(mitk::ContourModel* sourceContour,
- mitk::ContourModel* destinationContour,
- bool fromSelectedUpwards,
- int timestep);
+ int SplitContourFromSelectedVertex(mitk::ContourModel* srcContour,
+ mitk::ContourModel* destContour,
+ bool fromSelectedUpwards,
+ int timestep);
mitk::ImageLiveWireContourModelFilter::Pointer m_LiveWireFilter;
- mitk::Image::Pointer m_WorkingImage;
+ mitk::Image::Pointer m_WorkingSlice;
mitk::Point3D m_NextActiveVertexDown;
mitk::Point3D m_NextActiveVertexUp;
+
+ mitk::ContourModel::VertexIterator m_NextActiveVertexDownIter;
+ mitk::ContourModel::VertexIterator m_NextActiveVertexUpIter;
+
+ std::vector < itk::Index<2> > m_ContourBeingModified;
+
+ mitk::DataNode::Pointer m_EditingContourNode;
mitk::ContourModel::Pointer m_ContourLeft;
mitk::ContourModel::Pointer m_ContourRight;
};
-} // namespace
+} // namespace mitk
-#endif
+#endif // mitkContourModelLiveWireInteractor_h_Included
diff --git a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp
index 20082f9f8e..dd4c40390d 100644
--- a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp
+++ b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp
@@ -1,653 +1,630 @@
/*===================================================================
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
#include "mitkContourUtils.h"
#include "mitkContour.h"
#include
namespace mitk {
MITK_TOOL_MACRO(Segmentation_EXPORT, LiveWireTool2D, "LiveWire tool");
}
-
mitk::LiveWireTool2D::LiveWireTool2D()
:SegTool2D("LiveWireTool")
{
- m_Contour = mitk::ContourModel::New();
- m_ContourModelNode = mitk::DataNode::New();
- m_ContourModelNode->SetData( m_Contour );
- m_ContourModelNode->SetProperty("name", StringProperty::New("working contour node"));
- m_ContourModelNode->SetProperty("visible", BoolProperty::New(true));
- m_ContourModelNode->AddProperty( "contour.color", ColorProperty::New(0.9, 1.0, 0.1), NULL, true );
- m_ContourModelNode->AddProperty( "selectedcolor", ColorProperty::New(1.0, 0.0, 0.1), NULL, true );
-
-
- m_LiveWireContour = mitk::ContourModel::New();
- m_LiveWireContourNode = mitk::DataNode::New();
- //m_LiveWireContourNode->SetData( m_LiveWireContour );
- m_LiveWireContourNode->SetProperty("name", StringProperty::New("active livewire node"));
- m_LiveWireContourNode->SetProperty("visible", BoolProperty::New(true));
- m_LiveWireContourNode->AddProperty( "contour.color", ColorProperty::New(0.1, 1.0, 0.1), NULL, true );
- m_LiveWireContourNode->AddProperty( "selectedcolor", ColorProperty::New(0.5, 0.5, 0.1), NULL, true );
-
-
- m_LiveWireFilter = mitk::ImageLiveWireContourModelFilter::New();
-
// 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()
{
- m_Contours.clear();
+ 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;
}
const char* mitk::LiveWireTool2D::GetName() const
{
return "LiveWire";
}
void mitk::LiveWireTool2D::Activated()
{
Superclass::Activated();
}
void mitk::LiveWireTool2D::Deactivated()
{
- this->FinishTool();
-
DataNode* workingNode( m_ToolManager->GetWorkingData(0) );
- if ( !workingNode ) return;
+ assert ( workingNode );
Image* workingImage = dynamic_cast(workingNode->GetData());
- if ( !workingImage ) return;
+ assert ( workingImage );
ContourUtils::Pointer contourUtils = mitk::ContourUtils::New();
- /*+++++++++++++++++++++++ for all contours in list (currently created by tool) ++++++++++++++++++++++++++++++++++++*/
- std::vector< std::pair >::iterator it = m_Contours.begin();
- while(it != m_Contours.end() )
+ // 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( it->first->GetData() )
+ // if node contains data
+ if( itWorkingContours->first->GetData() )
{
- //+++++++++++++++if this is a contourModel
- mitk::ContourModel* contourModel = dynamic_cast(it->first->GetData());
+ // if this is a contourModel
+ mitk::ContourModel* contourModel = dynamic_cast