Jerome Piovano

Research in Medical Imaging and Computer Vision

/home/jpiovano/src/Odyssee++/trunk/Libs/LevelSet/src/Segmentation.h

Go to the documentation of this file.
00001 
00009 #ifndef SEGMENTATION_H
00010 #define SEGMENTATION_H
00011 
00012 #include <sstream>
00013 #include <vector>
00014 
00015 #include <Globals.h>
00016 #include <Schemes.h>
00017 #include <LevelSet.h>
00018 #include <Initializer.h>
00019 #include <DericheFilter.h>
00020 
00021 #include <SegmentationModule/SegmentationModule.h>
00022 
00023 using namespace Images;
00024 using namespace levelset;
00025 
00026 
00028 namespace segmentation {
00029 
00031         template <class _Modules,class _LevelSet,class _Index>
00032         float sum(_Modules & modules, const _LevelSet & phi, const _Index & ind, int& indice)
00033         {
00034                 //TODO automatic estimation via CFL conditions
00035                 //TODO normaliser a 1 la somme des weights => dt <= 1/v_max
00036                 float result = 0;
00037                 for (int i=0; i<modules.size(); i++){
00038                         const float value  = modules[i]->value(phi, ind);
00039                         const float weight = modules[i]->weight(ind);
00040                         result += value*weight;
00041                 }
00042                 return result;
00043         }
00044 
00060         template<unsigned DIM, typename Pixel = float>
00061         class Segmentation 
00062         {
00063         public: 
00064 
00065                 typedef           BaseImage<DIM, Pixel>              ImageType;
00066                 typedef           Initializer<DIM, float>            Initializer;
00067                 typedef           LevelSet<DIM, float>               LevelSet;
00068                 typedef typename  LevelSet::Index                    Index;
00069                 typedef           SegmentationModule<DIM,float>      SegmentationModule;
00070                 typedef           std::vector<SegmentationModule *>  Modules;
00071 
00072                 typedef           float (* ModuleAssembler)(Modules &, const LevelSet &, const Index &, int &);
00073 
00074                 typedef           Schemes<DIM,float>                 Schemes;
00075                 typedef           Pixels::RGB<unsigned char>         RGBPixel;
00076                 typedef           BaseImage<DIM, RGBPixel>           ColorImageType;
00077 
00080 
00082                 Segmentation(LevelSet *              _phi,              
00083                              Initializer *           _init,             
00084                              ImageType *             _data  = NULL,     
00085                              BaseImage<DIM, bool> *  _mask  = NULL,     
00086                              float                   _dt = 0.5f,        
00087                              int                     _reinit_freq = 1   
00088                              ); 
00089 
00091                 virtual ~Segmentation();
00092 
00094 
00096 
00098                 void add_module(SegmentationModule & _sm);
00100                 void remove_module(SegmentationModule & _sm);
00102                 void set_module_assembler(ModuleAssembler _assembler);
00104                 void set_level_set(LevelSet & _phi);
00106                 void set_initializer(Initializer & _init);
00108                 void set_data_term(ImageType & _data);
00110                 void set_mask(BaseImage<DIM, bool>& _mask);
00112                 float & dt();
00114                 int & reinit_freq();
00115         
00117 
00119                 
00121                 ColorImageType get_result(RGBPixel neg = RGBPixel(0,0,0), RGBPixel pos = RGBPixel(255,255,255));
00123                 ImageType get_binary_result();
00125                 ImageType get_speed(int _module = 0);
00127                 float get_energy();
00128 
00130 
00132 
00134                 void segment(int nbiter = 30, std::string evodir="", RGBPixel neg = RGBPixel(0,0,0), RGBPixel pos = RGBPixel(255,255,255));
00136                 bool stop_condition(int iter, int nbiter);
00138                 void init();
00140                 void iterate(int iter, int nbiter);
00141 
00142         protected:
00143 
00145 
00147 
00148                 LevelSet *                            m_phi;                
00149                 BaseImage<DIM, float>                 m_dphi;               
00150                 Initializer *                         m_init;               
00151                 ImageType *                           m_data;               
00152                 std::vector<SegmentationModule *>     m_sm;                 
00153                 ModuleAssembler                       m_assembler;          
00154                 BaseImage<DIM, bool> *                m_mask;               
00155                 int                                   m_reinit_freq;        
00156                 float                                 m_dt;                 
00157                 bool                                  m_stop_condition;     
00158 
00160         };
00161 
00162 
00170 
00171         // Constructors - Destructor - Initializers
00172 
00173 
00174         template<unsigned DIM, typename Pixel>
00175                 Segmentation<DIM, Pixel>::Segmentation(LevelSet * _phi,  Initializer * _init, ImageType * _data, BaseImage<DIM, bool> * _mask, float _dt, int _reinit_freq)
00176                 :m_phi(_phi), m_dphi(_phi->shape()), m_init(_init), m_data(_data), m_assembler(&sum), m_mask(_mask), m_reinit_freq(_reinit_freq), m_dt(_dt), m_stop_condition(false)
00177         { 
00178                 if (_data != NULL && _data->shape() != _phi->shape()) {
00179                         std::cerr << "Error : Shape of the data term and shape of the LevelSet don't match"  << std::endl;
00180                         exit(1);
00181                 }
00182                 if (_mask != NULL && _mask->shape() != _phi->shape()) {
00183                         std::cerr << "Error : Shape of the mask and shape of the LevelSet don't match"  << std::endl;
00184                         exit(1);
00185                 }
00186         }
00187 
00188         template<unsigned DIM, typename Pixel>
00189                 Segmentation<DIM, Pixel>::~Segmentation()
00190         { }
00191 
00192 
00194         // Modify segmentation information
00195 
00196 
00197         template<unsigned DIM, typename Pixel>
00198                 void Segmentation<DIM, Pixel>::add_module(SegmentationModule & _sm) 
00199         {
00200                 m_sm.push_back(&_sm);
00201         }
00202 
00203         template<unsigned DIM, typename Pixel>
00204                 void Segmentation<DIM, Pixel>::remove_module(SegmentationModule & _sm)  
00205         {
00206                 for (int i=0 ; i<m_sm.size() ; i++)
00207                         if (m_sm[i] == &_sm){
00208                                 std::swap(m_sm[i], *m_sm.end());
00209                                 m_sm.pop_back();
00210                                 return;
00211                         }
00212         }
00213 
00214         template<unsigned DIM, typename Pixel>
00215                 void Segmentation<DIM, Pixel>::set_module_assembler(ModuleAssembler _assembler)
00216         {
00217                 m_assembler = _assembler;
00218         }
00219 
00220         template<unsigned DIM, typename Pixel>
00221                 void Segmentation<DIM, Pixel>::set_mask( BaseImage<DIM, bool>& _mask) 
00222         {
00223                 if (_mask.shape() != m_phi->shape()) {
00224                         std::cerr << "Error : Shape of the mask and shape of the LevelSet don't match"  << std::endl;
00225                         exit(1);
00226                 }
00227                 m_mask = &_mask;
00228         }
00229 
00230         template<unsigned DIM, typename Pixel>
00231                 void Segmentation<DIM, Pixel>::set_initializer(Initializer & _init)
00232         {
00233                 m_init = &_init;
00234         }
00235 
00236         template<unsigned DIM, typename Pixel>
00237                 void Segmentation<DIM, Pixel>::set_level_set(LevelSet & _phi)
00238         {
00239                 m_phi = &_phi;
00240         }
00241 
00242         template<unsigned DIM, typename Pixel>
00243                 void Segmentation<DIM, Pixel>::set_data_term(ImageType & _data)
00244         {
00245                 if (_data.shape() != m_phi->shape()) {
00246                         std::cerr << "Error : Shape of the data term and shape of the LevelSet don't match"  << std::endl;
00247                         exit(1);
00248                 }
00249                 m_data = &_data;
00250         }
00251 
00252         template<unsigned DIM, typename Pixel>
00253                 float & Segmentation<DIM, Pixel>::dt()
00254         {
00255                 return m_dt;
00256         }
00257 
00258         template<unsigned DIM, typename Pixel>
00259                 int & Segmentation<DIM, Pixel>::reinit_freq()
00260         {
00261                 return m_reinit_freq;
00262         }
00263 
00264 
00266         // Results of the segmentation
00267 
00268 
00269         template<unsigned DIM, typename Pixel>
00270                 typename Segmentation<DIM, Pixel>::ColorImageType Segmentation<DIM, Pixel>::get_result(RGBPixel neg, RGBPixel pos)
00271         {
00272                 ColorImageType result;
00273 
00274                 result.resize(m_phi->shape());
00275 
00276                 if (m_data == NULL) 
00277                         result = 255;
00278                 else 
00279                         result = blitz::cast<unsigned char>(*m_data);
00280 
00281                 #pragma omp parallel for
00282                 for (int i = 0 ; i < m_phi->nb_points() ; i++){
00283                         const Index& ind = m_phi->get_point(i);
00284 
00285                         const float _phi = (*m_phi)(ind);
00286 
00287                         int inf_coords[DIM];
00288                         int sup_coords[DIM];
00289                         Schemes::find_neighbours(*m_phi, ind, inf_coords, sup_coords);
00290 
00291                         for (int i=0 ; i<DIM ; i++){
00292                                 Index inf = ind;
00293                                 Index sup = ind;
00294                                 inf(i+1) = inf_coords[i];
00295                                 sup(i+1) = sup_coords[i];
00296                                 if ((_phi * (*m_phi)(inf) <= 0) || (_phi * (*m_phi)(sup) <= 0))
00297                                         result(ind) = (_phi>0)? pos: neg;
00298                         }
00299                 }
00300 
00301                 return result;
00302         }
00303 
00304         template<unsigned DIM, typename Pixel>
00305                 typename Segmentation<DIM, Pixel>::ImageType Segmentation<DIM, Pixel>::get_binary_result() 
00306         {
00307                 ImageType result(m_phi->shape());
00308                 for (typename ImageType::template iterator<domain> ind=result.begin() ; ind!=result.end() ; ++ind )
00309                         result(ind) = ((*m_phi)(ind) < 0)? 0 : 255;
00310 
00311                 return result;
00312         }
00313 
00314         template<unsigned DIM, typename Pixel>
00315                 typename Segmentation<DIM, Pixel>::ImageType Segmentation<DIM, Pixel>::get_speed(int _module)
00316         {
00317                 ImageType result(m_phi->shape());
00318                 result = 0;
00319 
00320                 if (_module < 0 ||  _module > m_sm.size()){
00321                         std::cerr << " Module does not exist !" << std::endl;
00322                         return result;
00323                 }
00324 
00325                 if (_module == 0){
00326                         int indice;
00327                         #pragma omp parallel for
00328                         for (int i = 0 ; i < m_phi->nb_points() ; i++){
00329                                 const Index& ind = m_phi->get_point(i);
00330                                 if (m_mask==NULL || (*m_mask)(ind)==true)
00331                                         result(ind) = m_assembler(m_sm, *m_phi, ind, indice);
00332                         }
00333                 }
00334                 else {
00335                         #pragma omp parallel for
00336                         for (int i = 0 ; i < m_phi->nb_points() ; i++){
00337                                 const Index& ind = m_phi->get_point(i);
00338                                 if (m_mask==NULL || (*m_mask)(ind)==true){
00339                                         const float value  = m_sm[_module-1]->value(*m_phi, ind);
00340                                         const float weight = m_sm[_module-1]->weight(ind);
00341                                         result(ind) = value*weight;
00342                                 }
00343                         }
00344                 }
00345                 
00346                 return result;
00347         }
00348 
00349         template<unsigned DIM, typename Pixel>
00350                 float Segmentation<DIM, Pixel>::get_energy() 
00351         {
00352                 float total_energy = 0;
00353         
00354                 for (unsigned int i = 0 ; i < m_phi->nb_points() ; i++){
00355 
00356                         const Index& ind = m_phi->get_point(i);
00357 
00358                         if (m_mask==NULL || (*m_mask)(ind)!=0) 
00359                                 for (int j=0; j<m_sm.size(); j++){
00360                                         const float energy = m_sm[j]->energy(*m_phi, ind);
00361                                         const float weight = m_sm[j]->weight(ind);
00362                                         total_energy += energy*weight;
00363                                 }
00364                 }
00365 
00366                 return total_energy;
00367         }
00368 
00369 
00371         // Launch the segmentation
00372 
00373         template<unsigned DIM, typename Pixel>
00374                 void Segmentation<DIM, Pixel>::segment(int nbiter, std::string evodir, RGBPixel neg, RGBPixel pos) 
00375         {
00376                 // initialization
00377                 init();
00378 
00379                 // main loop
00380                 for (int i=0 ; !m_stop_condition ; i++){
00381 
00382                         std::cout << i << std::endl;
00383 
00384                         #ifdef SAVE_EVOLUTION
00385                         if((i%int(SAVE_EVOLUTION))==0) {
00386 
00387                                 std::ostringstream name;
00388 
00389                                 //TODO oblige de faire 3 objets ofstream sinon foire 
00390                                 std::ofstream file1;
00391                                 std::ofstream file2;
00392                                 std::ofstream file3;
00393 
00394                                 #if 1
00395                                 //TODO energy (?)
00396                                 std::cout <<  " - Energy : " << get_energy() << std::endl;
00397 
00398                                 name.str(""); 
00399                                 name << evodir << "phi_" << std::setw(6) << std::setfill('0') << i << ".inr";
00400                                 file1.open(name.str().c_str());
00401                                 file1 << format("inrimage") << *m_phi;
00402                                 std::cout <<  " - Saved " << name.str() << " ..."  << std::endl;
00403                                 #endif
00404 
00405                                 #if 1
00406                                 if (DIM == 2){
00407                                         // colored ppm only in 2D
00408                                         name.str("");
00409                                         name << evodir << "result_" << std::setw(6) << std::setfill('0') << i << ".ppm";
00410                                         file2.open(name.str().c_str());
00411                                         file2 << format("rawppm") << get_result(neg, pos);
00412                                         std::cout <<  " - Saved " << name.str() << " ..."  << std::endl;
00413                                 }
00414                                 else {
00415                                         // colored inrimage-5 in 2D/3D
00416                                         name.str("");
00417                                         name << evodir << "result_" << std::setw(6) << std::setfill('0') << i << ".inr";
00418                                         file2.open(name.str().c_str());
00419                                         ImageType result(m_phi->shape());
00420                                         result = blitz::cast<float>(get_result(neg, pos));
00421                                         file2 << format("Inrimage-5") << result; //blitz::cast<float>(get_result(neg, pos)); 
00422                                         std::cout <<  " - Saved " << name.str() << " ..."  << std::endl;
00423                                 }
00424                                 #endif
00425 
00426                                 #if 0  // speed
00427                                 for (int j=1; j<=m_sm.size(); j++){
00428                                         std::ofstream file3;
00429                                         name.str("");
00430                                         name << evodir << "speed_module" << j << "_" << std::setw(6) << std::setfill('0') << i << ".inr";
00431                                         file3.open(name.str().c_str());
00432                                         file3 << format("inrimage") << get_speed(j) ;
00433                                         std::cout <<  " - Saved " << name.str() << " ..."  << std::endl;
00434                                 }
00435                                 name.str("");
00436                                 name << evodir << "speed_" << std::setw(6) << std::setfill('0') << i << ".inr";
00437                                 file3.open(name.str().c_str());
00438                                 file3 << format("inrimage") << get_speed(0) ;
00439                                 std::cout <<  " - Saved " << name.str() << " ..."  << std::endl;
00440                                 #endif
00441 
00442                                 #if 1
00443                                 for (int j=0; j<m_sm.size(); j++)
00444                                         m_sm[j]->save_result(*m_phi, evodir, i);
00445                                 #endif
00446                         }
00447                         #endif
00448 
00449                         iterate(i, nbiter);
00450                 }
00451         }
00452 
00453         template<unsigned DIM, typename Pixel>
00454                 bool Segmentation<DIM, Pixel>::stop_condition(int iter, int nbiter)
00455         {
00456                 // stop at convergence
00457                 if (nbiter < 0){
00458 
00459                         // static object that keep traces of variation of the contour.
00460                         // stop if no variations (but maybe oscillation of max period 50) of the contour during 10 iter, or iter > 2000 (moche mais comment ?)
00461                         static BaseImage<DIM, short> sign_change(m_phi->shape());
00462                         static int count = 0;
00463 
00464                         if (iter == 0) {
00465                                 sign_change = 0;
00466                                 count = 0;
00467                         }
00468 
00469                         int nb_sign_change = 0;
00470                         for (int i = 0 ; i < m_phi->pos_to_neg_index() ; i++){
00471                                 const Index& ind = m_phi->get_point(i);
00472                                 if (iter - sign_change(ind) > 50) // no oscillation
00473                                         nb_sign_change++;
00474                                 sign_change(ind) = iter;
00475                         }
00476 
00477                         for (int i = m_phi->neg_to_pos_index() ; i < m_phi->nb_points() ; i++){
00478                                 const Index& ind = m_phi->get_point(i);
00479                                 if (iter - sign_change(ind) > 50) // no oscillation
00480                                         nb_sign_change++;
00481                                 sign_change(ind) = iter;
00482                         }
00483 
00484                         if (nb_sign_change > 0) count = 0;
00485                         return ((nb_sign_change == 0) && (++count > 20)) || (iter >= 2000);
00486                 }
00487 
00488                 // stop when (iter > iter max)
00489                 else return (iter >= nbiter);
00490         }
00491 
00492         template<unsigned DIM, typename Pixel>
00493                 void Segmentation<DIM, Pixel>::init()
00494         {
00495                 // resize of d_phi
00496                 if (m_dphi.shape() != m_phi->shape())
00497                         m_dphi.resize(m_phi->shape());
00498                         
00499                 m_dphi=0.0f;
00500 
00501                 // initialization of the modules
00502                 for (int i=0; i<m_sm.size(); i++)
00503                         m_sm[i]->init(*m_phi);
00504 
00505                 m_stop_condition = false;
00506         }
00507 
00508         template<unsigned DIM, typename Pixel>
00509                 void Segmentation<DIM, Pixel>::iterate(int iter, int nbiter) 
00510         {
00511                 #ifdef PRINT_TIME
00512                 timeval _time;
00513                 Globals::initChrono(_time);
00514                 #endif
00515 
00516                 m_dphi=0.0f;
00517 
00519 //ImageType result(m_phi->shape());
00520 // result = 0;
00521 int indice;
00523 
00524                 // speed computation
00525                 #pragma omp parallel for
00526                 for (int i = 0 ; i < m_phi->nb_points() ; i++){
00527 
00528                         const Index& ind = m_phi->get_point(i);
00529                         m_dphi(ind)=0.0f;
00530 
00531                         if (m_mask==NULL || (*m_mask)(ind)==true)
00532                                 m_dphi(ind) = m_assembler(m_sm, *m_phi, ind, indice);
00533                                 //result(ind) = indice;
00534                 }
00535 
00537 //std::ostringstream name;
00538 //name.str("");
00539 //std::ofstream file3;
00540 //name << std::setw(6) << std::setfill('0') << iter << ".inr";
00541 //file3.open(name.str().c_str());
00542 //file3 << format("inrimage") << result;
00543 //std::cout <<  "       - Saved " << name.str() << " ..."  << std::endl;
00545 
00546                 #ifdef PRINT_TIME
00547                 Globals::printChrono("  => compute speed : ", _time);
00548                 Globals::initChrono(_time);
00549                 #endif
00550 
00551                 // phi += dt * d_phi
00552                 m_phi->update(m_dphi, m_dt);
00553 
00554                 #ifdef PRINT_TIME
00555                 Globals::printChrono("  => update Level set : ", _time);
00556                 Globals::initChrono(_time);
00557                 #endif
00558 
00559                 // stop condition
00560                 m_stop_condition = stop_condition(iter, nbiter);
00561 
00562                 #ifdef PRINT_TIME
00563                 Globals::printChrono("  => stop condition : ", _time);
00564                 Globals::initChrono(_time);
00565                 #endif
00566 
00567                 // update segmentation modules
00568                 for (int i=0; i<m_sm.size(); i++)
00569                         if (m_sm[i]->adaptive()) m_sm[i]->update(*m_phi);
00570 
00571                 #ifdef PRINT_TIME
00572                 Globals::printChrono("  => total update modules : ", _time);
00573                 Globals::initChrono(_time);
00574                 #endif
00575 
00576                 // level-set reinitialization
00577                 if(iter%m_reinit_freq == 0) 
00578                         m_init->reinit_band(*m_phi);
00579 
00580                 #ifdef PRINT_TIME
00581                 Globals::printChrono("  => total reinit band : ", _time);
00582                 Globals::initChrono(_time);
00583                 #endif
00584         }
00585 }
00586 
00587 #endif // SEGMENTATION_H

For further information, please contact Jerome Piovano - Last update 2008-02-08