NorMIT-nav  2023.01.05-dev+develop.0da12
An IGT application
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) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
11 
12 #include "cxContourFilter.h"
13 
14 #include <vtkImageShrink3D.h>
15 #include <vtkMarchingCubes.h>
16 #include <vtkWindowedSincPolyDataFilter.h>
17 #include <vtkTriangleFilter.h>
18 #include <vtkDecimatePro.h>
19 #include <vtkPolyDataNormals.h>
20 #include <vtkImageData.h>
21 
22 
24 #include "cxTypeConversions.h"
25 #include "cxImage.h"
26 #include "cxMesh.h"
27 #include "cxDoubleProperty.h"
28 #include "cxBoolProperty.h"
29 #include "cxColorProperty.h"
31 #include "cxPatientModelService.h"
32 #include "cxViewService.h"
33 #include "cxVisServices.h"
34 
35 namespace cx
36 {
37 
39  FilterImpl(services)
40 {
41 }
42 
43 QString ContourFilter::getName() const
44 {
45  return "Contour";
46 }
47 
48 QString ContourFilter::getType() const
49 {
50  return "contour_filter";
51 }
52 
53 QString ContourFilter::getHelp() const
54 {
55  return "<html>"
56  "<h3>Surfacing.</h3>"
57  "<p><i>Find the surface of a binary volume using marching cubes.</i></p>"
58  "<p>- Optional factor 2 reduction</p>"
59  "<p>- Marching Cubes contouring</p>"
60  "<p>- Optional Windowed Sinc smoothing</p>"
61  "<p>- Decimation of triangles</p>"
62  "</html>";
63 }
64 
66 {
67  return "_ge";
68 }
69 
71 {
72  return BoolProperty::initialize("Reduce input", "",
73  "Reduce input volumes resolution by a factor of 2 in all directions.",
74  false, root);
75 }
76 
78 {
79  return BoolProperty::initialize("Smoothing", "",
80  "Smooth the output contour", true, root);
81 }
82 
84 {
85  return BoolProperty::initialize("Preserve mesh topology", "",
86  "Preserve mesh topology during reduction", true, root);
87 }
88 
90 {
91  DoublePropertyPtr retval = DoubleProperty::initialize("Threshold", "",
92  "Values from this threshold and above will be included",
93  100.0, DoubleRange(-1000, 1000, 1), 0, root);
94  retval->setGuiRepresentation(DoublePropertyBase::grSLIDER);
95  return retval;
96 }
97 
99 {
100  DoublePropertyPtr retval = DoubleProperty::initialize("Decimation %", "",
101  "Reduce number of triangles in output surface",
102  0.2, DoubleRange(0, 1, 0.01), 0, root);
103  retval->setInternal2Display(100);
104  return retval;
105 }
106 
108 {
109  return ColorProperty::initialize( "Color", "",
110  "Color of output model.",
111  QColor("green"), root);
112 }
113 
115 {
116  return DoubleProperty::initialize("Number of iterations (smoothing)", "",
117  "Number of iterations in smoothing filter. Higher number = more smoothing",
118  15, DoubleRange(1, 50, 1), 0, root);
119 }
120 
122 {
123  return DoubleProperty::initialize("Band pass smoothing", "",
124  "Band pass width in smoothing filter. Smaller number = more smoothing",
125  0.30, DoubleRange(0.05, 0.95, 0.05), 2, root);
126 }
127 
129 {
130  mReduceResolutionOption = this->getReduceResolutionOption(mOptions);
131  mOptionsAdapters.push_back(mReduceResolutionOption);
132 
133  mSurfaceThresholdOption = this->getSurfaceThresholdOption(mOptions);
134  connect(mSurfaceThresholdOption.get(), SIGNAL(changed()), this, SLOT(thresholdSlot()));
135  mOptionsAdapters.push_back(mSurfaceThresholdOption);
136 
137  mOptionsAdapters.push_back(this->getSmoothingOption(mOptions));
139  mOptionsAdapters.push_back(this->getPassBandOption(mOptions));
142 
143  mOptionsAdapters.push_back(this->getColorOption(mOptions));
144 }
145 
147 {
149 
150  temp = StringPropertySelectImage::New(mServices->patient());
151  temp->setValueName("Input");
152  temp->setHelp("Select image input for contouring");
153  connect(temp.get(), SIGNAL(dataChanged(QString)), this, SLOT(imageChangedSlot(QString)));
154  mInputTypes.push_back(temp);
155 }
156 
158 {
160 
161  temp = StringPropertySelectMesh::New(mServices->patient());
162  temp->setValueName("Output");
163  temp->setHelp("Output contour");
164  mOutputTypes.push_back(temp);
165 }
166 
168 {
170 
171  if (!mActive)
172  this->stopPreview();
173 }
174 
175 void ContourFilter::stopPreview()
176 {
177  if(mPreviewImage)
178  mPreviewImage->stopThresholdPreview();
179  mPreviewImage.reset();
180 }
181 
182 void ContourFilter::imageChangedSlot(QString uid)
183 {
184  ImagePtr image = mServices->patient()->getData<Image>(uid);
185  if(!image)
186  return;
187 
188  this->updateThresholdFromImageChange(uid, mSurfaceThresholdOption);
189  this->stopPreview();
190 
191  int extent[6];
192  image->getBaseVtkImageData()->GetExtent(extent);
193  mReduceResolutionOption->setHelp( "Current input resolution: " + qstring_cast(extent[1])
194  + " " + qstring_cast(extent[3]) + " " + qstring_cast(extent[5])
195  + " (If checked: " + qstring_cast(extent[1]/2)+ " " + qstring_cast(extent[3]/2) + " "
196  + qstring_cast(extent[5]/2) + ")");
197 }
198 
199 void ContourFilter::thresholdSlot()
200 {
201  if (mActive)
202  {
203  mPreviewImage = boost::dynamic_pointer_cast<Image>(mInputTypes[0]->getData());
204  if(mPreviewImage)
205  {
206  Eigen::Vector2d threshold = Eigen::Vector2d(mSurfaceThresholdOption->getValue(), mPreviewImage->getMax());
207  mPreviewImage->startThresholdPreview(threshold);
208  }
209  }
210 }
211 
213 {
214  this->stopPreview();
215  return FilterImpl::preProcess();
216 }
217 
219 {
220  ImagePtr input = this->getCopiedInputImage();
221  if (!input)
222  return false;
223 
224  //std::cout << "ContourFilter::execute : " << mCopiedOptions.ownerDocument().toString() << std::endl;
225 
226  BoolPropertyPtr reduceResolutionOption = this->getReduceResolutionOption(mCopiedOptions);
227  BoolPropertyPtr smoothingOption = this->getSmoothingOption(mCopiedOptions);
228  DoublePropertyPtr numberOfIterationsOption = this->getNumberOfIterationsOption(mCopiedOptions);
229  DoublePropertyPtr passBandOption = this->getPassBandOption(mCopiedOptions);
230  BoolPropertyPtr preserveTopologyOption = this->getPreserveTopologyOption(mCopiedOptions);
231  DoublePropertyPtr surfaceThresholdOption = this->getSurfaceThresholdOption(mCopiedOptions);
232  DoublePropertyPtr decimationOption = this->getDecimationOption(mCopiedOptions);
233 
234  //report(QString("Creating contour from \"%1\"...").arg(input->getName()));
235 
236  mRawResult = this->execute( input->getBaseVtkImageData(),
237  surfaceThresholdOption->getValue(),
238  reduceResolutionOption->getValue(),
239  smoothingOption->getValue(),
240  preserveTopologyOption->getValue(),
241  decimationOption->getValue(),
242  numberOfIterationsOption->getValue(),
243  passBandOption->getValue());
244  return true;
245 }
246 
248  double threshold,
249  bool reduceResolution,
250  bool smoothing,
251  bool preserveTopology,
252  double decimation,
253  double numberOfIterations,
254  double passBand)
255 {
256  if (!input)
257  return vtkPolyDataPtr();
258 
259  //Shrink input volume
260  vtkImageShrink3DPtr shrinker = vtkImageShrink3DPtr::New();
261  if(reduceResolution)
262  {
263 // std::cout << "smooth" << std::endl;
264  shrinker->SetInputData(input);
265  shrinker->SetShrinkFactors(2,2,2);
266  shrinker->Update();
267  }
268 
269  // Find countour
270  vtkMarchingCubesPtr convert = vtkMarchingCubesPtr::New();
271  if(reduceResolution)
272  convert->SetInputConnection(shrinker->GetOutputPort());
273  else
274  convert->SetInputData(input);
275 
276  convert->SetValue(0, threshold);
277  convert->Update();
278 
279  vtkPolyDataPtr cubesPolyData = convert->GetOutput();
280 // vtkPolyDataPtr cubesPolyData = vtkPolyDataPtr::New();
281 // cubesPolyData = convert->GetOutput();
282 // std::cout << "convert->GetOutput(); " << cubesPolyData.GetPointer() << std::endl;
283 
284  // Smooth surface model
285  vtkWindowedSincPolyDataFilterPtr smoother = vtkWindowedSincPolyDataFilterPtr::New();
286  if(smoothing)
287  {
288  smoother->SetInputData(cubesPolyData);
289  smoother->SetNumberOfIterations(numberOfIterations);// Higher number = more smoothing - default 15
290  smoother->SetBoundarySmoothing(false);
291  smoother->SetFeatureEdgeSmoothing(false);
292  smoother->SetNormalizeCoordinates(true);
293  smoother->SetFeatureAngle(120);
294  smoother->SetPassBand(passBand);//Lower number = more smoothing - default 0.3
295  smoother->Update();
296  cubesPolyData = smoother->GetOutput();
297  }
298 
299  //Create a surface of triangles
300 
301  //Decimate surface model (remove a percentage of the polygons)
302  vtkTriangleFilterPtr trifilt = vtkTriangleFilterPtr::New();
303  vtkDecimateProPtr deci = vtkDecimateProPtr::New();
304  vtkPolyDataNormalsPtr normals = vtkPolyDataNormalsPtr::New();
305  if (decimation > 0.000001)
306  {
307  trifilt->SetInputData(cubesPolyData);
308  trifilt->Update();
309  deci->SetInputConnection(trifilt->GetOutputPort());
310  deci->SetTargetReduction(decimation);
311  deci->SetPreserveTopology(preserveTopology);
312  //deci->PreserveTopologyOn();
313  deci->Update();
314  cubesPolyData = deci->GetOutput();
315  }
316 
317 
318  normals->SetInputData(cubesPolyData);
319  normals->SetComputeCellNormals(true);
320  normals->AutoOrientNormalsOn();
321  normals->Update();
322  cubesPolyData->DeepCopy(normals->GetOutput());
323 
324  return cubesPolyData;
325 }
326 
328 {
329  if (!mRawResult)
330  return false;
331 
332  ImagePtr input = this->getCopiedInputImage();
333 
334  if (!input)
335  return false;
336 
337  ColorPropertyPtr colorOption = this->getColorOption(mOptions);
338  MeshPtr output = this->postProcess(mServices->patient(), mRawResult, input, colorOption->getValue());
339  mRawResult = NULL;
340 
341  if (output)
342  mOutputTypes.front()->setValue(output->getUid());
343 
344  return true;
345 }
346 
348 {
349  if (!contour || !base)
350  return MeshPtr();
351 
352  QString uid = base->getUid() + ContourFilter::getNameSuffix() + "%1";
353  QString name = base->getName()+ ContourFilter::getNameSuffix() + "%1";
354  MeshPtr output = patient->createSpecificData<Mesh>(uid, name);
355  output->setVtkPolyData(contour);
356  if (!output)
357  return MeshPtr();
358 
359  output->get_rMd_History()->setRegistration(base->get_rMd());
360  output->get_rMd_History()->setParentSpace(base->getUid());
361 
362  output->setColor(color);
363 
364  patient->insertData(output);
365 
366  return output;
367 }
368 
369 } // namespace cx
cx::FilterImpl
Definition: cxFilterImpl.h:36
cx::BoolProperty::initialize
static BoolPropertyPtr initialize(const QString &uid, QString name, QString help, bool value, QDomNode root=QDomNode())
Definition: cxBoolProperty.cpp:30
vtkPolyDataNormalsPtr
vtkSmartPointer< class vtkPolyDataNormals > vtkPolyDataNormalsPtr
Definition: vtkForwardDeclarations.h:113
cx::ColorPropertyPtr
boost::shared_ptr< class ColorProperty > ColorPropertyPtr
Definition: cxForwardDeclarations.h:144
cx::ContourFilter::createOutputTypes
virtual void createOutputTypes()
Definition: cxContourFilter.cpp:157
cxContourFilter.h
cx::StringPropertySelectMesh::New
static StringPropertySelectMeshPtr New(PatientModelServicePtr patientModelService)
Definition: cxSelectDataStringProperty.h:131
qstring_cast
QString qstring_cast(const T &val)
Definition: cxTypeConversions.h:46
cx::FilterImpl::setActive
virtual void setActive(bool on)
Definition: cxFilterImpl.cpp:79
cx::ContourFilter::getDecimationOption
DoublePropertyPtr getDecimationOption(QDomElement root)
Definition: cxContourFilter.cpp:98
cx::Mesh::setVtkPolyData
void setVtkPolyData(const vtkPolyDataPtr &polyData)
Definition: cxMesh.cpp:92
cx::ContourFilter::preProcess
bool preProcess()
Definition: cxContourFilter.cpp:212
cx
Namespace for all CustusX production code.
Definition: cx_dev_group_definitions.h:13
cxImage.h
cx::ContourFilter::getSurfaceThresholdOption
DoublePropertyPtr getSurfaceThresholdOption(QDomElement root)
Definition: cxContourFilter.cpp:89
cx::BoolPropertyPtr
boost::shared_ptr< class BoolProperty > BoolPropertyPtr
Definition: cxPlusConnectWidget.h:29
cx::ContourFilter::getNameSuffix
static QString getNameSuffix()
Definition: cxContourFilter.cpp:65
cx::ContourFilter::createOptions
virtual void createOptions()
Definition: cxContourFilter.cpp:128
cx::ContourFilter::getReduceResolutionOption
BoolPropertyPtr getReduceResolutionOption(QDomElement root)
Definition: cxContourFilter.cpp:70
vtkDecimateProPtr
vtkSmartPointer< class vtkDecimatePro > vtkDecimateProPtr
Definition: vtkForwardDeclarations.h:54
cx::ContourFilter::getSmoothingOption
BoolPropertyPtr getSmoothingOption(QDomElement root)
Definition: cxContourFilter.cpp:77
cx::ContourFilter::setActive
virtual void setActive(bool on)
Definition: cxContourFilter.cpp:167
cx::VisServicesPtr
boost::shared_ptr< class VisServices > VisServicesPtr
Definition: cxMainWindow.h:40
cx::ContourFilter::execute
virtual bool execute()
Definition: cxContourFilter.cpp:218
cx::Filter::changed
void changed()
vtkImageDataPtr
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
Definition: cxVideoConnectionWidget.h:30
cxDoubleProperty.h
cx::DoublePropertyBase::grSLIDER
@ grSLIDER
Definition: cxDoublePropertyBase.h:81
cx::FilterImpl::mOutputTypes
std::vector< SelectDataStringPropertyBasePtr > mOutputTypes
Definition: cxFilterImpl.h:74
vtkImageShrink3DPtr
vtkSmartPointer< class vtkImageShrink3D > vtkImageShrink3DPtr
Definition: vtkForwardDeclarations.h:80
cx::ColorProperty::initialize
static ColorPropertyPtr initialize(const QString &uid, QString name, QString help, QColor value, QDomNode root=QDomNode())
Definition: cxColorProperty.cpp:24
cx::ContourFilter::createInputTypes
virtual void createInputTypes()
Definition: cxContourFilter.cpp:146
cx::FilterImpl::mInputTypes
std::vector< SelectDataStringPropertyBasePtr > mInputTypes
Definition: cxFilterImpl.h:73
cx::FilterImpl::mOptions
QDomElement mOptions
Definition: cxFilterImpl.h:76
cx::FilterImpl::mCopiedOptions
QDomElement mCopiedOptions
Definition: cxFilterImpl.h:80
cx::FilterImpl::getCopiedInputImage
ImagePtr getCopiedInputImage(int index=0)
Definition: cxFilterImpl.cpp:104
cx::DoubleProperty::initialize
static DoublePropertyPtr initialize(const QString &uid, QString name, QString help, double value, DoubleRange range, int decimals, QDomNode root=QDomNode())
Definition: cxDoubleProperty.cpp:30
cx::DoublePropertyPtr
boost::shared_ptr< class DoubleProperty > DoublePropertyPtr
Definition: cxReconstructionMethodService.h:33
vtkMarchingCubesPtr
vtkSmartPointer< class vtkMarchingCubes > vtkMarchingCubesPtr
Definition: vtkForwardDeclarations.h:90
cx::MeshPtr
boost::shared_ptr< class Mesh > MeshPtr
Definition: cxForwardDeclarations.h:48
cx::ContourFilter::getPreserveTopologyOption
BoolPropertyPtr getPreserveTopologyOption(QDomElement root)
Definition: cxContourFilter.cpp:83
cx::StringPropertySelectImage::New
static StringPropertySelectImagePtr New(PatientModelServicePtr patientModelService)
Definition: cxSelectDataStringProperty.h:76
cxViewService.h
cx::PatientModelServicePtr
boost::shared_ptr< class PatientModelService > PatientModelServicePtr
Definition: cxLogicManager.h:25
cxTypeConversions.h
cxPatientModelService.h
cx::ImagePtr
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
cx::ContourFilter::getType
virtual QString getType() const
Definition: cxContourFilter.cpp:48
cxRegistrationTransform.h
cx::vtkPolyDataPtr
vtkSmartPointer< vtkPolyData > vtkPolyDataPtr
Definition: cxCenterlineRegistration.h:42
cx::ContourFilter::getHelp
virtual QString getHelp() const
Definition: cxContourFilter.cpp:53
cx::ContourFilter::getName
virtual QString getName() const
Definition: cxContourFilter.cpp:43
cx::ContourFilter::getColorOption
ColorPropertyPtr getColorOption(QDomElement root)
Definition: cxContourFilter.cpp:107
cx::ContourFilter::getPassBandOption
DoublePropertyPtr getPassBandOption(QDomElement root)
Definition: cxContourFilter.cpp:121
cx::Mesh
A mesh data set.
Definition: cxMesh.h:45
cx::ContourFilter::postProcess
virtual bool postProcess()
Definition: cxContourFilter.cpp:327
vtkWindowedSincPolyDataFilterPtr
vtkSmartPointer< class vtkWindowedSincPolyDataFilter > vtkWindowedSincPolyDataFilterPtr
Definition: vtkForwardDeclarations.h:153
cxSelectDataStringProperty.h
cx::FilterImpl::preProcess
virtual bool preProcess()
Definition: cxFilterImpl.cpp:85
cx::FilterImpl::updateThresholdFromImageChange
void updateThresholdFromImageChange(QString uid, DoublePropertyPtr threshold)
Definition: cxFilterImpl.cpp:111
cx::DoubleRange
Utility class for describing a bounded numeric range.
Definition: cxDoubleRange.h:32
cxBoolProperty.h
cxMesh.h
cxColorProperty.h
vtkTriangleFilterPtr
vtkSmartPointer< class vtkTriangleFilter > vtkTriangleFilterPtr
Definition: vtkForwardDeclarations.h:145
cx::FilterImpl::mOptionsAdapters
std::vector< PropertyPtr > mOptionsAdapters
Definition: cxFilterImpl.h:75
cx::ContourFilter::ContourFilter
ContourFilter(VisServicesPtr services)
Definition: cxContourFilter.cpp:38
cx::ContourFilter::getNumberOfIterationsOption
DoublePropertyPtr getNumberOfIterationsOption(QDomElement root)
Definition: cxContourFilter.cpp:114
cx::SelectDataStringPropertyBasePtr
boost::shared_ptr< class SelectDataStringPropertyBase > SelectDataStringPropertyBasePtr
Definition: cxMeshGlyphsWidget.h:26
cx::FilterImpl::mActive
bool mActive
Definition: cxFilterImpl.h:81
cx::FilterImpl::mServices
VisServicesPtr mServices
Definition: cxFilterImpl.h:82
cxVisServices.h