C:/cmcintos/defOrgs/source/physical/Phys_LevelSet.cxx

00001 #ifndef _PHYS_LEVEL_SET_CXX
00002 #define _PHYS_LEVEL_SET_CXX
00003 
00004 #include "Phys_LevelSet.h"
00005 
00006 namespace mial
00007 {
00008 
00009         // TODO: remove #defines when no longer necessary
00010 #define DEFAULT_PROPAGATION_SCALING 0.5;
00011 #define DEFAULT_CURVATURE_SCALING 1.0;
00012 #define DEFAULT_ADVECTION_SCALING 3.0;
00013 #define DEFAULT_MAX_RMS_ERROR 0.02;
00014 #define DEFAULT_NUM_ITERATIONS 10;
00015 
00016         // default constructor:
00017         template< class DataType, class InputImageType, int nDims, class MType, class VType >
00018         Phys_LevelSet<DataType, InputImageType, nDims, MType, VType>
00019                 ::Phys_LevelSet()               
00020                 : Physics<DataType, nDims, MType, VType>() 
00021         {
00022                 inputImg =                              NULL;
00023                 distanceImg =                   NULL;
00024                 edgePotentialImg =              NULL;
00025                 propagationScaling =    DEFAULT_PROPAGATION_SCALING;
00026                 curvatureScaling =              DEFAULT_CURVATURE_SCALING;
00027                 advectionScaling =              DEFAULT_ADVECTION_SCALING;
00028                 maximumRMSError =               DEFAULT_MAX_RMS_ERROR;
00029                 numIterations =                 DEFAULT_NUM_ITERATIONS;
00030         }
00031 
00032         //----------------------------------------------------
00033         // Generate an distanceImg from a Geometric object
00034         // (e.g. the 'geom' member of a Phys_Euler).
00035         // (Should only be called after setInput() has been called):
00036         // TODO: check if setInput() precondition can be relaxed (only need inputImg's size...)
00037         template< class DataType, class InputImageType, int nDims, class MType, class VType >
00038         void
00039                 Phys_LevelSet<DataType,InputImageType,nDims,MType,VType>
00040 		::initializeDistanceImg()
00041         {
00042                 if(inputImg.IsNotNull())
00043                 {
00044                         std::cout << "Phys_LevelSet: Starting initializeDistanceImg()..." << std::endl;
00047                         //typedef  itk::FastMarchingImageFilter< 
00048                         //      InternalImageType, 
00049                         //      InternalImageType >  FastMarchingFilterType;
00050 
00052                         //FastMarchingFilterType::Pointer  fastMarchingFilter = FastMarchingFilterType::New();
00053 
00055                         //typedef FastMarchingFilterType::NodeContainer  NodeContainer;
00056                         //typedef FastMarchingFilterType::NodeType       NodeType;
00057 
00058                         //NodeContainer::Pointer seeds = NodeContainer::New(); // will hold the seeds used by the fastMarching filter
00059                         //seeds->Initialize();
00060 
00061                         //------------------------------
00062                         // extract the seed points from the geometry layer:
00063                         //unsigned int numNodes = geom->getNumNodes();
00064                         //const double INITIAL_DISTANCE = 5.0; 
00065 
00066                         //InternalImageType::IndexType* seedPositions = new InternalImageType::IndexType[ numNodes ];
00067                         //NodeType* nodes = new NodeType[ numNodes ];
00068 
00069                         //MType geomNodes = geom->getMatrixNodePositions();
00070 
00072                         //for( unsigned int i=0; i<numNodes; i++ )
00073                         //{
00074                         //      for( unsigned int j=0; j<nDims; j++ )
00075                         //      {
00076                         //              seedPositions[i][j] = geomNodes(i,j);
00077                         //      }
00078                         //      nodes[i].SetValue( INITIAL_DISTANCE );
00079                         //      nodes[i].SetIndex( seedPositions[i] );
00080                         //      seeds->InsertElement( i, nodes[i] );
00081                         //}
00082 
00083                         // DEBUG: TEMPORARILY USE LESS SEED POINTS------------------------
00084 
00085                         //InternalImageType::IndexType seedPosition;
00086                         //NodeType node;
00087                         //for( unsigned int j=0; j<nDims; j++ )
00088                         //{
00089                         //      seedPosition[j] = 50.0;
00090                         //}
00091                         //node.SetValue( INITIAL_DISTANCE );
00092                         //node.SetIndex( seedPosition );
00093                         //seeds->InsertElement( 0, node );
00094                         // END DEBUG -----------------------------------------------------
00095 
00096                         // DEBUG: GET BINARY IMAGE FROM MESH ------------------------
00097                         typedef Geom_MeshSpatialObject<DataType, nDims>                                         GeomMeshSpatialObjectType;
00098                         typedef typename GeomMeshSpatialObjectType::MeshSpatialObjectType                       MeshSpatialObjectType;
00099 
00100                                         
00101                         typename BinaryImageType::SizeType sz = inputImg->GetLargestPossibleRegion().GetSize();
00102                         typename BinaryImageType::Pointer binImg = static_cast< GeomMeshSpatialObjectType* > (this->geom.GetPointer())->generateBinaryImageFromTopology( sz);
00103 
00104                         //Assert that the phys level set is up to date.
00105                         this->geom->didTopologyChange();
00106                         this->geom->didNodesChange();
00107 
00108 
00109                         typedef itk::SignedDanielssonDistanceMapImageFilter<
00110                                 BinaryImageType,
00111                                 InternalImageType > DistanceMapFilterType;
00112                         typename DistanceMapFilterType::Pointer distanceMapFilter = DistanceMapFilterType::New();
00113 
00114                         distanceMapFilter->SetInput(binImg );
00115                         distanceMapFilter->Update();
00116                         distanceImg = distanceMapFilter->GetOutput();
00117                         // END DEBUG -----------------------------------------------------
00118 
00120                         //fastMarchingFilter->SetTrialPoints(  seeds  );
00122                         //fastMarchingFilter->SetSpeedConstant( 1.0 );
00123 
00124                         //fastMarchingFilter->SetOutputSize( inputImg->GetBufferedRegion().GetSize() );
00125 
00126                         //fastMarchingFilter->Update(); // run the filter
00127                         //distanceImg = fastMarchingFilter->GetOutput();
00128 
00129                         //delete [] nodes;
00130                         //delete [] seedPositions;
00131 
00133                         if(DEBUG)
00134                         {
00135                                 std::cout << "Phys_LevelSet: distance image initialized." << std::endl; 
00136                                 typedef itk::ImageFileWriter< InternalImageType >               DistanceWriterType;
00137                                 typename DistanceWriterType::Pointer distanceImageWriter = DistanceWriterType::New();
00138                                 std::string distanceImageFileName = "C:\\distanceImage.mhd";
00139                                 distanceImageWriter->SetFileName( distanceImageFileName.c_str() );
00140                                 distanceImageWriter->SetInput( distanceImg );
00141                                 distanceImageWriter->Update();
00142                                 std::cout << "Phys_LevelSet: distance image written to '" 
00143                                         << distanceImageFileName << "'." << std::endl;
00144 
00145                                 typedef itk::ImageFileWriter< BinaryImageType >         BinaryWriterType;
00146                                 typename BinaryWriterType::Pointer binaryImageWriter = BinaryWriterType::New();
00147                                 std::string binaryImageFileName = "C:\\binaryImageGeneratedFromMesh.mhd";
00148                                 binaryImageWriter->SetFileName( binaryImageFileName.c_str() );
00149                                 binaryImageWriter->SetInput( binImg );
00150                                 binaryImageWriter->Update();
00151                                 std::cout << "Phys_LevelSet: generated binary image written to '" 
00152                                         << binaryImageFileName << "'." << std::endl;
00153                         }
00154                         // END DEBUG ----------------------------------------------------------
00155                 } // end if(inputImg != NULL)
00156         } // end initializeDistanceImg(Geometric *geom)
00157 
00158 
00159         //----------------------------------------------------
00160         // Generate edge potential image based on the current inputImg
00161         template< class DataType, class InputImageType, int nDims, class MType, class VType >
00162         void
00163                 Phys_LevelSet<DataType,InputImageType,nDims,MType,VType>
00164 		::initializeEdgePotentialImg()
00165         {
00166                 if(inputImg.IsNotNull())
00167                 {
00168                         // TODO: Add CurvatureAnisotropicDiffusionImageFilter here?
00169 
00170                         typedef itk::GradientMagnitudeRecursiveGaussianImageFilter<
00171                                 InputImageType, 
00172                                 InternalImageType >  GradientFilterType;
00173 
00174                         typedef itk::SigmoidImageFilter<                               
00175                                 InternalImageType, 
00176                                 InternalImageType >  SigmoidFilterType;
00177 
00178                         // TODO: eliminate hardcoding of gradientMagnitudeFilter sigma
00179                         typename GradientFilterType::Pointer  gradientMagnitudeFilter = GradientFilterType::New();
00180                         const double sigma = 1.0;
00181                         gradientMagnitudeFilter->SetSigma( sigma );
00182 
00183                         // TODO: eliminate hardcoding of sigmoidFilter parameters
00184                         typename SigmoidFilterType::Pointer sigmoidFilter = SigmoidFilterType::New();
00185                         sigmoidFilter->SetOutputMinimum( 0.0 );
00186                         sigmoidFilter->SetOutputMaximum( 1.0 );
00187                         const double alpha =  -0.3;
00188                         const double beta  =  2;
00189                         sigmoidFilter->SetAlpha( alpha );
00190                         sigmoidFilter->SetBeta( beta );
00191 
00192                         // connect the filters:
00193                         gradientMagnitudeFilter->SetInput( inputImg );
00194                         sigmoidFilter->SetInput( gradientMagnitudeFilter->GetOutput() );
00195 
00196                         // run the filters:
00197                         sigmoidFilter->Update();
00198 
00199                         edgePotentialImg = sigmoidFilter->GetOutput();
00200 
00201                 } // end if(inputImg != NULL)
00202         }  // end initializeEdgePotentialImg()
00203 
00204         //----------------------------------------------------
00205         // DEBUG FUNCTION
00206         template< class DataType, class InputImageType, int nDims, class MType, class VType >
00207         void 
00208                 Phys_LevelSet<DataType,InputImageType,nDims,MType,VType>
00209 		::printInternalValues()
00210         {
00211                 std::cout << "inputImg initialized: " << inputImg.IsNotNull() << std::endl;
00212                 std::cout << "distanceImg initialized: " << distanceImg.IsNotNull() << std::endl;
00213                 std::cout << "edgePotentialImg initialized: " << edgePotentialImg.IsNotNull() << std::endl;
00214                 std::cout << "propagationScaling: " << propagationScaling << std::endl;
00215                 std::cout << "curvatureScaling: " << curvatureScaling << std::endl;
00216                 std::cout << "advectionScaling: " << advectionScaling << std::endl;
00217                 std::cout << "maximumRMSError: " << maximumRMSError << std::endl;
00218                 std::cout << "numIterations: " << numIterations << std::endl;
00219                 return;
00220         }
00221 
00222         //----------------------------------------------------
00223         template< class DataType, class InputImageType, int nDims, class MType, class VType >
00224         bool 
00225                 Phys_LevelSet<DataType,InputImageType,nDims,MType,VType>
00226 		::runDeformation(const std::string defName,typename DeformationType::deformationIn* const arg ,std::stringstream * const stream)
00227         {
00228 
00229                 //TODO make this more efficient--only update if change, only update new springs etc
00230                 if(this->geom->didTopologyChange() || this->geom->didNodesChange())
00231                 {
00232                         //The distance image must be reinitialized
00233                         initializeDistanceImg();
00234                 }
00235 
00236                 // TODO: replace O(n) search with lg(n) search on sorted list.
00237                 for(int i=0; i< this->numDeformations; i++)
00238                 {
00239                         if( defName.compare(this->deformationsList[i]->getName()) == 0 )
00240                         {
00241                                 try
00242                                 {
00243                                         typename DeformationType::DefArgSet org;
00244                                         org.distanceImg = distanceImg;
00245                                         this->deformationsList[i]->run(arg,&org,stream);
00246                                         break;
00247                                 }catch(typename DeformationType::Error * de)
00248                                 {
00249                                         std::cerr << "Could not complete deformation" << std::endl;
00250                                         Error e;
00251                                         e.msg = "Could not complete deformation";
00252                                         e.deformationNumber = i;
00253                                         e.deformationError = de;
00254                                         throw & e;
00255                                 }
00256                         }
00257                 }
00258                 return false;
00259         }
00260 
00261 
00262         //----------------------------------------------------
00263         template< class DataType, class InputImageType, int nDims, class MType, class VType >
00264         bool 
00265                 Phys_LevelSet<DataType,InputImageType,nDims,MType,VType>
00266 		::simulate()
00267         {
00268                 //std::cout << "Starting Phys_LevelSet simulation..." << std::endl; // DEBUG
00269                 // NOTE: use smartPointer.IsNull(), not == NULL!
00270                 if( inputImg.IsNull() ) { return -1; }
00271                 else
00272                 {
00273                         if( distanceImg.IsNull() )
00274                         {
00275                                 initializeDistanceImg();
00276                                 // TODO: add code here to generate a generic distance img (e.g. with a single seed in the middle)
00277                         }
00278                         if( edgePotentialImg.IsNull() ) 
00279                         {
00280                                 initializeEdgePotentialImg(); // generate an edge image based on the current inputImg
00281                         }
00282 
00283                         // note that the third template parameter for this filter is 
00284                         // defaulted to 'float' if not provided, which causes problems 
00285                         // later with assigning its output to an image:
00286                         typedef itk::GeodesicActiveContourLevelSetImageFilter<
00287                                 InternalImageType, 
00288                                 InternalImageType, 
00289                                 DataType >  GeodesicActiveContourFilterType;
00290 
00291                         typename GeodesicActiveContourFilterType::Pointer 
00292                                 levelSetFilter = GeodesicActiveContourFilterType::New();
00293 
00294                         // assign the levelSetFilter's inputs (class member images):
00295                         levelSetFilter->SetInput(distanceImg );
00296                         levelSetFilter->SetFeatureImage(                edgePotentialImg );
00297 
00298                         levelSetFilter->SetPropagationScaling(  propagationScaling );
00299                         levelSetFilter->SetCurvatureScaling(    curvatureScaling );
00300                         levelSetFilter->SetAdvectionScaling(    advectionScaling );
00301                         levelSetFilter->SetMaximumRMSError(             maximumRMSError );
00302                         levelSetFilter->SetNumberOfIterations(  numIterations );
00303 
00304                         // thresholding filter:
00305                         typedef itk::BinaryThresholdImageFilter< 
00306                                 InternalImageType, 
00307                                 BinaryImageType >  ThresholdingFilterType;
00308                         typename ThresholdingFilterType::Pointer thresholdFilter = ThresholdingFilterType::New();
00309 
00310                         // TODO: eliminate hardcoding of thresholdFilter parameters?
00311                         thresholdFilter->SetLowerThreshold( -1000.0 );
00312                         thresholdFilter->SetUpperThreshold(     0.0 );
00313                         thresholdFilter->SetOutsideValue(  0  );
00314                         thresholdFilter->SetInsideValue(  255 );
00315 
00316                         // connect the output of the levelSetFilter to the thresholdFilter's input:
00317                         thresholdFilter->SetInput( levelSetFilter->GetOutput() );
00318 
00319                         // run level set filter and threshold result:
00320                         thresholdFilter->Update();
00321 
00322                         outputImg = thresholdFilter->GetOutput();
00323 
00324                         std::cout << "Phys_LevelSet simulation completed." << std::endl;
00325                         //Feed the output distance image back into the level set filter
00326                         distanceImg = levelSetFilter->GetOutput();
00327 
00328                         std::cout << "Updating geometry" << std::endl;
00329                         this->geom->generateTopologyFromBinaryImage(outputImg);
00330 
00331                         std::cout << "Clock: " << this->time << std::endl;
00332                         this->time ++;
00333 
00334                         return false; // DEBUG: TEMPORARY!
00335                 }
00336         } // end simulate()
00337 
00338         //----------------------------------------------------
00339         template< class DataType, class InputImageType, int nDims, class MType, class VType >
00340         void 
00341                 Phys_LevelSet<DataType,InputImageType,nDims,MType,VType>
00342 		::setExternalForces( void * notUsed)
00343         {
00344                 // this is required because setExternalForces is pure virtual in the ABC
00345         }
00346 
00347         //----------------------------------------------------
00348         //template<class DataType,  int nDims>
00349         //      bool 
00350         //      Phys_LevelSet<DataType, vType, nDims>
00351         //      ::runDeformation(std::istream& args)
00352         //{
00353 
00354         //}
00355 
00356 } // end namespace mial
00357 
00358 #endif // _PHYS_LEVEL_SET_CXX included

Generated on Wed Jul 19 13:05:18 2006 for IDO by  doxygen 1.4.7