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
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
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
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
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
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
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
00268 if(tmp * base::operator()(ind) < 0)
00269 {
00270
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
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
00285 else i++;
00286 }
00287 }
00288
00289
00291
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
00306 m_mask(ind) = m_nbpts;
00307
00308
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
00322 m_mask(ind) = -1;
00323 m_nbpts--;
00324
00325
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
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
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
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
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
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
00466
00467
00468 template<unsigned DIM, typename Pixel>
00469 void LevelSet<DIM, Pixel>::reinit_PDE(int iter, float dt)
00470 {
00471
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