vtkImagePolyDataSeedConnectivity.cxx

Go to the documentation of this file.
00001 /*=========================================================================
00002 
00003   Program:   wxMaracas
00004   Module:    $RCSfile: vtkImagePolyDataSeedConnectivity.cxx,v $
00005   Language:  C++
00006   Date:      $Date: 2009/05/14 13:54:57 $
00007   Version:   $Revision: 1.1 $
00008 
00009   Copyright: (c) 2002, 2003
00010   License:
00011   
00012      This software is distributed WITHOUT ANY WARRANTY; without even 
00013      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
00014      PURPOSE.  See the above copyright notice for more information.
00015 
00016 =========================================================================*/
00017 #include "vtkImagePolyDataSeedConnectivity.h"
00018 
00019 #include <vtkPolyData.h>
00020 #include <vtkImageData.h>
00021 #include <vtkMath.h>
00022 #include <vtkPlane.h>
00023 #include <vtkSphere.h>
00024 #include <vtkImplicitBoolean.h>
00025 #include <vtkImplicitFunctionToImageStencil.h>
00026 #include <vtkImageStencil.h>
00027 #include <vtkObjectFactory.h>
00028 #include <vtkImageSeedConnectivity.h>
00029 #include <vtkImageIterator.h>
00030 #include <vtkImageGaussianSmooth.h>
00031 #include <vtkMarchingCubes.h>
00032 #include <vtkPolyDataConnectivityFilter.h>
00033 #include <vtkCleanPolyData.h>
00034 #include <vtkTriangleFilter.h>
00035 #include <vtkPointData.h>
00036 #include <vtkImageContinuousDilate3D.h>
00037 
00038 vtkCxxRevisionMacro(vtkImagePolyDataSeedConnectivity, "$Revision: 1.1 $");
00039 vtkStandardNewMacro(vtkImagePolyDataSeedConnectivity);
00040 vtkCxxSetObjectMacro(vtkImagePolyDataSeedConnectivity, Axis,vtkPolyData);
00041 
00042 //----------------------------------------------------------------------------
00043 vtkImagePolyDataSeedConnectivity::vtkImagePolyDataSeedConnectivity()
00044 {
00045   this->Axis = NULL;
00046   this->ClipImageData = vtkImageData::New();
00047   this->OuterMold = vtkPolyData::New();
00048   this->ThresholdRatio = 0.45;
00049 }
00050 //----------------------------------------------------------------------------
00051 vtkImagePolyDataSeedConnectivity::~vtkImagePolyDataSeedConnectivity()
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 }
00067 //Macros definitions
00068 #define PSC_MIN(x,y)      ((x)<(y) ? (x) : (y))
00069 #define PSC_MAX(x,y)      ((x)>(y) ? (x) : (y))
00070 //----------------------------------------------------------------------------
00071 void vtkImagePolyDataSeedConnectivity::Execute()
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 }
00279 //end of macros use
00280 #undef PSC_MAX
00281 #undef PSC_MIN
00282 //----------------------------------------------------------------------------
00283 //We need to add a function that from the raw data is able to clip with
00284 //the begining and ending of polydata to produce sharp edge.
00285 void vtkImagePolyDataSeedConnectivity::ClipImageWithAxis()
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 }
00408 //----------------------------------------------------------------------------
00409 void vtkImagePolyDataSeedConnectivity::PrintSelf(ostream& os, vtkIndent indent)
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 }
00422 
00423 

Generated on 18 Mar 2010 for creaMaracasVisu_lib by  doxygen 1.6.1