CustusX  15.3.4-beta
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxContourFilter.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 #include "cxContourFilter.h"
34 
35 #include <vtkImageShrink3D.h>
36 #include <vtkMarchingCubes.h>
37 #include <vtkWindowedSincPolyDataFilter.h>
38 #include <vtkTriangleFilter.h>
39 #include <vtkDecimatePro.h>
40 #include <vtkPolyDataNormals.h>
41 #include <vtkImageData.h>
42 
43 
45 #include "cxTypeConversions.h"
46 #include "cxImage.h"
47 #include "cxMesh.h"
48 #include "cxDoubleProperty.h"
49 #include "cxBoolProperty.h"
50 #include "cxColorProperty.h"
52 #include "cxPatientModelService.h"
53 #include "cxViewService.h"
54 #include "cxVisServices.h"
55 
56 namespace cx
57 {
58 
60  FilterImpl(services)
61 {
62 }
63 
64 QString ContourFilter::getName() const
65 {
66  return "Contour";
67 }
68 
69 QString ContourFilter::getType() const
70 {
71  return "ContourFilter";
72 }
73 
74 QString ContourFilter::getHelp() const
75 {
76  return "<html>"
77  "<h3>Surfacing.</h3>"
78  "<p><i>Find the surface of a binary volume using marching cubes.</i></p>"
79  "<p>- Optional factor 2 reduction</p>"
80  "<p>- Marching Cubes contouring</p>"
81  "<p>- Optional Windowed Sinc smoothing</p>"
82  "<p>- Decimation of triangles</p>"
83  "</html>";
84 }
85 
87 {
88  return BoolProperty::initialize("Reduce input", "",
89  "Reduce input volumes resolution by a factor of 2 in all directions.", false, root);
90 }
91 
93 {
94  return BoolProperty::initialize("Smoothing", "",
95  "Smooth the output contour", true, root);
96 }
97 
99 {
100  return BoolProperty::initialize("Preserve mesh topology", "",
101  "Preserve mesh topology during reduction", true, root);
102 }
103 
105 {
106  DoublePropertyPtr retval = DoubleProperty::initialize("Threshold", "",
107  "Values from this threshold and above will be included",
108  100.0, DoubleRange(-1000, 1000, 1), 0, root);
109  retval->setGuiRepresentation(DoublePropertyBase::grSLIDER);
110  return retval;
111 }
112 
114 {
115  DoublePropertyPtr retval = DoubleProperty::initialize("Decimation %", "",
116  "Reduce number of triangles in output surface",
117  0.2, DoubleRange(0, 1, 0.01), 0, root);
118  retval->setInternal2Display(100);
119  return retval;
120 }
121 
123 {
124  return ColorProperty::initialize("Color", "",
125  "Color of output model.",
126  QColor("green"), root);
127 }
128 
130 {
131  mReduceResolutionOption = this->getReduceResolutionOption(mOptions);
132  mOptionsAdapters.push_back(mReduceResolutionOption);
133 
134  mSurfaceThresholdOption = this->getSurfaceThresholdOption(mOptions);
135  connect(mSurfaceThresholdOption.get(), SIGNAL(changed()), this, SLOT(thresholdSlot()));
136  mOptionsAdapters.push_back(mSurfaceThresholdOption);
137 
138  mOptionsAdapters.push_back(this->getSmoothingOption(mOptions));
141 
142  mOptionsAdapters.push_back(this->getColorOption(mOptions));
143 }
144 
146 {
148 
149  temp = StringPropertySelectImage::New(mServices->getPatientService());
150  temp->setValueName("Input");
151  temp->setHelp("Select image input for contouring");
152  connect(temp.get(), SIGNAL(dataChanged(QString)), this, SLOT(imageChangedSlot(QString)));
153  mInputTypes.push_back(temp);
154 }
155 
157 {
159 
160  temp = StringPropertySelectMesh::New(mServices->getPatientService());
161  temp->setValueName("Output");
162  temp->setHelp("Output contour");
163  mOutputTypes.push_back(temp);
164 }
165 
167 {
169 
170  if (!mActive)
171  mServices->visualizationService->removePreview();
172 }
173 
174 void ContourFilter::imageChangedSlot(QString uid)
175 {
176  ImagePtr image = mServices->getPatientService()->getData<Image>(uid);
177  if(!image)
178  return;
179 
180  this->updateThresholdFromImageChange(uid, mSurfaceThresholdOption);
181  mServices->visualizationService->removePreview();
182 
183  int extent[6];
184  image->getBaseVtkImageData()->GetExtent(extent);
185  mReduceResolutionOption->setHelp("Current input resolution: " + qstring_cast(extent[1])
186  + " " + qstring_cast(extent[3]) + " " + qstring_cast(extent[5])
187  + " (If checked: " + qstring_cast(extent[1]/2)+ " " + qstring_cast(extent[3]/2) + " "
188  + qstring_cast(extent[5]/2) + ")");
189 }
190 
191 void ContourFilter::thresholdSlot()
192 {
193  if (mActive)
194  {
195  ImagePtr image = boost::dynamic_pointer_cast<Image>(mInputTypes[0]->getData());
196  std::vector<double> threshold;
197  threshold.push_back(mSurfaceThresholdOption->getValue());
198  mServices->visualizationService->setPreview(image, threshold);
199  }
200 }
201 
203 {
204  mServices->visualizationService->removePreview();
205  return FilterImpl::preProcess();
206 }
207 
209 {
210  ImagePtr input = this->getCopiedInputImage();
211  if (!input)
212  return false;
213 
214  // std::cout << "ContourFilter::execute : " << mCopiedOptions.ownerDocument().toString() << std::endl;
215 
216  BoolPropertyPtr reduceResolutionOption = this->getReduceResolutionOption(mCopiedOptions);
217  BoolPropertyPtr smoothingOption = this->getSmoothingOption(mCopiedOptions);
218  BoolPropertyPtr preserveTopologyOption = this->getPreserveTopologyOption(mCopiedOptions);
219  DoublePropertyPtr surfaceThresholdOption = this->getSurfaceThresholdOption(mCopiedOptions);
220  DoublePropertyPtr decimationOption = this->getDecimationOption(mCopiedOptions);
221 
222  // report(QString("Creating contour from \"%1\"...").arg(input->getName()));
223 
224  mRawResult = this->execute(input->getBaseVtkImageData(),
225  surfaceThresholdOption->getValue(),
226  reduceResolutionOption->getValue(),
227  smoothingOption->getValue(),
228  preserveTopologyOption->getValue(),
229  decimationOption->getValue());
230  return true;
231 }
232 
234  double threshold,
235  bool reduceResolution,
236  bool smoothing,
237  bool preserveTopology,
238  double decimation)
239 {
240  if (!input)
241  return vtkPolyDataPtr();
242 
243  //Shrink input volume
244  vtkImageShrink3DPtr shrinker = vtkImageShrink3DPtr::New();
245  if(reduceResolution)
246  {
247 // std::cout << "smooth" << std::endl;
248  shrinker->SetInputData(input);
249  shrinker->SetShrinkFactors(2,2,2);
250  shrinker->Update();
251  }
252 
253  // Find countour
254  vtkMarchingCubesPtr convert = vtkMarchingCubesPtr::New();
255  if(reduceResolution)
256  convert->SetInputConnection(shrinker->GetOutputPort());
257  else
258  convert->SetInputData(input);
259 
260  convert->SetValue(0, threshold);
261  convert->Update();
262 
263  vtkPolyDataPtr cubesPolyData = convert->GetOutput();
264 // vtkPolyDataPtr cubesPolyData = vtkPolyDataPtr::New();
265 // cubesPolyData = convert->GetOutput();
266 // std::cout << "convert->GetOutput(); " << cubesPolyData.GetPointer() << std::endl;
267 
268  // Smooth surface model
269  vtkWindowedSincPolyDataFilterPtr smoother = vtkWindowedSincPolyDataFilterPtr::New();
270  if(smoothing)
271  {
272  smoother->SetInputData(cubesPolyData);
273  smoother->SetNumberOfIterations(15);// Higher number = more smoothing
274  smoother->SetBoundarySmoothing(false);
275  smoother->SetFeatureEdgeSmoothing(false);
276  smoother->SetNormalizeCoordinates(true);
277  smoother->SetFeatureAngle(120);
278  smoother->SetPassBand(0.3);//Lower number = more smoothing
279  smoother->Update();
280  cubesPolyData = smoother->GetOutput();
281  }
282 
283  //Create a surface of triangles
284 
285  //Decimate surface model (remove a percentage of the polygons)
286  vtkTriangleFilterPtr trifilt = vtkTriangleFilterPtr::New();
287  vtkDecimateProPtr deci = vtkDecimateProPtr::New();
288  vtkPolyDataNormalsPtr normals = vtkPolyDataNormalsPtr::New();
289  if (decimation > 0.000001)
290  {
291  trifilt->SetInputData(cubesPolyData);
292  trifilt->Update();
293  deci->SetInputConnection(trifilt->GetOutputPort());
294  deci->SetTargetReduction(decimation);
295  deci->SetPreserveTopology(preserveTopology);
296  // deci->PreserveTopologyOn();
297  deci->Update();
298  cubesPolyData = deci->GetOutput();
299  }
300 
301  normals->SetInputData(cubesPolyData);
302  normals->Update();
303 
304  cubesPolyData->DeepCopy(normals->GetOutput());
305 
306  return cubesPolyData;
307 }
308 
310 {
311  if (!mRawResult)
312  return false;
313 
314  ImagePtr input = this->getCopiedInputImage();
315 
316  if (!input)
317  return false;
318 
319  ColorPropertyPtr colorOption = this->getColorOption(mOptions);
320  MeshPtr output = this->postProcess(mServices->getPatientService(), mRawResult, input, colorOption->getValue());
321  mRawResult = NULL;
322 
323  if (output)
324  mOutputTypes.front()->setValue(output->getUid());
325 
326  return true;
327 }
328 
330 {
331  if (!contour || !base)
332  return MeshPtr();
333 
334  QString uid = base->getUid() + "_ge%1";
335  QString name = base->getName()+" ge%1";
336  MeshPtr output = patient->createSpecificData<Mesh>(uid, name);
337  output->setVtkPolyData(contour);
338  if (!output)
339  return MeshPtr();
340 
341  output->get_rMd_History()->setRegistration(base->get_rMd());
342  output->get_rMd_History()->setParentSpace(base->getUid());
343 
344  output->setColor(color);
345 
346  patient->insertData(output);
347 
348  return output;
349 }
350 
351 } // namespace cx
QString qstring_cast(const T &val)
vtkSmartPointer< class vtkDecimatePro > vtkDecimateProPtr
static BoolPropertyPtr initialize(const QString &uid, QString name, QString help, bool value, QDomNode root=QDomNode())
std::vector< SelectDataStringPropertyBasePtr > mInputTypes
Definition: cxFilterImpl.h:94
QDomElement mCopiedOptions
Definition: cxFilterImpl.h:101
A mesh data set.
Definition: cxMesh.h:61
DoublePropertyPtr getSurfaceThresholdOption(QDomElement root)
vtkSmartPointer< class vtkMarchingCubes > vtkMarchingCubesPtr
boost::shared_ptr< class ColorProperty > ColorPropertyPtr
virtual void createOptions()
boost::shared_ptr< class VisServices > VisServicesPtr
Definition: cxMainWindow.h:61
virtual void setActive(bool on)
virtual bool preProcess()
Utility class for describing a bounded numeric range.
Definition: cxDoubleRange.h:53
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:48
vtkSmartPointer< class vtkWindowedSincPolyDataFilter > vtkWindowedSincPolyDataFilterPtr
vtkSmartPointer< class vtkPolyData > vtkPolyDataPtr
Definition: cxProbeSector.h:47
ColorPropertyPtr getColorOption(QDomElement root)
BoolPropertyPtr getPreserveTopologyOption(QDomElement root)
std::vector< PropertyPtr > mOptionsAdapters
Definition: cxFilterImpl.h:96
boost::shared_ptr< class SelectDataStringPropertyBase > SelectDataStringPropertyBasePtr
virtual void createInputTypes()
virtual QString getHelp() const
virtual bool execute()
void setVtkPolyData(const vtkPolyDataPtr &polyData)
Definition: cxMesh.cpp:94
virtual QString getType() const
virtual void createOutputTypes()
BoolPropertyPtr getSmoothingOption(QDomElement root)
A volumetric data set.
Definition: cxImage.h:64
vtkSmartPointer< class vtkPolyDataNormals > vtkPolyDataNormalsPtr
DoublePropertyPtr getDecimationOption(QDomElement root)
boost::shared_ptr< class PatientModelService > PatientModelServicePtr
ContourFilter(VisServicesPtr services)
vtkSmartPointer< class vtkTriangleFilter > vtkTriangleFilterPtr
vtkSmartPointer< class vtkImageShrink3D > vtkImageShrink3DPtr
ImagePtr getCopiedInputImage(int index=0)
virtual void setActive(bool on)
QDomElement mOptions
Definition: cxFilterImpl.h:97
boost::shared_ptr< class DoubleProperty > DoublePropertyPtr
virtual QString getName() const
BoolPropertyPtr getReduceResolutionOption(QDomElement root)
std::vector< SelectDataStringPropertyBasePtr > mOutputTypes
Definition: cxFilterImpl.h:95
static DoublePropertyPtr initialize(const QString &uid, QString name, QString help, double value, DoubleRange range, int decimals, QDomNode root=QDomNode())
static StringPropertySelectMeshPtr New(PatientModelServicePtr patientModelService)
virtual bool postProcess()
static StringPropertySelectImagePtr New(PatientModelServicePtr patientModelService)
static ColorPropertyPtr initialize(const QString &uid, QString name, QString help, QColor value, QDomNode root=QDomNode())
boost::shared_ptr< class BoolProperty > BoolPropertyPtr
boost::shared_ptr< class Mesh > MeshPtr
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
void updateThresholdFromImageChange(QString uid, DoublePropertyPtr threshold)
void changed()