#include <vtkImagePolyDataSeedConnectivity.h>
Public Member Functions | |
vtkTypeRevisionMacro (vtkImagePolyDataSeedConnectivity, vtkStructuredPointsToPolyDataFilter) | |
void | PrintSelf (ostream &os, vtkIndent indent) |
virtual void | SetAxis (vtkPolyData *) |
vtkGetObjectMacro (Axis, vtkPolyData) | |
vtkSetMacro (ThresholdRatio, double) | |
vtkGetMacro (ThresholdRatio, double) | |
vtkGetObjectMacro (OuterMold, vtkPolyData) | |
Static Public Member Functions | |
static vtkImagePolyDataSeedConnectivity * | New () |
Protected Member Functions | |
vtkImagePolyDataSeedConnectivity () | |
~vtkImagePolyDataSeedConnectivity () | |
void | Execute () |
void | ClipImageWithAxis () |
Protected Attributes | |
double | ThresholdRatio |
vtkPolyData * | Axis |
vtkImageData * | ClipImageData |
vtkPolyData * | OuterMold |
Private Member Functions | |
vtkImagePolyDataSeedConnectivity (const vtkImagePolyDataSeedConnectivity &) | |
void | operator= (const vtkImagePolyDataSeedConnectivity &) |
Definition at line 28 of file vtkImagePolyDataSeedConnectivity.h.
vtkImagePolyDataSeedConnectivity::vtkImagePolyDataSeedConnectivity | ( | ) | [protected] |
Definition at line 43 of file vtkImagePolyDataSeedConnectivity.cxx.
References Axis, ClipImageData, New(), OuterMold, and ThresholdRatio.
00044 { 00045 this->Axis = NULL; 00046 this->ClipImageData = vtkImageData::New(); 00047 this->OuterMold = vtkPolyData::New(); 00048 this->ThresholdRatio = 0.45; 00049 }
vtkImagePolyDataSeedConnectivity::~vtkImagePolyDataSeedConnectivity | ( | ) | [protected] |
Definition at line 51 of file vtkImagePolyDataSeedConnectivity.cxx.
References Axis, ClipImageData, and OuterMold.
00052 { 00053 if(this->Axis) 00054 { 00055 this->Axis->Delete(); 00056 } 00057 this->ClipImageData->Delete(); 00058 this->ClipImageData = NULL; 00059 this->OuterMold->Delete(); 00060 this->OuterMold = NULL; 00061 }
vtkImagePolyDataSeedConnectivity::vtkImagePolyDataSeedConnectivity | ( | const vtkImagePolyDataSeedConnectivity & | ) | [private] |
void vtkImagePolyDataSeedConnectivity::ClipImageWithAxis | ( | ) | [protected] |
Instead of working directly on leo we might remove the heart by a trick: If we could cut with a disk at place where the last(first) axis point is we could avoid the flood fill algo to spread in the heart...smart !
First we construct a virtual disk (=half sphere for now) See: Disk-Stencil.py
What we do here: Get first point (p2) and second point (p1) : assume it exists ! Then calculate vector p2->p1 normalize it use it to define intersection plane between sphere and plane
What we do here: Get last point (p2) and before last point (p1) : assume it exists ! Then calculate vector p2->p1 normalize it use it to define intersection plane between sphere and plane
Now use dgobbi class: Stencil stuff to remove the 'bad' heart part
Should I do my own vtkCappedCylinder ?? solution: no , cause ... I can't remember why... :p
Definition at line 285 of file vtkImagePolyDataSeedConnectivity.cxx.
References Axis, ClipImageData, and New().
Referenced by Execute().
00286 { 00287 //no input need we'll work with member data: 00288 //Now we only need the region growing part: 00299 double normal[3]; 00300 00308 this->Axis->Update(); 00309 vtkPoints *points = this->Axis->GetPoints(); 00310 int numPts = points->GetNumberOfPoints(); 00311 double p1[3]; 00312 double p2[3]; 00313 00314 points->GetPoint( 0, p2 ); 00315 points->GetPoint( 1, p1 ); 00316 00317 normal[0] = p1[0] - p2[0]; 00318 normal[1] = p1[1] - p2[1]; 00319 normal[2] = p1[2] - p2[2]; 00320 vtkMath::Normalize( normal ); 00321 00322 vtkPlane *plane1 = vtkPlane::New(); 00323 plane1->SetOrigin( p2[ 0 ], p2[ 1 ], p2[ 2 ] ); 00324 plane1->SetNormal( normal[0], normal[1], normal[2]); 00325 00326 vtkDataArray* scalars = this->Axis->GetPointData()->GetScalars(); 00327 double tuple[2]; 00328 scalars->GetTuple(0, tuple); 00329 double radius = tuple[0]; 00330 00331 vtkSphere *sphere1 = vtkSphere::New(); 00332 sphere1->SetCenter( p2[ 0 ], p2[ 1 ], p2[ 2 ] ); 00333 sphere1->SetRadius( radius + 1); 00334 00335 vtkImplicitBoolean *disk1 = vtkImplicitBoolean::New(); 00336 disk1->SetOperationTypeToIntersection(); 00337 disk1->AddFunction(sphere1); 00338 disk1->AddFunction(plane1); 00339 00348 //ax->getControlPoint(numPts - 1, p2, p2+3); 00349 points->GetPoint( numPts - 1, p2); 00350 //ax->getControlPoint(numPts - 2, p1, p1+3); //assume it exists 00351 points->GetPoint( numPts - 2, p1); 00352 normal[0] = p1[0] - p2[0]; 00353 normal[1] = p1[1] - p2[1]; 00354 normal[2] = p1[2] - p2[2]; 00355 vtkMath::Normalize( normal ); 00356 00357 vtkPlane *plane2 = vtkPlane::New(); 00358 plane2->SetOrigin( p2[ 0 ], p2[ 1 ], p2[ 2 ] ); 00359 plane2->SetNormal( normal[0], normal[1], normal[2]); 00360 00361 vtkSphere *sphere2 = vtkSphere::New(); 00362 sphere2->SetCenter( p2[ 0 ], p2[ 1 ], p2[ 2 ] ); 00363 sphere2->SetRadius( radius + 1 ); 00364 00365 vtkImplicitBoolean *disk2 = vtkImplicitBoolean::New(); 00366 disk2->SetOperationTypeToIntersection(); 00367 disk2->AddFunction(sphere2); 00368 disk2->AddFunction(plane2); 00369 00370 vtkImplicitBoolean *disk = vtkImplicitBoolean::New(); 00371 disk->SetOperationTypeToUnion(); 00372 disk->AddFunction(disk1); 00373 disk->AddFunction(disk2); 00374 00379 vtkImplicitFunctionToImageStencil *functionToStencil = vtkImplicitFunctionToImageStencil::New (); 00380 functionToStencil->SetInput ( disk ); 00381 00382 vtkImageStencil *stencil = vtkImageStencil::New(); 00383 stencil->SetInput( this->GetInput() ); 00384 stencil->SetStencil( functionToStencil->GetOutput() ); 00385 stencil->ReverseStencilOn(); 00386 stencil->SetBackgroundValue (0); 00387 //don't forget to call ->Update before using an iterator !!! 00388 stencil->Update(); 00389 00390 this->ClipImageData->ShallowCopy( stencil->GetOutput() ); 00391 00397 //Delete stuff: 00398 plane1 -> Delete(); 00399 sphere1 -> Delete(); 00400 disk1 -> Delete(); 00401 plane2 -> Delete(); 00402 sphere2 -> Delete(); 00403 disk2 -> Delete(); 00404 disk -> Delete(); 00405 functionToStencil -> Delete(); 00406 stencil -> Delete(); 00407 }
void vtkImagePolyDataSeedConnectivity::Execute | ( | ) | [protected] |
Instead of working on the real image, we might take advantage of class Stencil made by dgobbi
Steps:
Internal function that take an input of a b&w or grayscale image (should be unsigned short/ unsigned char and apply a dilatation (see math morpho for info). NB: dilation o gaussian = gaussian o dilatation
Definition at line 71 of file vtkImagePolyDataSeedConnectivity.cxx.
References Axis, ClipImageData, ClipImageWithAxis(), New(), OuterMold, PSC_MAX, PSC_MIN, and ThresholdRatio.
00072 { 00073 vtkImageData *input = this->GetInput(); 00074 vtkPolyData *output = this->GetOutput(); 00075 int intervalle = 2; 00076 int dim[3]; 00077 00078 vtkDebugMacro(<< "Executing polydata seed connectivity..."); 00079 00080 if (input == NULL) 00081 { 00082 vtkErrorMacro(<<"Input is NULL"); 00083 return; 00084 } 00085 00086 // just deal with volumes 00087 if ( input->GetDataDimension() != 3 ) 00088 { 00089 vtkErrorMacro("Bad input: only treats 3D structured point datasets"); 00090 return; 00091 } 00092 00093 input->GetDimensions(dim); 00094 00095 //Allocate a temporary image that will be filled in b&w 00096 //this is the base of the algothm, from a graysccale input + an axis 00097 //we produce a b&w image the the marching cubes can contour: 00098 00099 vtkImageData *imagedata = vtkImageData::New(); 00100 imagedata->SetOrigin( input->GetOrigin() ); 00101 imagedata->SetSpacing( input->GetSpacing() ); 00102 imagedata->SetExtent( input->GetExtent() ); 00103 imagedata->SetScalarTypeToUnsignedChar (); //for connectityseed + reduce mem usage 00104 imagedata->AllocateScalars(); 00105 00106 /* 00107 Result: piece of crap !! 00108 There was some leakage from another vessel that was near enough from the heart. 00109 */ 00110 00111 vtkImageSeedConnectivity *seed = vtkImageSeedConnectivity::New(); 00112 seed->SetInput( imagedata ); 00113 seed->SetInputConnectValue( 255 ); //If 0 -> inverse video, 255 -> rien ! 00114 00115 // Before starting the loop we should make sure the image has been clipped 00116 // with the polydata: 00117 this->ClipImageWithAxis(); 00118 00119 vtkPoints *points = this->Axis->GetPoints(); 00120 vtkDataArray* scalars = this->Axis->GetPointData()->GetScalars(); 00121 00122 int numPts = points->GetNumberOfPoints(); 00123 double p1[3], p2[3], p3[3], tuple[2]; 00124 double radius, signalvalue; 00125 int region[6]; 00126 int i_p2; //allow saving of p2 index 00127 unsigned short* inSI, *inSIEnd; 00128 unsigned char* outSI,*outSIEnd; 00129 00130 for(int i=0; i<numPts; i+=intervalle) 00131 { 00132 i_p2 = i+intervalle/2; 00133 points->GetPoint(i, p1); 00134 if(numPts <= i+2*intervalle) 00135 { 00136 i_p2 = i+intervalle; 00137 points->GetPoint(numPts - 1, p3); 00138 i = numPts; //no more iteration 00139 } 00140 else 00141 { 00142 points->GetPoint(i+intervalle, p3); 00143 } 00144 points->GetPoint(i_p2, p2); 00145 00146 //Now we can add p2 point to the see list: 00147 //seed->AddSeed( 3, p2); //too bad :( 00148 seed->AddSeed( (int)p2[0], (int)p2[1], (int)p2[2] ); 00149 00150 //this parameter seems to be ok for most image 00151 //furthermore it doesn't make any change to make it bigger. 00152 scalars->GetTuple(i_p2, tuple); 00153 radius = tuple[0]; 00154 signalvalue = tuple[1]; 00155 radius *= 4; //multiply for a factor 4 for aneurism case 00156 00157 region[0] = (int)PSC_MAX(p2[0] - radius, 0); 00158 region[2] = (int)PSC_MAX(p2[1] - radius, 0); 00159 region[4] = (int)PSC_MAX(p2[2] - radius, 0); 00160 00161 region[1] = (int)PSC_MIN(p2[0] + radius, dim[0] - 1); 00162 region[3] = (int)PSC_MIN(p2[1] + radius, dim[1] - 1); 00163 region[5] = (int)PSC_MIN(p2[2] + radius, dim[2] - 1); 00164 00165 // multiply signal by a factor this allow user to accuratley find the best 00166 // range 00167 signalvalue *= ThresholdRatio; 00168 00178 //Solution: this is too much a trouble: rather do it once on the entry (=first axis point) 00179 00180 vtkImageIterator<unsigned short> inIt(this->ClipImageData, region);//image_woheart 00181 vtkImageIterator<unsigned char> outIt(imagedata, region); 00182 // vtkImageProgressIterator should be nicer in conjonction with a wxGauge 00183 00184 // Loop through ouput pixels 00185 while (!inIt.IsAtEnd()) 00186 { 00187 inSI = inIt.BeginSpan(); inSIEnd = inIt.EndSpan(); 00188 outSI = outIt.BeginSpan(); outSIEnd = outIt.EndSpan(); 00189 00190 // Pixel operation 00191 while (inSI != inSIEnd) 00192 *outSI++ = (signalvalue <= *inSI++) ? 255 : 0; 00193 00194 inIt.NextSpan(); outIt.NextSpan(); 00195 } 00196 } 00197 00198 //NEW: introduced by Maciek/Marcela: use a vtkImageGaussian to get rid 00199 //of the crenelage/steps introduced by MarchingCubes 00200 00201 vtkImageGaussianSmooth *gauss = vtkImageGaussianSmooth::New(); 00202 gauss->SetInput( seed->GetOutput() ); 00203 gauss->SetDimensionality(3); 00204 //gauss->SetStandardDeviation(1.0); 00205 //gauss->SetRadiusFactor(3.); 00206 00207 vtkMarchingCubes *contour = vtkMarchingCubes::New(); 00208 contour->SetInput ( gauss->GetOutput() ); 00209 contour->SetNumberOfContours( 1 ); 00210 contour->SetValue(0, 128); 00211 contour->ComputeGradientsOn (); 00212 contour->ComputeScalarsOn (); 00213 00214 vtkCleanPolyData *clean = vtkCleanPolyData::New(); 00215 clean->SetInput ( contour->GetOutput() ); 00216 00217 vtkTriangleFilter *tf = vtkTriangleFilter::New(); 00218 tf->SetInput( clean->GetOutput() ); 00219 tf->Update(); 00220 00221 //Need to do a deep copy as we'll do a ShallowCopy afterwards 00222 output->DeepCopy( tf->GetOutput() ); 00223 00224 //output->Squeeze(); //usefull ? 00225 00226 // Now we do a dilatation of seed->GetOutput() in order to have inner (=output) 00227 // and outer mold (=OuterMold): 00235 //First apply a morpho math: dilatation of 2mm: 00236 vtkImageContinuousDilate3D *dilate = vtkImageContinuousDilate3D ::New(); 00237 dilate->SetInput ( seed->GetOutput() ); 00238 //TODO: determine real kernel based on scale = cm/pixel 00239 //See: http://public.kitware.com/pipermail/vtkusers/2000-September/004210.html 00240 //[Spacing is x and y is the distance between the samples. The units of measure 00241 //are your choice. Often medical images use millimeters. Let's say your medical 00242 //data resolution is 512 x 512 and your study has a 250 mm field of view. Then 00243 //the spacing in x and y would be 250/512 or .488 mm.] 00244 //therefore we have here: 00245 00246 int kernelsize[3]; 00247 double spacing[3]; 00248 seed->GetOutput()->GetSpacing( spacing ); //beware input should be Update() 00249 for(int j=0; j<3; j++) 00250 { 00251 //2mm thickness, we assume spacing units is in mm !! 00252 kernelsize[j] = 3; //(int) (2. / spacing[i]); 00253 //std::cout << "kernel=" << kernelsize[i] << ",et:" << (int)(2./0.3334) << ","; 00254 //beware if spacing=0.3334 -> 2/0.3334 = 5 !!!! bad bad +/-0.5 to see 00255 } 00256 dilate->SetKernelSize (kernelsize[0], kernelsize[1], kernelsize[2]); 00257 00258 //VTK filters rules !!! 00259 gauss->SetInput( dilate->GetOutput()); 00260 tf->Update(); 00261 // shallow copy result into output. 00262 // Could be re-written, as we know there is no vert neither strips... 00263 OuterMold->ShallowCopy( tf->GetOutput() ); 00264 00265 //OuterMold->Squeeze(); //usefull ? 00266 00267 //Delete temp stuff: 00268 imagedata -> Delete(); 00269 seed -> Delete(); 00270 gauss -> Delete(); 00271 contour -> Delete(); 00272 clean -> Delete(); 00273 tf -> Delete(); 00274 dilate -> Delete(); 00275 00276 //TODO: if this filter is used many times when working on different image size 00277 //I guess we need to find something brighter for this->ClipImageData 00278 }
static vtkImagePolyDataSeedConnectivity* vtkImagePolyDataSeedConnectivity::New | ( | ) | [static] |
Referenced by ClipImageWithAxis(), Execute(), and vtkImagePolyDataSeedConnectivity().
void vtkImagePolyDataSeedConnectivity::operator= | ( | const vtkImagePolyDataSeedConnectivity & | ) | [private] |
void vtkImagePolyDataSeedConnectivity::PrintSelf | ( | ostream & | os, | |
vtkIndent | indent | |||
) |
Definition at line 409 of file vtkImagePolyDataSeedConnectivity.cxx.
References Axis.
00410 { 00411 this->Superclass::PrintSelf(os,indent); 00412 if ( this->Axis ) 00413 { 00414 os << indent << "Axis of " << this->Axis->GetNumberOfPoints() 00415 << "points defined\n"; 00416 } 00417 else 00418 { 00419 os << indent << "Axis not defined\n"; 00420 } 00421 }
virtual void vtkImagePolyDataSeedConnectivity::SetAxis | ( | vtkPolyData * | ) | [virtual] |
vtkImagePolyDataSeedConnectivity::vtkGetMacro | ( | ThresholdRatio | , | |
double | ||||
) |
vtkImagePolyDataSeedConnectivity::vtkGetObjectMacro | ( | OuterMold | , | |
vtkPolyData | ||||
) |
vtkImagePolyDataSeedConnectivity::vtkGetObjectMacro | ( | Axis | , | |
vtkPolyData | ||||
) |
vtkImagePolyDataSeedConnectivity::vtkSetMacro | ( | ThresholdRatio | , | |
double | ||||
) |
vtkImagePolyDataSeedConnectivity::vtkTypeRevisionMacro | ( | vtkImagePolyDataSeedConnectivity | , | |
vtkStructuredPointsToPolyDataFilter | ||||
) |
vtkPolyData* vtkImagePolyDataSeedConnectivity::Axis [protected] |
Definition at line 58 of file vtkImagePolyDataSeedConnectivity.h.
Referenced by ClipImageWithAxis(), Execute(), PrintSelf(), vtkImagePolyDataSeedConnectivity(), and ~vtkImagePolyDataSeedConnectivity().
vtkImageData* vtkImagePolyDataSeedConnectivity::ClipImageData [protected] |
Definition at line 60 of file vtkImagePolyDataSeedConnectivity.h.
Referenced by ClipImageWithAxis(), Execute(), vtkImagePolyDataSeedConnectivity(), and ~vtkImagePolyDataSeedConnectivity().
vtkPolyData* vtkImagePolyDataSeedConnectivity::OuterMold [protected] |
Definition at line 61 of file vtkImagePolyDataSeedConnectivity.h.
Referenced by Execute(), vtkImagePolyDataSeedConnectivity(), and ~vtkImagePolyDataSeedConnectivity().
double vtkImagePolyDataSeedConnectivity::ThresholdRatio [protected] |
Definition at line 56 of file vtkImagePolyDataSeedConnectivity.h.
Referenced by Execute(), and vtkImagePolyDataSeedConnectivity().