Jerome Piovano

Research in Medical Imaging and Computer Vision

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

Go to the documentation of this file.
00001 
00024 #ifndef LEVELSET_H
00025 #define LEVELSET_H
00026 
00027 #include <cmath>
00028 #include <Image.H>
00029 #include <Initializer.h>
00030 
00031 #include <Fluxes.h>
00032 
00033 #define _USE_MATH_DEFINES 
00034  
00035 using namespace Images;
00036 using namespace levelset;
00037 
00038 
00040 namespace levelset {
00041 
00046         template<unsigned DIM, typename Pixel = float>
00047         class LevelSet : public BaseImage<DIM, Pixel>
00048         {
00049         public:
00050 
00051                 typedef          BaseImage<DIM, Pixel>             base;
00052                 typedef typename base::Shape                       Shape;
00053                 typedef typename base::Index                       Index;
00054                 typedef          Initializer<DIM, Pixel>           Initializer;
00055 
00056 //TODO type de l'approximateur fixe en dur dans le code . autre idee ???
00057 
00058                 typedef          Weno3<DIM, Pixel>                 Approximator;
00059                 typedef          Fluxes<DIM, Approximator, Pixel>  Fluxes;
00060                 typedef          Schemes<DIM, Pixel>               Schemes;
00061 
00064 
00066                 LevelSet();
00067 
00069                 LevelSet(const Shape &  _shape,              
00070                          float          _thickness = 3.0f    
00071                          );
00072 
00074                 template <typename Pixel2>
00075                 LevelSet(const LevelSet<DIM, Pixel2>& ls):base(ls), m_thickness(ls.thickness()), m_mask(ls.shape()), m_nbpts(0), m_pos_to_neg(0), m_neg_to_pos(0)
00076                 {
00077                         m_mask = -1;
00078                         m_band = new Index[ls.size()];
00079                         for (int i=0 ; i<ls.nb_points() ; i++)
00080                                 add_point(ls.get_point(i));
00081                 }
00082 
00084                 template <typename Pixel2>
00085                 LevelSet operator=(const LevelSet<DIM, Pixel2>& ls)
00086                 {
00087                         if (base::shape != ls.shape())
00088                                 resize(ls.shape());
00089                         
00090                         base::operator=(ls);
00091                         m_thickness = ls.thickness();
00092                         m_nbpts = 0;
00093                         for (int i=0 ; i<ls.nb_points() ; i++)
00094                                 add_point(ls.get_point(i));
00095                         return *this;
00096                 }
00097 
00099                 virtual ~LevelSet();
00100 
00101                 using base::operator=;
00102 
00103                 void resize(const Shape& s);
00104 
00106 
00108 
00110                 void update(const BaseImage<DIM, Pixel> &dphi, const float dt);
00111 
00113 
00115 
00117                 bool is_in_band(const Index& ind) const;
00119                 bool add_point(const Index& ind);
00121                 bool remove_point(const Index& ind);
00123                 const Index& get_point(unsigned i) const;
00125                 int nb_points() const;
00127                 int pos_to_neg_index() const;
00129                 int neg_to_pos_index() const;
00131                 float & thickness();
00133                 void clear_band();
00134 
00136 
00138 
00140                 void init_sphere(const Index& center, float radius, Initializer& init, bool add=true);
00142                 void init_small_spheres(float radius, float window, Initializer& init, bool add=true);
00144                 void init_border(const unsigned border, Initializer& init, bool add=true);
00146                 void init_rectangle(const Index& tl, const Index& br, Initializer& init, bool add=true);
00148                 void init_image(const BaseImage<DIM, Pixel>& image, Initializer& init, const Pixel& pix = 0);
00149 
00151 
00153 
00154 //TODO accelerer reinit pde . globalement reinit pde assez lent ... gprof dis que ca viens de blitz tiny vector .... peut etre essayer d implementer avec des tableaux plutot.
00155 
00157                 void reinit_PDE(int iter = 2, float dt = 0.4);
00159                 void extend_data(BaseImage<DIM, Pixel>& u, short type = 0, int iter = 20, float dt = 0.4) const;
00161                 Pixel band_average(const BaseImage<DIM, Pixel>& u, const float epsilon = 2.0) const;
00163                 Pixel band_integral(const BaseImage<DIM, Pixel>& u, const float epsilon = 2.0) const;
00165                 Pixel area(const float epsilon = 2.0) const;
00166 
00167         protected:
00168 
00170 
00172 
00173                 float                            m_thickness;   
00174                 Index *                          m_band;        
00175                 BaseImage<DIM, int>              m_mask;        
00176                 unsigned                         m_nbpts;       
00177                 unsigned                         m_pos_to_neg;  
00178                 unsigned                         m_neg_to_pos;  
00179 
00181         };
00182 
00183 
00191 
00192         // Constructors - Destructor - Copy
00193 
00194         template<unsigned DIM, typename Pixel>
00195                         LevelSet<DIM, Pixel>::LevelSet()
00196         : base(), m_thickness(0), m_band(NULL), m_mask(), m_nbpts(0), m_pos_to_neg(0), m_neg_to_pos(0)
00197         { }
00198 
00199         template<unsigned DIM, typename Pixel>
00200                         LevelSet<DIM, Pixel>::LevelSet(const Shape &  _shape, float _thickness)
00201         : base(_shape), m_thickness(_thickness), m_mask(_shape), m_nbpts(0), m_pos_to_neg(0), m_neg_to_pos(0)
00202         { 
00203                 m_mask = -1;
00204                 base::operator=(-m_thickness);
00205                 m_band = new Index[base::size()];
00206         }
00207 
00208         template<unsigned DIM, typename Pixel>
00209                 LevelSet<DIM, Pixel>::~LevelSet() 
00210         { 
00211                 if (m_band != NULL) delete[] m_band;
00212         }
00213 
00214         template<unsigned DIM, typename Pixel>
00215                 void LevelSet<DIM, Pixel>::resize(const Shape& s)
00216         {
00217                 base::resize(s);
00218                 m_mask.resize(s);
00219                 base::operator=(-m_thickness);
00220                 m_mask = -1;
00221                 if (m_band != NULL) delete[] m_band;
00222                 m_band = new Index[base::size()];
00223                 m_nbpts = 0;
00224         }
00225 
00226 
00228         // Update of the narrow band
00229 
00230 
00231         // note : after the update, the array 'm_band' is organized as follow :
00232         //
00233         //          --------------------------------------------------------------------------------------
00234         //  m_band  |      pos->neg      |                  other                   |     neg->pos       |
00235         //          --------------------------------------------------------------------------------------
00236         //          ^                    ^                                         ^                    ^
00237         //          0               m_pos_to_neg                             m_neg_to_pos            m_nbpts
00238         //
00239         // where,
00240         //    - pos->neg [0,            m_pos_to_neg-1] : points where the sign of phi changed from positive to negative.
00241         //    - neg->pos [m_pos_to_neg, m_neg_to_pos-1] : points where the sign of phi didn't change
00242         //    - other    [m_neg_to_pos,      m_nbpts-1] : points where the sign of phi changed from negative to positive
00243         // 
00244         // cf : "The Problem of the Dutch National Flag", Dijkstra
00245 
00246         template<unsigned DIM, typename Pixel>
00247         void LevelSet<DIM, Pixel>::update(const BaseImage<DIM, Pixel> &dphi, const float dt)
00248         {
00249                 m_pos_to_neg = 0;
00250                 m_neg_to_pos = m_nbpts;
00251 
00252                 unsigned int i = 0;
00253                 while (i < m_neg_to_pos)
00254                 {
00255                         const Index& ind = get_point(i);
00256 
00257                         Pixel tmp = base::operator()(ind);
00258 
00259                         base::operator()(ind) += dt * dphi(ind);
00260 
00261                         // keep the zero level set in the band
00262                         if (m_thickness > 0) {
00263                                 base::operator()(ind) = (base::operator()(ind) >  m_thickness) ?  m_thickness : base::operator()(ind);
00264                                 base::operator()(ind) = (base::operator()(ind) < -m_thickness) ? -m_thickness : base::operator()(ind);
00265                         }
00266 
00267                         // sign changes
00268                         if(tmp * base::operator()(ind) < 0)
00269                         {  
00270                                 //pos->neg
00271                                 if (tmp>0){
00272                                         std::swap(m_band[m_pos_to_neg], m_band[i]);
00273                                         std::swap(m_mask(m_band[m_pos_to_neg]), m_mask(m_band[i]));
00274                                         m_pos_to_neg++;
00275                                         i++;
00276                                 }
00277                                 //neg->pos
00278                                 else if(tmp<0) {
00279                                         m_neg_to_pos--;
00280                                         std::swap(m_band[m_neg_to_pos], m_band[i]);
00281                                         std::swap(m_mask(m_band[m_neg_to_pos]), m_mask(m_band[i]));
00282                                 }
00283                         }
00284                         //others
00285                         else i++;
00286                 }
00287         }
00288         
00289 
00291         //  Access/Modif of the narrow band 
00292         
00293 
00294         template<unsigned DIM, typename Pixel>
00295         bool LevelSet<DIM, Pixel>::is_in_band(const Index& ind) const
00296         {
00297                 return (m_mask(ind) != -1);
00298         }
00299                 
00300         template<unsigned DIM, typename Pixel>
00301         bool LevelSet<DIM, Pixel>::add_point(const Index& ind)
00302         {
00303                 if (!is_in_band(ind)){
00304 
00305                         // we put the indice of the point in the mask of indice
00306                         m_mask(ind) = m_nbpts;
00307 
00308                         // we add the point at the end of m_band
00309                         m_band[m_nbpts++] = ind;
00310                         return true;
00311                 }
00312                 return false;
00313         }
00314 
00315         template<unsigned DIM, typename Pixel>
00316         bool LevelSet<DIM, Pixel>::remove_point(const Index& ind)
00317         {
00318                 if (is_in_band(ind)){
00319                         const int position = m_mask(ind);
00320 
00321                         // we remove the point from the band
00322                         m_mask(ind) = -1;
00323                         m_nbpts--;
00324 
00325                         // we put the last point at its place
00326                         if (position != m_nbpts){
00327                                 m_band[position] = m_band[m_nbpts];
00328                                 m_mask(m_band[position]) = position;
00329                         }
00330                         return true;
00331                 }
00332                 return false;
00333         }
00334                 
00335         template<unsigned DIM, typename Pixel>
00336         const typename LevelSet<DIM, Pixel>::Index& LevelSet<DIM, Pixel>::get_point(unsigned i) const
00337         {
00338                 return m_band[i];
00339         }
00340                 
00341         template<unsigned DIM, typename Pixel>
00342         int LevelSet<DIM, Pixel>::nb_points() const
00343         {
00344                 return m_nbpts;
00345         }       
00346 
00347         template<unsigned DIM, typename Pixel>
00348         int LevelSet<DIM, Pixel>::pos_to_neg_index() const
00349         {
00350                 return m_pos_to_neg;
00351         }       
00352                 
00353         template<unsigned DIM, typename Pixel>
00354         int LevelSet<DIM, Pixel>::neg_to_pos_index() const
00355         {
00356                 return m_neg_to_pos;
00357         }       
00358                 
00359         template<unsigned DIM, typename Pixel>
00360         float & LevelSet<DIM, Pixel>::thickness() 
00361         {
00362                 return m_thickness;
00363         }
00364         
00365         template<unsigned DIM, typename Pixel>
00366         void LevelSet<DIM, Pixel>::clear_band()
00367         {
00368                 m_nbpts = 0;
00369                 m_mask = -1;
00370         }
00371 
00372         
00374         // Initializers
00375         
00376 
00377         template<unsigned DIM, typename Pixel>
00378         void LevelSet<DIM, Pixel>::init_sphere(const Index& center, float radius, Initializer& init, bool add)
00379         {
00380                 for (typename base::template iterator<domain> i=this->begin() ; i!=this->end() ; ++i ){
00381 
00382                         //compute the squared distance of the point 'i' to the point 'center'
00383                         float dist = 0;
00384                         for (unsigned dim=1 ; dim<=base::dimension() ; dim++)
00385                                 dist += Maths::sqr(i(dim)-center(dim));
00386 
00387                         dist = radius - sqrt(dist);
00388 
00389                         if (add) base::operator()(i) = ((dist>=0) || (base::operator()(i)>0))? 1 : -1;
00390                         else     base::operator()(i) = ((dist< 0) && (base::operator()(i)>0))? 1 : -1;
00391                 }
00392 
00393                 init.init_band(*this);
00394         }
00395 
00396         template<unsigned DIM, typename Pixel>
00397         void LevelSet<DIM, Pixel>::init_small_spheres(float radius, float window, Initializer& init, bool add)
00398         {
00399                 for (typename base::template iterator<domain> i=this->begin() ; i!=this->end() ; ++i ){
00400 
00401                         //compute the squared distance of the point 'i % windows' to the point of coordinate 'windows / 2'
00402                         float dist = 0;
00403                         for (unsigned dim=1 ; dim<=base::dimension() ; dim++)
00404                                 dist += Maths::sqr(i(dim)%int(window)-window/2);
00405 
00406                         dist = radius - sqrt(dist);
00407 
00408                         if (add) base::operator()(i) = ((dist>=0) || (base::operator()(i)>0))? 1 : -1;
00409                         else     base::operator()(i) = ((dist< 0) && (base::operator()(i)>0))? 1 : -1;
00410                 }
00411 
00412                 init.init_band(*this);
00413         }
00414         
00415         template<unsigned DIM, typename Pixel>
00416         void LevelSet<DIM, Pixel>::init_border(const unsigned border, Initializer& init, bool add)
00417         {
00418                 for (typename base::template iterator<domain> i=this->begin() ; i!=this->end() ; ++i ){
00419 
00420                         //inside=true if the point 'i' inside the region
00421                         bool inside = true;
00422                         for (unsigned dim=1 ; dim<=base::dimension() ; dim++)
00423                                 inside &= (i(dim) >= border) && (i(dim) <= base::extent(dim-1) - border);
00424 
00425                         if (add) base::operator()(i) = ( inside || (base::operator()(i)>0))? 1 : -1;
00426                         else     base::operator()(i) = (!inside && (base::operator()(i)>0))? 1 : -1;
00427                 }
00428 
00429                 init.init_band(*this);
00430         }
00431         
00432         template<unsigned DIM, typename Pixel>
00433         void LevelSet<DIM, Pixel>::init_rectangle(const Index& tl, const Index& br, Initializer& init, bool add)
00434         {
00435                 for (typename base::template iterator<domain> i=this->begin() ; i!=this->end() ; ++i ){
00436 
00437                         //inside=true if the point 'i' inside the region
00438                         bool inside = true;
00439                         for (unsigned dim=1 ; dim<=base::dimension() ; dim++)
00440                                 inside &= (i(dim) >= tl(dim)) && (i(dim) <= br(dim));
00441 
00442                         if (add) base::operator()(i) = ( inside || (base::operator()(i)>0))? 1 : -1;
00443                         else     base::operator()(i) = (!inside && (base::operator()(i)>0))? 1 : -1;
00444                 }
00445 
00446                 init.init_band(*this);
00447         }
00448 
00449         template<unsigned DIM, typename Pixel>          
00450         void LevelSet<DIM, Pixel>::init_image(const BaseImage<DIM, Pixel>& image, Initializer& init, const Pixel& pix)
00451         {
00452                 resize(image.shape());
00453                 
00454                 operator=(image);
00455                 
00456                 for (typename base::template iterator<domain> i=this->begin() ; i!=this->end() ; ++i ){
00457                         base::operator()(i) = (base::operator()(i) > pix)? 1 : -1;
00458                 }
00459 
00460                 init.init_band(*this);
00461         }
00462         
00463 
00465         // Auxiliary functions
00466 
00467 
00468         template<unsigned DIM, typename Pixel>
00469         void LevelSet<DIM, Pixel>::reinit_PDE(int iter, float dt)
00470         {
00471                 // note : pb si sur stack et que temp trop gros, foire .. donc alloc/desalloc explicite.
00472                 Pixel* temp = new Pixel[nb_points()];
00473                         
00474                 for (int t=0;t<iter;t++) {      
00475                         #pragma omp parallel for
00476                         for (int i = 0 ; i < nb_points() ; i++){
00477                                 const Index& ind = get_point(i);
00478                                 temp[i] = Fluxes::reinitialization(*this,ind);
00479                         }
00480 
00481                         #pragma omp parallel for
00482                         for (int i = 0 ; i < nb_points() ; i++){
00483                                 const Index& ind = get_point(i);
00484                                 base::operator()(ind) += dt*temp[i];
00485                         }
00486                 }
00487 
00488                 delete[] temp;
00489         }
00490 
00491         template<unsigned DIM, typename Pixel>
00492         void LevelSet<DIM, Pixel>::extend_data(BaseImage<DIM, Pixel>& u, short type, int iter, float dt) const
00493         {
00494                 Pixel temp[nb_points()];
00495 
00496                 for (int t=0;t<iter;t++) {
00497                         #pragma omp parallel for
00498                         for (int i = 0 ; i < nb_points() ; i++){
00499                                 const Index& ind = get_point(i);
00500                                 switch(type){
00501                                         case  1 : temp[i] = (base::operator()(ind) >  0) ? Fluxes::extension(*this,u,ind) : 0; break;
00502                                         case -1 : temp[i] = (base::operator()(ind) <= 0) ? Fluxes::extension(*this,u,ind) : 0; break;
00503                                         default : temp[i] = Fluxes::extension(*this,u,ind); break;
00504                                 }
00505                         }
00506                                 
00507                         #pragma omp parallel for
00508                         for (int i = 0 ; i < nb_points() ; i++){
00509                                 const Index& ind = get_point(i);
00510                                 u(ind)  += dt * temp[i];
00511                         }
00512                 }
00513         }
00514 
00515         template<unsigned DIM, typename Pixel>
00516         Pixel LevelSet<DIM, Pixel>::band_average(const BaseImage<DIM, Pixel>& u, const float epsilon) const
00517         {
00518                 Pixel num = 0;
00519                 Pixel den = 0;
00520 
00521                 for (int i = 0 ; i < nb_points() ; i++){
00522                         const Index& ind = get_point(i);
00523                         const Pixel  val = base::operator()(ind);
00524 
00525                         if (fabs(val) < epsilon) {
00526                                 const Pixel tmp = Globals::delta(val, epsilon) * Schemes::norm_gradient(*this, ind);
00527                                 den += tmp;
00528                                 num += tmp * u(ind);
00529                         }
00530                 }
00531 
00532                 if (den < Globals::EPS) return 0;
00533 
00534                 return num / den;
00535         }
00536 
00537         template<unsigned DIM, typename Pixel>
00538         Pixel LevelSet<DIM, Pixel>::band_integral(const BaseImage<DIM, Pixel>& u, const float epsilon) const
00539         {
00540                 Pixel sum = 0;
00541 
00542                 for (int i = 0 ; i < nb_points() ; i++){
00543                         const Index& ind = get_point(i);
00544                         const Pixel  val = base::operator()(ind);
00545 
00546                         if (fabs(val) < epsilon)
00547                                 sum += u(ind) * Globals::delta(val, epsilon) * Schemes::norm_gradient(*this, ind);
00548                 }
00549 
00550                 return sum;
00551         }
00552 
00553         template<unsigned DIM, typename Pixel>
00554         Pixel LevelSet<DIM, Pixel>::area(const float epsilon) const
00555         {
00556                 Pixel sum = 0;
00557                 
00558                 for (int i = 0 ; i < nb_points() ; i++){
00559                         const Index& ind = get_point(i);
00560                         const Pixel  val = base::operator()(ind);
00561 
00562                         if (fabs(val) < epsilon) 
00563                                 sum += Globals::delta(val, epsilon) * Schemes::norm_gradient(*this, ind);
00564                 }
00565 
00566                 return sum;
00567         }
00568 }
00569 
00570 
00571 #endif  // LEVELSET_H

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