Medical Imaging Interaction Toolkit  2018.4.99-b585543d
Medical Imaging Interaction Toolkit
mitkShowSegmentationAsSurface.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 (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
16 #include <mitkCoreObjectFactory.h>
17 #include <mitkLabelSetImage.h>
18 #include <vtkPolyDataNormals.h>
19 
20 namespace mitk
21 {
23  : m_UIDGeneratorSurfaces("Surface_"),
24  m_IsLabelSetImage(false)
25  {
26  }
27 
29  {
30  }
31 
33  {
34  Superclass::Initialize(other);
35 
36  bool syncVisibility(false);
37 
38  if (other)
39  {
40  other->GetParameter("Sync visibility", syncVisibility);
41  }
42 
43  SetParameter("Sync visibility", syncVisibility);
44  SetParameter("Median kernel size", 3u);
45  SetParameter("Apply median", true);
46  SetParameter("Smooth", true);
47  SetParameter("Gaussian SD", 1.5);
48  SetParameter("Decimate mesh", true);
49  SetParameter("Decimation rate", 0.8);
50  SetParameter("Wireframe", false);
51 
52  m_SurfaceNodes.clear();
53  }
54 
56  {
57  try
58  {
60  GetPointerParameter("Input", image);
61 
62  return image.IsNotNull() && GetGroupNode();
63  }
64  catch (std::invalid_argument &)
65  {
66  return false;
67  }
68  }
69 
71  {
73  GetPointerParameter("Input", image);
74 
75  bool smooth(true);
76  GetParameter("Smooth", smooth);
77 
78  bool applyMedian(true);
79  GetParameter("Apply median", applyMedian);
80 
81  bool decimateMesh(true);
82  GetParameter("Decimate mesh", decimateMesh);
83 
84  unsigned int medianKernelSize(3);
85  GetParameter("Median kernel size", medianKernelSize);
86 
87  double gaussianSD(1.5);
88  GetParameter("Gaussian SD", gaussianSD);
89 
90  double reductionRate(0.8);
91  GetParameter("Decimation rate", reductionRate);
92 
93  MITK_INFO << "Creating polygon model with smoothing " << smooth << " gaussianSD " << gaussianSD << " median "
94  << applyMedian << " median kernel " << medianKernelSize << " mesh reduction " << decimateMesh
95  << " reductionRate " << reductionRate;
96 
97  auto labelSetImage = dynamic_cast<LabelSetImage *>(image.GetPointer());
98 
99  if (nullptr != labelSetImage)
100  {
101  auto numberOfLayers = labelSetImage->GetNumberOfLayers();
102 
103  for (decltype(numberOfLayers) layerIndex = 0; layerIndex < numberOfLayers; ++layerIndex)
104  {
105  auto labelSet = labelSetImage->GetLabelSet(layerIndex);
106 
107  for (auto labelIter = labelSet->IteratorConstBegin(); labelIter != labelSet->IteratorConstEnd(); ++labelIter)
108  {
109  if (0 == labelIter->first)
110  continue; // Do not process background label
111 
112  auto labelImage = labelSetImage->CreateLabelMask(labelIter->first, false, layerIndex);
113 
114  if (labelImage.IsNull())
115  continue;
116 
117  auto labelSurface = this->ConvertBinaryImageToSurface(labelImage);
118 
119  if (labelSurface.IsNull())
120  continue;
121 
122  auto node = DataNode::New();
123  node->SetData(labelSurface);
124  node->SetColor(labelIter->second->GetColor());
125  node->SetName(labelIter->second->GetName());
126 
127  m_SurfaceNodes.push_back(node);
128  }
129  }
130  }
131  else
132  {
133  auto surface = this->ConvertBinaryImageToSurface(image);
134 
135  if (surface.IsNotNull())
136  {
137  auto node = DataNode::New();
138  node->SetData(surface);
139  m_SurfaceNodes.push_back(node);
140  }
141  }
142 
143  m_IsLabelSetImage = nullptr != labelSetImage;
144  return true;
145  }
146 
148  {
149  for (const auto &node : m_SurfaceNodes)
150  {
151  bool wireframe = false;
152  GetParameter("Wireframe", wireframe);
153 
154  if (wireframe)
155  {
156  auto representation = dynamic_cast<VtkRepresentationProperty *>(node->GetProperty("material.representation"));
157  if (nullptr != representation)
158  representation->SetRepresentationToWireframe();
159  }
160 
161  node->SetProperty("opacity", FloatProperty::New(0.3f));
162  node->SetProperty("line width", FloatProperty::New(1.0f));
163  node->SetProperty("scalar visibility", BoolProperty::New(false));
164 
165  auto name = node->GetName();
166  auto groupNode = this->GetGroupNode();
167 
168  if (!m_IsLabelSetImage)
169  {
170  if ((name.empty() || DataNode::NO_NAME_VALUE() == name) && nullptr != groupNode)
171  name = groupNode->GetName();
172 
173  if (name.empty())
174  name = "Surface";
175  }
176 
177  bool smooth = true;
178  GetParameter("Smooth", smooth);
179 
180  if (smooth)
181  name.append(" (smoothed)");
182 
183  node->SetName(name);
184 
185  if (!m_IsLabelSetImage)
186  {
187  auto colorProp = groupNode->GetProperty("color");
188 
189  if (nullptr != colorProp)
190  {
191  node->ReplaceProperty("color", colorProp->Clone());
192  }
193  else
194  {
195  node->SetProperty("color", ColorProperty::New(1.0, 1.0, 0.0));
196  }
197  }
198 
199  bool showResult = true;
200  GetParameter("Show result", showResult);
201 
202  bool syncVisibility = false;
203  GetParameter("Sync visibility", syncVisibility);
204 
205  auto visibleProp = groupNode->GetProperty("visible");
206 
207  if (nullptr != visibleProp && syncVisibility)
208  {
209  node->ReplaceProperty("visible", visibleProp->Clone());
210  }
211  else
212  {
213  node->SetProperty("visible", BoolProperty::New(showResult));
214  }
215 
216  if (!m_IsLabelSetImage)
217  {
219  GetPointerParameter("Input", image);
220 
221  if (image.IsNotNull())
222  {
223  auto organTypeProp = image->GetProperty("organ type");
224 
225  if (nullptr != organTypeProp)
226  node->GetData()->SetProperty("organ type", organTypeProp);
227  }
228  }
229 
230  this->InsertBelowGroupNode(node);
231  }
232 
233  Superclass::ThreadedUpdateSuccessful();
234  }
235 
236  Surface::Pointer ShowSegmentationAsSurface::ConvertBinaryImageToSurface(Image::Pointer binaryImage)
237  {
238  bool smooth = true;
239  GetParameter("Smooth", smooth);
240 
241  bool applyMedian = true;
242  GetParameter("Apply median", applyMedian);
243 
244  bool decimateMesh = true;
245  GetParameter("Decimate mesh", decimateMesh);
246 
247  unsigned int medianKernelSize = 3;
248  GetParameter("Median kernel size", medianKernelSize);
249 
250  double gaussianSD = 1.5;
251  GetParameter("Gaussian SD", gaussianSD);
252 
253  double reductionRate = 0.8;
254  GetParameter("Decimation rate", reductionRate);
255 
257  filter->SetInput(binaryImage);
258  filter->SetThreshold(0.5);
259  filter->SetUseGaussianImageSmooth(smooth);
260  filter->SetSmooth(smooth);
261  filter->SetMedianFilter3D(applyMedian);
262 
263  if (smooth)
264  {
265  filter->InterpolationOn();
266  filter->SetGaussianStandardDeviation(gaussianSD);
267  }
268 
269  if (applyMedian)
270  filter->SetMedianKernelSize(medianKernelSize, medianKernelSize, medianKernelSize);
271 
272  // Fix to avoid VTK warnings (see T5390)
273  if (binaryImage->GetDimension() > 3)
274  decimateMesh = false;
275 
276  if (decimateMesh)
277  {
278  filter->SetDecimate(ImageToSurfaceFilter::QuadricDecimation);
279  filter->SetTargetReduction(reductionRate);
280  }
281  else
282  {
283  filter->SetDecimate(ImageToSurfaceFilter::NoDecimation);
284  }
285 
286  filter->UpdateLargestPossibleRegion();
287 
288  auto surface = filter->GetOutput();
289  auto polyData = surface->GetVtkPolyData();
290 
291  if (nullptr == polyData)
292  throw std::logic_error("Could not create polygon model");
293 
294  polyData->SetVerts(nullptr);
295  polyData->SetLines(nullptr);
296 
297  if (smooth || applyMedian || decimateMesh)
298  {
299  auto normals = vtkSmartPointer<vtkPolyDataNormals>::New();
300 
301  normals->AutoOrientNormalsOn();
302  normals->FlipNormalsOff();
303  normals->SetInputData(polyData);
304 
305  normals->Update();
306 
307  surface->SetVtkPolyData(normals->GetOutput());
308  }
309  else
310  {
311  surface->SetVtkPolyData(polyData);
312  }
313 
314  return surface;
315  }
316 }
#define MITK_INFO
Definition: mitkLogMacros.h:18
void InsertBelowGroupNode(mitk::DataNode *node)
static Pointer New()
DataCollection - Class to facilitate loading/accessing structured data.
void SetParameter(const char *parameter, const T &value)
For any kind of normal types.
static std::string NO_NAME_VALUE()
Definition: mitkDataNode.h:393
void GetParameter(const char *parameter, T &value) const
static Pointer New()
unsigned int GetNumberOfLayers() const
static Pointer New()
void Initialize(const NonBlockingAlgorithm *other=nullptr) override
mitk::Image::Pointer image
static Pointer New()
LabelSetImage class for handling labels and layers in a segmentation session.
void GetPointerParameter(const char *parameter, itk::SmartPointer< T > &value) const