Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkPlanarFigureSegmentationController.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
18 
19 #include <vtkCellArray.h>
20 #include <vtkImageData.h>
21 #include <vtkPoints.h>
22 #include <vtkPolyData.h>
23 #include <vtkPolygon.h>
24 #include <vtkSmartPointer.h>
25 
26 #include <mitkIOUtil.h>
27 #include <mitkImageAccessByItk.h>
28 #include <mitkImageCast.h>
31 
33  : itk::Object(),
34  m_ReduceFilter(NULL),
35  m_NormalsFilter(NULL),
36  m_DistanceImageCreator(NULL),
37  m_ReferenceImage(NULL),
38  m_SegmentationAsImage(NULL)
39 {
41 }
42 
44 {
45 }
46 
48 {
49  m_ReferenceImage = referenceImage;
50 }
51 
53 {
54  if (planarFigure.IsNull())
55  return;
56 
57  bool newFigure = true;
58  std::size_t indexOfFigure = 0;
59  for (std::size_t i = 0; i < m_PlanarFigureList.size(); i++)
60  {
61  if (m_PlanarFigureList.at(i) == planarFigure)
62  {
63  indexOfFigure = i;
64  newFigure = false;
65  break;
66  }
67  }
68 
69  mitk::Surface::Pointer figureAsSurface = NULL;
70 
71  if (newFigure)
72  {
73  m_PlanarFigureList.push_back(planarFigure);
74  figureAsSurface = this->CreateSurfaceFromPlanarFigure(planarFigure);
75  m_SurfaceList.push_back(figureAsSurface);
76  if (!m_PlanarFigureList.empty())
77  {
78  indexOfFigure = m_PlanarFigureList.size() - 1;
79  }
80  }
81  else
82  {
83  figureAsSurface = this->CreateSurfaceFromPlanarFigure(planarFigure);
84  m_SurfaceList.at(indexOfFigure) = figureAsSurface;
85  }
86 
87  if (m_ReduceFilter.IsNull())
88  {
89  InitializeFilters();
90  }
91 
92  m_ReduceFilter->SetInput(indexOfFigure, figureAsSurface);
93 
94  m_NormalsFilter->SetInput(indexOfFigure, m_ReduceFilter->GetOutput(indexOfFigure));
95  m_DistanceImageCreator->SetInput(indexOfFigure, m_NormalsFilter->GetOutput(indexOfFigure));
96 }
97 
99 {
100  if (planarFigure.IsNull())
101  return;
102 
103  bool figureFound = false;
104  std::size_t indexOfFigure = 0;
105  for (std::size_t i = 0; i < m_PlanarFigureList.size(); i++)
106  {
107  if (m_PlanarFigureList.at(i) == planarFigure)
108  {
109  indexOfFigure = i;
110  figureFound = true;
111  break;
112  }
113  }
114 
115  if (!figureFound)
116  return;
117 
118  PlanarFigureListType::iterator whereIter = m_PlanarFigureList.begin();
119  whereIter += indexOfFigure;
120  m_PlanarFigureList.erase(whereIter);
121 
122  SurfaceListType::iterator surfaceIter = m_SurfaceList.begin();
123  surfaceIter += indexOfFigure;
124  m_SurfaceList.erase(surfaceIter);
125 
126  // TODO: fix this! The following code had to be removed as the method
127  // RemoveInputs() has been removed in ITK 4
128  // The remaining code works correctly but is slower
129  if (false && indexOfFigure == m_PlanarFigureList.size() - 1)
130  {
131  // Ff the removed figure was the last one in the list, we can simply
132  // remove the last input from each filter.
133  // m_DistanceImageCreator->RemoveInputs( m_NormalsFilter->GetOutput( indexOfFigure ) );
134  // m_NormalsFilter->RemoveInput( m_ReduceFilter->GetOutput( indexOfFigure ) );
135  // m_ReduceFilter->RemoveInput( const_cast<mitk::Surface*>(m_ReduceFilter->GetInput(indexOfFigure)) );
136  }
137  else
138  {
139  // this is not very nice! If the figure that has been removed is NOT the last
140  // one in the list we have to create new filters and add all remaining
141  // inputs again.
142  //
143  // Has to be done as the filters do not work when removing an input
144  // other than the last one.
145 
146  // create new filters
147  InitializeFilters();
148 
149  // and add all existing surfaces
150  SurfaceListType::iterator surfaceIter = m_SurfaceList.begin();
151  int index = 0;
152  for (surfaceIter = m_SurfaceList.begin(); surfaceIter != m_SurfaceList.end(); surfaceIter++)
153  {
154  m_ReduceFilter->SetInput(index, (*surfaceIter));
155  m_NormalsFilter->SetInput(index, m_ReduceFilter->GetOutput(index));
156  m_DistanceImageCreator->SetInput(index, m_NormalsFilter->GetOutput(index));
157 
158  ++index;
159  }
160  }
161 }
162 
163 template <typename TPixel, unsigned int VImageDimension>
164 void mitk::PlanarFigureSegmentationController::GetImageBase(itk::Image<TPixel, VImageDimension> *input,
166 {
167  result = input;
168 }
169 
171 {
172  m_SegmentationAsImage = NULL;
173 
174  if (m_PlanarFigureList.size() == 0)
175  {
176  m_SegmentationAsImage = mitk::Image::New();
177  m_SegmentationAsImage->Initialize(mitk::MakeScalarPixelType<unsigned char>(), *m_ReferenceImage->GetTimeGeometry());
178 
179  return m_SegmentationAsImage;
180  }
181 
183  AccessFixedDimensionByItk_1(m_ReferenceImage.GetPointer(), GetImageBase, 3, itkImage);
184  m_DistanceImageCreator->SetReferenceImage(itkImage.GetPointer());
185 
186  m_ReduceFilter->Update();
187  m_NormalsFilter->Update();
188  m_DistanceImageCreator->Update();
189 
190  mitk::Image::Pointer distanceImage = m_DistanceImageCreator->GetOutput();
191 
192  // Cleanup the pipeline
193  distanceImage->DisconnectPipeline();
194  m_DistanceImageCreator = NULL;
195  m_NormalsFilter = NULL;
196  m_ReduceFilter = NULL;
197  itkImage = NULL;
198 
199  // If this bool flag is true, the distanceImage will be written to the
200  // filesystem as nrrd-image and as surface-representation.
201  bool debugOutput(false);
202  if (debugOutput)
203  {
204  mitk::IOUtil::Save(distanceImage, "v:/DistanceImage.nrrd");
205  }
206 
208  imageToSurfaceFilter->SetInput(distanceImage);
209  imageToSurfaceFilter->SetThreshold(0);
210  imageToSurfaceFilter->Update();
211 
212  mitk::Surface::Pointer segmentationAsSurface = imageToSurfaceFilter->GetOutput();
213 
214  // Cleanup the pipeline
215  segmentationAsSurface->DisconnectPipeline();
216  imageToSurfaceFilter = NULL;
217 
218  if (debugOutput)
219  {
220  mitk::IOUtil::Save(segmentationAsSurface, "v:/DistanceImageAsSurface.vtk");
221  }
222 
224  surfaceToImageFilter->SetInput(segmentationAsSurface);
225  surfaceToImageFilter->SetImage(m_ReferenceImage);
226  surfaceToImageFilter->SetMakeOutputBinary(true);
227  surfaceToImageFilter->Update();
228 
229  m_SegmentationAsImage = surfaceToImageFilter->GetOutput();
230 
231  // Cleanup the pipeline
232  m_SegmentationAsImage->DisconnectPipeline();
233 
234  return m_SegmentationAsImage;
235 }
236 
239 {
240  if (figure.IsNull())
241  {
242  MITK_ERROR << "Given PlanarFigure is NULL. Please provide valid PlanarFigure.";
243  return NULL;
244  }
245 
247 
248  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
249  vtkSmartPointer<vtkPolygon> polygon = vtkSmartPointer<vtkPolygon>::New();
250  vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
251  vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
252 
253  const mitk::PlaneGeometry *figureGeometry = figure->GetPlaneGeometry();
254 
255  // Get the polyline
256  mitk::PlanarFigure::PolyLineType planarPolyLine = figure->GetPolyLine(0);
257  mitk::PlanarFigure::PolyLineType::iterator iter;
258 
259  // iterate over the polyline, ...
260  int pointCounter = 0;
261  for (iter = planarPolyLine.begin(); iter != planarPolyLine.end(); iter++)
262  {
263  // ... determine the world-coordinates
264  mitk::Point3D pointInWorldCoordiantes;
265  figureGeometry->Map(*iter, pointInWorldCoordiantes);
266 
267  // and add them as new points to the vtkPoints
268  points->InsertNextPoint(pointInWorldCoordiantes[0], pointInWorldCoordiantes[1], pointInWorldCoordiantes[2]);
269  ++pointCounter;
270  }
271 
272  // create a polygon with the points of the polyline
273  polygon->GetPointIds()->SetNumberOfIds(pointCounter);
274  for (int i = 0; i < pointCounter; i++)
275  {
276  polygon->GetPointIds()->SetId(i, i);
277  }
278 
279  // initialize the vtkCellArray and vtkPolyData
280  cells->InsertNextCell(polygon);
281  polyData->SetPoints(points);
282  polyData->SetPolys(cells);
283 
284  // set the polydata to the surface
285  newSurface->SetVtkPolyData(polyData);
286 
287  return newSurface;
288 }
289 
292 {
293  return m_PlanarFigureList;
294 }
295 
297 {
298  m_ReduceFilter = mitk::ReduceContourSetFilter::New();
299  m_ReduceFilter->SetReductionType(ReduceContourSetFilter::NTH_POINT);
300  m_ReduceFilter->SetStepSize(10);
301  m_NormalsFilter = mitk::ComputeContourSetNormalsFilter::New();
302  m_DistanceImageCreator = mitk::CreateDistanceImageFromSurfaceFilter::New();
303 }
static void Save(const mitk::BaseData *data, const std::string &path)
Save a mitk::BaseData instance.
Definition: mitkIOUtil.cpp:824
itk::SmartPointer< Self > Pointer
void SetReferenceImage(Image::Pointer referenceImage)
Setter for the reference image.
void RemovePlanarFigure(mitk::PlanarFigure::Pointer planarFigure)
virtual bool Map(const mitk::Point3D &pt3d_mm, mitk::Point2D &pt2d_mm) const
Project a 3D point given in mm (pt3d_mm) onto the 2D geometry. The result is a 2D point in mm (pt2d_m...
#define MITK_ERROR
Definition: mitkLogMacros.h:24
Image::Pointer GetInterpolationResult()
Performs the interpolation and returns the result as binary image.
void AddPlanarFigure(PlanarFigure::Pointer planarFigure)
Adds a new PlanarFigure to be considered in the interpolation.
void GetImageBase(itk::Image< TPixel, VImageDimension > *input, itk::ImageBase< 3 >::Pointer &result)
static Pointer New()
#define AccessFixedDimensionByItk_1(mitkImage, itkImageTypeFunction, dimension, arg1)
std::vector< PolyLineElement > PolyLineType
Describes a two-dimensional, rectangular plane.
static Pointer New()
static Surface::Pointer CreateSurfaceFromPlanarFigure(PlanarFigure::Pointer figure)
Method to create a surface from a PlanarFigure.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.