Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
mitkContourModelUtils.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 
17 #include "mitkContourModelUtils.h"
18 #include "mitkImageAccessByItk.h"
19 #include "mitkImageCast.h"
20 
21 #include "itkCastImageFilter.h"
22 #include "mitkContourModel.h"
24 #include "mitkImage.h"
25 #include "mitkImageVtkAccessor.h"
26 #include "mitkSurface.h"
27 #include "vtkImageData.h"
28 #include "vtkImageLogic.h"
29 #include "vtkImageStencil.h"
30 #include "vtkPointData.h"
31 #include "vtkPolyData.h"
32 #include "vtkPolyDataToImageStencil.h"
33 #include "vtkSmartPointer.h"
34 
35 #include "mitkLabelSetImage.h"
36 
38 {
39 }
40 
42 {
43 }
44 
46  Image *slice, ContourModel *contourIn3D, bool itkNotUsed(correctionForIpSegmentation), bool constrainToInside)
47 {
48  if (!slice || !contourIn3D)
49  return nullptr;
50 
51  ContourModel::Pointer projectedContour = ContourModel::New();
52  projectedContour->Initialize(*contourIn3D);
53 
54  const BaseGeometry *sliceGeometry = slice->GetGeometry();
55 
56  int numberOfTimesteps = contourIn3D->GetTimeGeometry()->CountTimeSteps();
57 
58  for (int currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++)
59  {
60  auto iter = contourIn3D->Begin(currentTimestep);
61  auto end = contourIn3D->End(currentTimestep);
62 
63  while (iter != end)
64  {
65  Point3D currentPointIn3D = (*iter)->Coordinates;
66 
67  Point3D projectedPointIn2D;
68  projectedPointIn2D.Fill(0.0);
69  sliceGeometry->WorldToIndex(currentPointIn3D, projectedPointIn2D);
70  // MITK_INFO << "world point " << currentPointIn3D << " in index is " << projectedPointIn2D;
71 
72  if (!sliceGeometry->IsIndexInside(projectedPointIn2D) && constrainToInside)
73  {
74  MITK_DEBUG << "**" << currentPointIn3D << " is " << projectedPointIn2D << " --> correct it (TODO)" << std::endl;
75  }
76 
77  projectedContour->AddVertex(projectedPointIn2D, currentTimestep);
78  iter++;
79  }
80  }
81 
82  return projectedContour;
83 }
84 
86  const BaseGeometry *sliceGeometry, ContourModel *contourIn2D, bool itkNotUsed(correctionForIpSegmentation))
87 {
88  if (!sliceGeometry || !contourIn2D)
89  return nullptr;
90 
92  worldContour->Initialize(*contourIn2D);
93 
94  int numberOfTimesteps = contourIn2D->GetTimeGeometry()->CountTimeSteps();
95 
96  for (int currentTimestep = 0; currentTimestep < numberOfTimesteps; currentTimestep++)
97  {
98  auto iter = contourIn2D->Begin(currentTimestep);
99  auto end = contourIn2D->End(currentTimestep);
100 
101  while (iter != end)
102  {
103  Point3D currentPointIn2D = (*iter)->Coordinates;
104 
105  Point3D worldPointIn3D;
106  worldPointIn3D.Fill(0.0);
107  sliceGeometry->IndexToWorld(currentPointIn2D, worldPointIn3D);
108  // MITK_INFO << "index " << currentPointIn2D << " world " << worldPointIn3D << std::endl;
109 
110  worldContour->AddVertex(worldPointIn3D, currentTimestep);
111  iter++;
112  }
113  }
114 
115  return worldContour;
116 }
117 
119  Image *sliceImage,
120  mitk::Image::Pointer workingImage,
121  int paintingPixelValue)
122 {
123  mitk::ContourModelUtils::FillContourInSlice(projectedContour, 0, sliceImage, workingImage, paintingPixelValue);
124 }
125 
127  unsigned int timeStep,
128  Image *sliceImage,
129  mitk::Image::Pointer workingImage,
130  int paintingPixelValue)
131 {
132  // create a surface of the input ContourModel
135  contourModelFilter->SetInput(projectedContour);
136  contourModelFilter->Update();
137  surface = contourModelFilter->GetOutput();
138 
139  // that's our vtkPolyData-Surface
140  vtkSmartPointer<vtkPolyData> surface2D = vtkSmartPointer<vtkPolyData>::New();
141  if (surface->GetVtkPolyData(timeStep) == nullptr)
142  {
143  MITK_WARN << "No surface has been created from contour model. Add more points to fill contour in slice.";
144  return;
145  }
146  surface2D->SetPoints(surface->GetVtkPolyData(timeStep)->GetPoints());
147  surface2D->SetLines(surface->GetVtkPolyData(timeStep)->GetLines());
148  surface2D->Modified();
149  // surface2D->Update();
150 
151  // prepare the binary image's voxel grid
152  vtkSmartPointer<vtkImageData> whiteImage = vtkSmartPointer<vtkImageData>::New();
153  whiteImage->DeepCopy(sliceImage->GetVtkImageData());
154 
155  // fill the image with foreground voxels:
156  unsigned char inval = 255;
157  unsigned char outval = 0;
158  vtkIdType count = whiteImage->GetNumberOfPoints();
159  for (vtkIdType i = 0; i < count; ++i)
160  {
161  whiteImage->GetPointData()->GetScalars()->SetTuple1(i, inval);
162  }
163  // polygonal data --> image stencil:
164  vtkSmartPointer<vtkPolyDataToImageStencil> pol2stenc = vtkSmartPointer<vtkPolyDataToImageStencil>::New();
165 
166  // Set a minimal tolerance, so that clipped pixels will be added to contour as well.
167  pol2stenc->SetTolerance(mitk::eps);
168  pol2stenc->SetInputData(surface2D);
169  pol2stenc->Update();
170 
171  // cut the corresponding white image and set the background:
172  vtkSmartPointer<vtkImageStencil> imgstenc = vtkSmartPointer<vtkImageStencil>::New();
173 
174  imgstenc->SetInputData(whiteImage);
175  imgstenc->SetStencilConnection(pol2stenc->GetOutputPort());
176  imgstenc->ReverseStencilOff();
177  imgstenc->SetBackgroundValue(outval);
178  imgstenc->Update();
179 
180  // Fill according to the Color Team
181  vtkSmartPointer<vtkImageData> filledImage = imgstenc->GetOutput();
182  vtkSmartPointer<vtkImageData> resultImage = sliceImage->GetVtkImageData();
183  FillSliceInSlice(filledImage, resultImage, workingImage, paintingPixelValue);
184 
185  sliceImage->SetVolume(resultImage->GetScalarPointer());
186 }
187 
188 void mitk::ContourModelUtils::FillSliceInSlice(vtkSmartPointer<vtkImageData> filledImage,
189  vtkSmartPointer<vtkImageData> resultImage,
190  mitk::Image::Pointer image,
191  int paintingPixelValue)
192 {
193  mitk::LabelSetImage *labelImage; // Todo: Get the working Image
194  labelImage = dynamic_cast<LabelSetImage *>(image.GetPointer());
195  int count = filledImage->GetNumberOfPoints();
196 
197  // if image is not a LabelSetImage just paint or erase
198  if (!labelImage)
199  {
200  for (vtkIdType i = 0; i < count; ++i)
201  {
202  if (filledImage->GetPointData()->GetScalars()->GetTuple1(i) > 1)
203  {
204  resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue);
205  }
206  }
207  }
208 
209  // now for LabelSetImages
210  else
211  {
212  auto backgroundValue = labelImage->GetExteriorLabel()->GetValue();
213 
214  // paint, but do not overwrite locked pixels
215  if (paintingPixelValue != backgroundValue)
216  {
217  for (vtkIdType i = 0; i < count; ++i)
218  {
219  if (filledImage->GetPointData()->GetScalars()->GetTuple1(i) > 1)
220  {
221  auto existingValue = resultImage->GetPointData()->GetScalars()->GetTuple1(i);
222  if (!labelImage->GetLabel(existingValue, labelImage->GetActiveLayer())->GetLocked())
223  {
224  resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue);
225  }
226  }
227  }
228  }
229 
230  // erase, but only active label (regardless of locked state)
231  else
232  {
233  auto activePixelValue = labelImage->GetActiveLabel(labelImage->GetActiveLayer())->GetValue();
234 
235  for (vtkIdType i = 0; i < count; ++i)
236  {
237  if (filledImage->GetPointData()->GetScalars()->GetTuple1(i) > 1)
238  {
239  if (resultImage->GetPointData()->GetScalars()->GetTuple1(i) == activePixelValue)
240  {
241  resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue);
242  }
243  }
244  }
245  }
246  }
247 }
static ContourModel::Pointer BackProjectContourFrom2DSlice(const BaseGeometry *sliceGeometry, ContourModel *contourIn2D, bool correctionForIpSegmentation=false)
Projects a slice index coordinates of a contour back into world coordinates.
ContourModel is a structure of linked vertices defining a contour in 3D space. The vertices are store...
VertexIterator End(int timestep=0) const
Returns a const VertexIterator at the end element of the contour.
static void FillContourInSlice(ContourModel *projectedContour, Image *sliceImage, mitk::Image::Pointer workingImage, int paintingPixelValue=1)
Fill a contour in a 2D slice with a specified pixel value at time step 0.
bool IsIndexInside(const mitk::Point3D &index) const
Test whether the point p ((continous!)index coordinates in units) is inside the bounding box...
#define MITK_DEBUG
Definition: mitkLogMacros.h:26
mitk::Label * GetLabel(PixelType pixelValue, unsigned int layer=0) const
Returns the mitk::Label with the given pixelValue and for the given layer.
virtual vtkImageData * GetVtkImageData(int t=0, int n=0)
Get a volume at a specific time t of channel n as a vtkImageData.
Definition: mitkImage.cpp:221
const mitk::TimeGeometry * GetTimeGeometry() const
Return the TimeGeometry of the data as const pointer.
Definition: mitkBaseData.h:52
mitk::Label * GetExteriorLabel()
Gets the mitk::Label which is used as default exterior label.
virtual bool SetVolume(const void *data, int t=0, int n=0)
Set data as volume at time t in channel n. It is in the responsibility of the caller to ensure that t...
Definition: mitkImage.cpp:673
#define MITK_WARN
Definition: mitkLogMacros.h:23
Image class for storing images.
Definition: mitkImage.h:76
static ContourModel::Pointer ProjectContourTo2DSlice(Image *slice, ContourModel *contourIn3D, bool correctionForIpSegmentation, bool constrainToInside)
Projects a contour onto an image point by point. Converts from world to index coordinates.
mitk::Label * GetActiveLabel(unsigned int layer=0)
Returns the active label of a specific layer.
void IndexToWorld(const mitk::Vector3D &vec_units, mitk::Vector3D &vec_mm) const
Convert (continuous or discrete) index coordinates of a vector vec_units to world coordinates (in mm)...
LabelSetImage class for handling labels and layers in a segmentation session.
VertexIterator Begin(int timestep=0) const
Returns a const VertexIterator at the start element of the contour.
MITKCORE_EXPORT const ScalarType eps
static Pointer New()
static void FillSliceInSlice(vtkSmartPointer< vtkImageData > filledImage, vtkSmartPointer< vtkImageData > resultImage, mitk::Image::Pointer image, int paintingPixelValue)
Fills a image (filledImage) into another image (resultImage) by incorporating the rules of LabelSet-I...
unsigned int GetActiveLayer() const
Gets the ID of the currently active layer.
PixelType GetValue() const
Definition: mitkLabel.cpp:171
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
Definition: mitkBaseData.h:129
static Pointer New()
BaseGeometry Describes the geometry of a data object.
void WorldToIndex(const mitk::Point3D &pt_mm, mitk::Point3D &pt_units) const
Convert world coordinates (in mm) of a point to (continuous!) index coordinates.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.