Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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.