CustusX  16.5
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->patient());
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->patient());
161  temp->setValueName("Output");
162  temp->setHelp("Output contour");
163  mOutputTypes.push_back(temp);
164 }
165 
167 {
169 
170  if (!mActive)
171  this->stopPreview();
172 }
173 
174 void ContourFilter::stopPreview()
175 {
176  if(mPreviewImage)
177  mPreviewImage->stopThresholdPreview();
178  mPreviewImage.reset();
179 }
180 
181 void ContourFilter::imageChangedSlot(QString uid)
182 {
183  ImagePtr image = mServices->patient()->getData<Image>(uid);
184  if(!image)
185  return;
186 
187  this->updateThresholdFromImageChange(uid, mSurfaceThresholdOption);
188  this->stopPreview();
189 
190  int extent[6];
191  image->getBaseVtkImageData()->GetExtent(extent);
192  mReduceResolutionOption->setHelp("Current input resolution: " + qstring_cast(extent[1])
193  + " " + qstring_cast(extent[3]) + " " + qstring_cast(extent[5])
194  + " (If checked: " + qstring_cast(extent[1]/2)+ " " + qstring_cast(extent[3]/2) + " "
195  + qstring_cast(extent[5]/2) + ")");
196 }
197 
198 void ContourFilter::thresholdSlot()
199 {
200 // this->stopPreview();
201  if (mActive)
202  {
203  mPreviewImage = boost::dynamic_pointer_cast<Image>(mInputTypes[0]->getData());
204  Eigen::Vector2d threshold = Eigen::Vector2d(mSurfaceThresholdOption->getValue(), mPreviewImage->getMax());
205  mPreviewImage->startThresholdPreview(threshold);
206  }
207 }
208 
210 {
211  this->stopPreview();
212  return FilterImpl::preProcess();
213 }
214 
216 {
217  ImagePtr input = this->getCopiedInputImage();
218  if (!input)
219  return false;
220 
221  // std::cout << "ContourFilter::execute : " << mCopiedOptions.ownerDocument().toString() << std::endl;
222 
223  BoolPropertyPtr reduceResolutionOption = this->getReduceResolutionOption(mCopiedOptions);
224  BoolPropertyPtr smoothingOption = this->getSmoothingOption(mCopiedOptions);
225  BoolPropertyPtr preserveTopologyOption = this->getPreserveTopologyOption(mCopiedOptions);
226  DoublePropertyPtr surfaceThresholdOption = this->getSurfaceThresholdOption(mCopiedOptions);
227  DoublePropertyPtr decimationOption = this->getDecimationOption(mCopiedOptions);
228 
229  // report(QString("Creating contour from \"%1\"...").arg(input->getName()));
230 
231  mRawResult = this->execute(input->getBaseVtkImageData(),
232  surfaceThresholdOption->getValue(),
233  reduceResolutionOption->getValue(),
234  smoothingOption->getValue(),
235  preserveTopologyOption->getValue(),
236  decimationOption->getValue());
237  return true;
238 }
239 
241  double threshold,
242  bool reduceResolution,
243  bool smoothing,
244  bool preserveTopology,
245  double decimation)
246 {
247  if (!input)
248  return vtkPolyDataPtr();
249 
250  //Shrink input volume
251  vtkImageShrink3DPtr shrinker = vtkImageShrink3DPtr::New();
252  if(reduceResolution)
253  {
254 // std::cout << "smooth" << std::endl;
255  shrinker->SetInputData(input);
256  shrinker->SetShrinkFactors(2,2,2);
257  shrinker->Update();
258  }
259 
260  // Find countour
261  vtkMarchingCubesPtr convert = vtkMarchingCubesPtr::New();
262  if(reduceResolution)
263  convert->SetInputConnection(shrinker->GetOutputPort());
264  else
265  convert->SetInputData(input);
266 
267  convert->SetValue(0, threshold);
268  convert->Update();
269 
270  vtkPolyDataPtr cubesPolyData = convert->GetOutput();
271 // vtkPolyDataPtr cubesPolyData = vtkPolyDataPtr::New();
272 // cubesPolyData = convert->GetOutput();
273 // std::cout << "convert->GetOutput(); " << cubesPolyData.GetPointer() << std::endl;
274 
275  // Smooth surface model
276  vtkWindowedSincPolyDataFilterPtr smoother = vtkWindowedSincPolyDataFilterPtr::New();
277  if(smoothing)
278  {
279  smoother->SetInputData(cubesPolyData);
280  smoother->SetNumberOfIterations(15);// Higher number = more smoothing
281  smoother->SetBoundarySmoothing(false);
282  smoother->SetFeatureEdgeSmoothing(false);
283  smoother->SetNormalizeCoordinates(true);
284  smoother->SetFeatureAngle(120);
285  smoother->SetPassBand(0.3);//Lower number = more smoothing
286  smoother->Update();
287  cubesPolyData = smoother->GetOutput();
288  }
289 
290  //Create a surface of triangles
291 
292  //Decimate surface model (remove a percentage of the polygons)
293  vtkTriangleFilterPtr trifilt = vtkTriangleFilterPtr::New();
294  vtkDecimateProPtr deci = vtkDecimateProPtr::New();
295  vtkPolyDataNormalsPtr normals = vtkPolyDataNormalsPtr::New();
296  if (decimation > 0.000001)
297  {
298  trifilt->SetInputData(cubesPolyData);
299  trifilt->Update();
300  deci->SetInputConnection(trifilt->GetOutputPort());
301  deci->SetTargetReduction(decimation);
302  deci->SetPreserveTopology(preserveTopology);
303  // deci->PreserveTopologyOn();
304  deci->Update();
305  cubesPolyData = deci->GetOutput();
306  }
307 
308  normals->SetInputData(cubesPolyData);
309  normals->Update();
310 
311  cubesPolyData->DeepCopy(normals->GetOutput());
312 
313  return cubesPolyData;
314 }
315 
317 {
318  if (!mRawResult)
319  return false;
320 
321  ImagePtr input = this->getCopiedInputImage();
322 
323  if (!input)
324  return false;
325 
326  ColorPropertyPtr colorOption = this->getColorOption(mOptions);
327  MeshPtr output = this->postProcess(mServices->patient(), mRawResult, input, colorOption->getValue());
328  mRawResult = NULL;
329 
330  if (output)
331  mOutputTypes.front()->setValue(output->getUid());
332 
333  return true;
334 }
335 
337 {
338  if (!contour || !base)
339  return MeshPtr();
340 
341  QString uid = base->getUid() + "_ge%1";
342  QString name = base->getName()+" ge%1";
343  MeshPtr output = patient->createSpecificData<Mesh>(uid, name);
344  output->setVtkPolyData(contour);
345  if (!output)
346  return MeshPtr();
347 
348  output->get_rMd_History()->setRegistration(base->get_rMd());
349  output->get_rMd_History()->setParentSpace(base->getUid());
350 
351  output->setColor(color);
352 
353  patient->insertData(output);
354 
355  return output;
356 }
357 
358 } // 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:62
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
ColorPropertyPtr getColorOption(QDomElement root)
BoolPropertyPtr getPreserveTopologyOption(QDomElement root)
std::vector< PropertyPtr > mOptionsAdapters
Definition: cxFilterImpl.h:96
vtkSmartPointer< class vtkPolyData > vtkPolyDataPtr
VisServicesPtr mServices
Definition: cxFilterImpl.h:103
boost::shared_ptr< class SelectDataStringPropertyBase > SelectDataStringPropertyBasePtr
virtual void createInputTypes()
virtual QString getHelp() const
virtual bool execute()
void setVtkPolyData(const vtkPolyDataPtr &polyData)
Definition: cxMesh.cpp:100
virtual QString getType() const
virtual void createOutputTypes()
BoolPropertyPtr getSmoothingOption(QDomElement root)
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()