GOFIGURE2  0.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
QGoFilterSemiAutoBase.cxx
Go to the documentation of this file.
1 /*=========================================================================
2  Authors: The GoFigure Dev. Team.
3  at Megason Lab, Systems biology, Harvard Medical school, 2009-11
4 
5  Copyright (c) 2009-11, President and Fellows of Harvard College.
6  All rights reserved.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions are met:
10 
11  Redistributions of source code must retain the above copyright notice,
12  this list of conditions and the following disclaimer.
13  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  Neither the name of the President and Fellows of Harvard College
17  nor the names of its contributors may be used to endorse or promote
18  products derived from this software without specific prior written
19  permission.
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27  OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 
33 =========================================================================*/
34 #include "QGoFilterSemiAutoBase.h"
35 
36 #include "QGoGUILibConfigure.h"
37 
38 #include "vtkSmartPointer.h"
39 #include "vtkImageData.h"
40 
41 //#include "QGoSeedBaseWidget.h"
42 
43 //Extract one slice
44 #include "vtkMatrix4x4.h"
45 #include "vtkImageReslice.h"
46 
47 // construct contour
48 #include "vtkContourFilter.h"
49 #include "vtkMarchingSquares.h"
50 #include "vtkCellArray.h"
51 #include "vtkPolylineDecimation.h"
52 #include "vtkStripper.h"
53 #include "vtkFeatureEdges.h"
54 
55 // construct mesh
56 #include "vtkMarchingCubes.h"
57 // keep the largest region
58 #include "vtkPolyDataConnectivityFilter.h"
59 // fill the holes!
60 #include "vtkFillHolesFilter.h"
61 // and smooth it...!
62 #include "vtkWindowedSincPolyDataFilter.h"
63 #include "vtkPolyDataWriter.h"
64 
65 // to cut
66 #include "vtkPlane.h"
67 #include "vtkCutter.h"
68 
69 #include "vtkImageExport.h"
70 
71 //--------------------------------------------------------------------------
73  QObject(iParent),
74  m_Widget(NULL),
75  m_Radius(3.),
76  m_Number(0),
77  m_Channel(0),
78  m_Points(NULL),
79  m_OriginalImageMC(NULL),
80  m_Sampling(3)
81 {
82  m_Output = vtkImageData::New();
83  m_vtk2itkImage = vtkImageExport::New();
84 
85  m_Center[0] = 0;
86  m_Center[1] = 0;
87  m_Center[2] = 0;
88 }
89 
90 //--------------------------------------------------------------------------
91 
92 //--------------------------------------------------------------------------
95 {
96  m_Output->Delete();
97  m_vtk2itkImage->Delete();
98 }
99 
100 //--------------------------------------------------------------------------
101 
102 //--------------------------------------------------------------------------
103 void
105 {
106  m_Name = iName;
107 }
108 
109 //--------------------------------------------------------------------------
110 
111 //--------------------------------------------------------------------------
112 QString
114 {
115  return m_Name;
116 }
117 
118 //--------------------------------------------------------------------------
119 
120 //--------------------------------------------------------------------------
121 void
123 {
124  //m_Widget = iWidget;
125 }
126 
127 //--------------------------------------------------------------------------
128 
129 //--------------------------------------------------------------------------
130 QWidget *
132 {
133  return m_Widget;
134 }
135 
136 //--------------------------------------------------------------------------
137 
138 //--------------------------------------------------------------------------
139 // Original data without ROI
140 vtkSmartPointer< vtkImageData >
142 {
143  return ( *m_OriginalImageMC )[m_Channel];
144 }
145 
146 //--------------------------------------------------------------------------
147 
148 //--------------------------------------------------------------------------
149 // Original data without ROI
150 void
151 QGoFilterSemiAutoBase::setOutput(vtkImageData *iOutputImage)
152 {
153  m_Output->DeepCopy(iOutputImage);
154 }
155 
156 //--------------------------------------------------------------------------
157 
158 //--------------------------------------------------------------------------
159 vtkImageData *
161 {
162  return m_Output;
163 }
164 
165 //--------------------------------------------------------------------------
166 // Center of the ROI to apply the segmentation algorithm
167 //--------------------------------------------------------------------------
168 void
170 {
171  m_Center[0] = iCenter[0];
172  m_Center[1] = iCenter[1];
173  m_Center[2] = iCenter[2];
174 }
175 
176 //--------------------------------------------------------------------------
177 // Center of the ROI to apply the segmentation algorithm
178 //--------------------------------------------------------------------------
179 double *
181 {
182  return m_Center;
183 }
184 
185 //--------------------------------------------------------------------------
186 // Radius to define ROI
187 //--------------------------------------------------------------------------
188 void
190 {
191  m_Radius = iRadius;
192 }
193 
194 //--------------------------------------------------------------------------
195 // Radius to define ROI
196 //--------------------------------------------------------------------------
197 double
199 {
200  return m_Radius;
201 }
202 
203 //--------------------------------------------------------------------------
204 // Radius to define ROI
205 //--------------------------------------------------------------------------
206 void
208 {
209  m_Sampling = iSampling;
210 }
211 
212 //--------------------------------------------------------------------------
213 
214 //--------------------------------------------------------------------------
215 int
217 {
218  return m_Sampling;
219 }
220 
221 //--------------------------------------------------------------------------
222 // Radius to define ROI
223 //--------------------------------------------------------------------------
224 void
226 {
227  m_Channel = iChannel;
228 }
229 
230 //--------------------------------------------------------------------------
231 
232 //--------------------------------------------------------------------------
233 int
235 {
236  return m_Channel;
237 }
238 
239 //--------------------------------------------------------------------------
240 
241 //--------------------------------------------------------------------------
242 vtkPoints *
244 {
245  return m_Points;
246 }
247 
248 //--------------------------------------------------------------------------
249 
250 //--------------------------------------------------------------------------
251 void
253 {
254  m_Points = iPoints;
255 }
256 
257 //--------------------------------------------------------------------------
258 
259 //--------------------------------------------------------------------------
260 void
261 QGoFilterSemiAutoBase::setOriginalImageMC(std::vector< vtkSmartPointer< vtkImageData > > *iOriginalImage)
262 {
263  m_OriginalImageMC = iOriginalImage;
264 }
265 
266 //--------------------------------------------------------------------------
267 
268 //--------------------------------------------------------------------------
269 void
271 {
272  /*QWidget *w = m_Widget->parentWidget()->parentWidget();
273 
274  if ( m_Number == iCurrentFilter )
275  {
276  m_Widget->show();
277  QObject::connect( w, SIGNAL( Apply() ),
278  this, SLOT( Apply() ) );
279  }
280  else
281  {
282  m_Widget->hide();
283  QObject::disconnect( w, SIGNAL( Apply() ),
284  this, SLOT( Apply() ) );
285  }*/
286 }
287 
288 //--------------------------------------------------------------------------
289 
290 //--------------------------------------------------------------------------
291 void
293 {
294  //QWidget * w = m_Widget->parentWidget()->parentWidget();
295  //QGoSeedBaseWidget *baseWidget = dynamic_cast< QGoSeedBaseWidget * >( w );
296 
297  //if ( checked && ( m_Number != baseWidget->GetCurrentFilter() ) )
298  // {
299  // m_Widget->hide();
300  // }
301 }
302 
303 //--------------------------------------------------------------------------
304 
305 //--------------------------------------------------------------------------
306 void
308 {
309  /*m_Number = iFilterNumber;
310 
311  QWidget *w = m_Widget->parentWidget()->parentWidget();
312 
313  // Buttons connections
314  QObject::connect( w, SIGNAL( Apply() ),
315  this, SLOT( Apply() ) );
316  QObject::connect( w, SIGNAL( Filter(int) ),
317  this, SLOT( UpdateVisibility(int) ) );
318  QObject::connect( w, SIGNAL( Radius(double) ),
319  this, SLOT( setRadius(double) ) );
320  QObject::connect( w, SIGNAL( Channel(int) ),
321  this, SLOT( setChannel(int) ) );
322  QObject::connect( w, SIGNAL( Sampling(int) ),
323  this, SLOT( setSampling(int) ) );
324  QObject::connect( w, SIGNAL( Clicked(bool) ),
325  this, SLOT( UpdateAdvancedMode(bool) ) );
326 
327  // End of segmentation signals
328  QObject::connect( this, SIGNAL( MeshCreated(vtkPolyData *, int) ),
329  w, SIGNAL( MeshCreated(vtkPolyData *, int) ) );
330  QObject::connect( this, SIGNAL( ContourCreated(vtkPolyData *) ),
331  w, SIGNAL( ContourCreated(vtkPolyData *) ) );
332  QObject::connect( this, SIGNAL( ImageProcessed() ),
333  w, SIGNAL( ImageProcessed() ) );
334 
335  QObject::connect( this, SIGNAL( CreateCorrespondingMesh(int) ),
336  w, SIGNAL( CreateCorrespondingMesh(int) ) );
337  QObject::connect( this, SIGNAL( AddContourForMeshToContours(vtkPolyData *) ),
338  w, SIGNAL( AddContourForMeshToContours(vtkPolyData *) ) );
339 
340  QObject::connect( this, SIGNAL( UpdateSeeds() ),
341  w, SIGNAL( UpdateSeeds() ) );
342  QObject::connect( this, SIGNAL( SegmentationFinished() ),
343  w, SIGNAL( SegmentationFinished() ) );*/
344 }
345 
346 //--------------------------------------------------------------------------
347 
348 //--------------------------------------------------------------------------
349 vtkImageData *
350 QGoFilterSemiAutoBase::extractOneSlice(vtkImageData *iOriginalImage, double *iOrigin, int iDirection)
351 {
352  static double elements[3][16] = { {
353  1, 0, 0, 0,
354  0, 1, 0, 0,
355  0, 0, 1, 0,
356  0, 0, 0, 1
357  },
358  {
359  1, 0, 0, 0,
360  0, 0, 1, 0,
361  0, -1, 0, 0,
362  0, 0, 0, 1
363  },
364  {
365  0, 0, -1, 0,
366  1, 0, 0, 0,
367  0, -1, 0, 0,
368  0, 0, 0, 1
369  } };
370 
371  // Set the slice orientation
372  vtkMatrix4x4 *resliceAxes = vtkMatrix4x4::New();
373 
374  resliceAxes->DeepCopy(elements[iDirection]);
375  // Set the point through which to slice
376  resliceAxes->SetElement(0, 3, iOrigin[0]);
377  resliceAxes->SetElement(1, 3, iOrigin[1]);
378  resliceAxes->SetElement(2, 3, iOrigin[2]);
379 
380  vtkImageReslice *reslicer = vtkImageReslice::New();
381  reslicer->SetOutputDimensionality(2);
382  reslicer->SetInformationInput(iOriginalImage);
383  reslicer->SetInterpolationModeToLinear();
384  reslicer->SetInput(iOriginalImage);
385  reslicer->SetResliceAxes(resliceAxes);
386  reslicer->Update();
387 
388  vtkImageData *output = vtkImageData::New();
389  output->DeepCopy( reslicer->GetOutput() );
390 
391  reslicer->Delete();
392  resliceAxes->Delete();
393 
394  return output;
395 }
396 
397 //--------------------------------------------------------------------------
398 
399 //--------------------------------------------------------------------------
400 vtkPolyData *
401 QGoFilterSemiAutoBase::ReconstructContour(vtkImageData *iInputImage, const double & iThreshold)
402 {
403  // create iso-contours
404  vtkMarchingSquares *contours = vtkMarchingSquares::New();
405 
406  contours->SetInput(iInputImage);
407  contours->GenerateValues (1, iThreshold, iThreshold);
408  contours->Update();
409 
410  vtkPolyData *outputToOrganize = vtkPolyData::New();
411  outputToOrganize->DeepCopy( contours->GetOutput() );
412 
413  vtkPolyData *output = ReorganizeContour(outputToOrganize);
414 
415  contours->Delete();
416  outputToOrganize->Delete();
417 
418  return output;
419 }
420 
421 //--------------------------------------------------------------------------
422 
423 //--------------------------------------------------------------------------
424 vtkPolyData *
425 QGoFilterSemiAutoBase::ReorganizeContour(vtkPolyData *iInputImage, bool iDecimate)
426 {
427  // Create reorganize contours
428  vtkStripper *stripper = vtkStripper::New();
429 
430  stripper->SetInput(iInputImage);
431  //Is it useful?? Which number is the best suited?
432  stripper->SetMaximumLength(999);
433  stripper->Update();
434 
435  // Reorder points
436  stripper->GetOutput()->GetLines()->InitTraversal();
437 
438  // npts = nb of points in the line
439  // *pts = pointer to each point
440 
441  vtkIdType *pts = NULL;
442  vtkIdType npts = 0;
443  stripper->GetOutput()->GetLines()->GetNextCell(npts, pts);
444  vtkPoints *points = vtkPoints::New();
445 
446  vtkCellArray *lines = vtkCellArray::New();
447  vtkIdType * lineIndices = new vtkIdType[static_cast< int >( npts + 1 )];
448 
449  for ( int k = 0; k < static_cast< int >( npts ); k++ )
450  {
451  points->InsertPoint( k, stripper->GetOutput()->GetPoints()->GetPoint(pts[k]) );
452  lineIndices[k] = k;
453  }
454 
455  lineIndices[static_cast< int >( npts )] = 0;
456  lines->InsertNextCell(npts + 1, lineIndices);
457  delete[] lineIndices;
458 
459  vtkPolyData *testPolyD = vtkPolyData::New();
460  testPolyD->SetPoints(points);
461  testPolyD->SetLines(lines);
462 
463  if ( iDecimate )
464  {
465  //Decimation (has to be after points reorganization)
467  decimator->SetInput(testPolyD);
468 
469  double ratio = 1. - 20. / static_cast< double >( npts );
470 
471  decimator->SetTargetReduction(ratio);
472  decimator->Update();
473 
474  vtkPolyData *output = vtkPolyData::New();
475  output->DeepCopy( decimator->GetOutput() );
476 
477  lines->Delete();
478  points->Delete();
479  stripper->Delete();
480  decimator->Delete();
481  testPolyD->Delete();
482 
483  return output;
484  }
485  else
486  {
487  lines->Delete();
488  points->Delete();
489  stripper->Delete();
490 
491  return testPolyD;
492  }
493 }
494 
495 //--------------------------------------------------------------------------
496 
497 //--------------------------------------------------------------------------
498 vtkPolyData *
499 QGoFilterSemiAutoBase::ReconstructMesh(vtkImageData *iInputImage, const double & iThreshold)
500 {
501  // create iso-contours
502  // Problem[Kishore]: Creates holes in some meshes although image has no hole
503 // vtkMarchingCubes *contours = vtkMarchingCubes::New();
504 //
505 // contours->SetInput(iInputImage);
506 // contours->GenerateValues (1, iThreshold, iThreshold);
507 // contours->SetComputeGradients(0);
508 // contours->SetComputeNormals(1);
509 // contours->SetComputeScalars(0);
510 // contours->SetNumberOfContours(1);
511 // contours->Update();
512 
513  vtkSmartPointer< vtkContourFilter > contours = vtkSmartPointer< vtkContourFilter >::New();
514  contours->SetInput(iInputImage);
515  contours->SetComputeGradients(0);
516  contours->SetComputeNormals(0);
517  contours->SetComputeScalars(0);
518  contours->SetNumberOfContours(1);
519  contours->SetValue(0, iThreshold);
520  contours->Update();
521 
522  vtkSmartPointer< vtkFeatureEdges > feature =
523  vtkSmartPointer< vtkFeatureEdges >::New();
524  feature->SetInputConnection( contours->GetOutputPort() );
525  feature->BoundaryEdgesOn();
526  feature->FeatureEdgesOff();
527  feature->NonManifoldEdgesOn();
528  feature->ManifoldEdgesOff();
529  feature->Update();
530 
531  vtkSmartPointer< vtkFillHolesFilter > fillFilter =
532  vtkSmartPointer< vtkFillHolesFilter >::New();
533 
534  vtkSmartPointer< vtkPolyDataConnectivityFilter > connectivityFilter =
535  vtkSmartPointer< vtkPolyDataConnectivityFilter >::New();
536  connectivityFilter->SetExtractionModeToLargestRegion();
537 
538 
539  if ( feature->GetOutput()->GetNumberOfCells() > 0 )
540  {
541  // fill holes if any!
542  fillFilter->SetInputConnection( contours->GetOutputPort() );
543  fillFilter->Update();
544 
545  connectivityFilter->SetInputConnection( fillFilter->GetOutputPort() );
546  }
547  else
548  {
549  connectivityFilter->SetInputConnection( contours->GetOutputPort() );
550  }
551 
552  // keep the largest region
553  connectivityFilter->Update();
554 
555  unsigned int smoothingIterations = 15;
556  double passBand = 0.001;
557  double featureAngle = 120.0;
558 
559  // smoothing
560  vtkSmartPointer< vtkWindowedSincPolyDataFilter > smoother =
561  vtkSmartPointer< vtkWindowedSincPolyDataFilter >::New();
562  smoother->SetInputConnection( connectivityFilter->GetOutputPort() );
563  smoother->SetNumberOfIterations( smoothingIterations );
564  smoother->BoundarySmoothingOff();
565  smoother->FeatureEdgeSmoothingOff();
566  smoother->SetFeatureAngle(featureAngle);
567  smoother->SetPassBand(passBand);
568  smoother->NonManifoldSmoothingOn();
569  smoother->NormalizeCoordinatesOn();
570  smoother->Update();
571 
572  vtkPolyData *output = vtkPolyData::New();
573  output->DeepCopy( connectivityFilter->GetOutput() );
574 
575  return output;
576 }
577 
578 //--------------------------------------------------------------------------
void setOriginalImageMC(std::vector< vtkSmartPointer< vtkImageData > > *iOriginalImage)
double * getCenter()
Get the center of the area to be segmented.
void setName(QString iName)
Set Name of the filter in the combo box.
QGoFilterSemiAutoBase(QObject *iParent=NULL)
Constructor.
vtkSmartPointer< vtkImageData > getInput()
void setOutput(vtkImageData *iOutput)
int getChannel()
Get the channel to be segmented.
vtkPolyData * ReorganizeContour(vtkPolyData *iInputImage=NULL, bool iDecimate=true)
void UpdateVisibility(int iFilter)
virtual void ConnectSignals(int iFilterNumber)
void setChannel(int iChannel=0)
void setWidget(QWidget *iWidget)
Set the widget associated to the filter.
vtkPolyData * ReconstructMesh(vtkImageData *iInputImage, const double &iThreshold)
void setSampling(int iSampling)
static vtkPolylineDecimation * New()
Instantiate this object with a target reduction of 0.90.
QWidget * getWidget()
Get the widget associated to the filter.
void setCenter(double *iCenter)
Decimate a polyline.
vtkPolyData * ReconstructContour(vtkImageData *iInputImage, const double &iThreshold)
QString getName()
Get Name of the filter in the combo box.
std::vector< vtkSmartPointer< vtkImageData > > * m_OriginalImageMC
virtual ~QGoFilterSemiAutoBase()
Destructor.
vtkImageExport * m_vtk2itkImage
vtkImageData * extractOneSlice(vtkImageData *iOriginalImage, double *iOrigin, int iDirection)
double getRadius()
Get the radius of the area to be segmented.
void setPoints(vtkPoints *iPoints)
void setRadius(double iRadius)