00001
00007 #ifndef FAST_MARCHING_H
00008 #define FAST_MARCHING_H
00009
00010 #include <algorithm>
00011 #include <limits>
00012
00013 #include <Image.H>
00014 #include <Globals.h>
00015 #include <PriorityQueue.h>
00016
00017 using namespace Images;
00018
00019 namespace levelset {
00020
00025 template<unsigned DIM, typename Pixel = float, int sign = +1>
00026 class FastMarching : public BaseImage<DIM, unsigned>
00027 {
00028 public:
00029
00030 typedef BaseImage<DIM, unsigned> base;
00031 typedef BaseImage<DIM, Pixel> ImageType;
00032 typedef typename base::Index Index;
00033 typedef PriorityQueue< Index > CoordQueue;
00034 typedef typename CoordQueue::QueuePosition QueuePosition;
00035 typedef BaseImage<DIM, QueuePosition> ImageQueuePosition;
00036
00038 typedef enum { eAlive=0, eTrial=1, eFar=2, eForbidden=3 } eState;
00039
00042
00044 FastMarching();
00046 FastMarching(ImageType *_phi);
00048 virtual ~FastMarching();
00049
00051 void init(ImageType & _phi);
00052
00054
00056
00058 unsigned nb_alive_points() const;
00060 const Index& get_alive_point(unsigned i);
00062 void add_alive_point(const Index& ind);
00064 void add_trial_point(const Index& ind);
00066 void add_forbidden_point(const Index& ind);
00068 void init_trial_from_alive();
00070 void clear();
00071
00073
00075
00077 void run();
00079 void run(Pixel _limit);
00080
00082
00084
00085 protected:
00086
00088 Pixel _get_value(const Index& ind) const;
00090 virtual Pixel _update_value(const Index& ind) const = 0;
00092 bool _solve_trinome(const Pixel a, const Pixel b, const Pixel c, Pixel &sol_max, Pixel &sol_min) const;
00093
00094 private:
00096 void __update_point(const Index& ind);
00097
00099
00101
00102 Index * m_alive_tab;
00103 unsigned m_nb_alive;
00104 CoordQueue m_trial_queue;
00105 ImageQueuePosition m_image_queue_position;
00106 protected:
00107 Pixel m_big;
00108 ImageType * m_phi;
00109
00110 };
00111
00112
00123 template <unsigned DIM, typename Pixel, int sign = +1>
00124 class Eikonal : public FastMarching<DIM, Pixel, sign>
00125 {
00126 public:
00127
00128 typedef FastMarching<DIM, Pixel, sign> base;
00129 typedef typename base::ImageType ImageType;
00130 typedef typename base::Index Index;
00131
00133 Eikonal();
00135 Eikonal(ImageType * _phi);
00137 virtual ~Eikonal() {}
00138
00140 void set_metric(ImageType * _metric);
00141
00142 protected:
00144 virtual Pixel _update_value(const Index& ind) const;
00146 Pixel _solve(const Index& ind, Pixel val[DIM]) const;
00147
00148 private:
00149
00150 ImageType * m_metric;
00151 };
00152
00153
00159
00160
00161
00162
00163 template<unsigned DIM, typename Pixel, int sign>
00164 FastMarching<DIM, Pixel, sign>::FastMarching()
00165 : base(), m_phi(NULL), m_alive_tab(NULL), m_nb_alive(0), m_trial_queue(), m_image_queue_position(), m_big(std::numeric_limits<Pixel>::max())
00166 { }
00167
00168 template<unsigned DIM, typename Pixel, int sign>
00169 FastMarching<DIM, Pixel, sign>::FastMarching(ImageType *_phi)
00170 : base(_phi->shape()), m_phi(_phi), m_nb_alive(0), m_trial_queue(), m_image_queue_position(_phi->shape()), m_big(std::numeric_limits<Pixel>::max())
00171 {
00172 m_alive_tab = new Index[base::size()];
00173 base::operator = (eFar);
00174 m_image_queue_position = QueuePosition();
00175 }
00176
00177 template<unsigned DIM, typename Pixel, int sign>
00178 FastMarching<DIM, Pixel, sign>::~FastMarching()
00179 {
00180 if (m_alive_tab != NULL) delete[] m_alive_tab;
00181 }
00182
00183 template<unsigned DIM, typename Pixel, int sign>
00184 void FastMarching<DIM, Pixel, sign>::init(ImageType & _phi)
00185 {
00186
00187 if (_phi.shape() != base::shape()){
00188
00189 base::resize(_phi.shape());
00190 m_image_queue_position.resize(_phi.shape());
00191
00192 if (m_alive_tab != NULL) delete[] m_alive_tab;
00193 m_alive_tab = new Index[base::size()];
00194 }
00195 clear();
00196 m_phi = &_phi;
00197 }
00198
00199
00201
00202
00203
00204 template<unsigned DIM, typename Pixel, int sign>
00205 unsigned FastMarching<DIM, Pixel, sign>::nb_alive_points() const
00206 {
00207 return m_nb_alive;
00208 }
00209
00210 template<unsigned DIM, typename Pixel, int sign>
00211 const typename FastMarching<DIM, Pixel, sign>::Index& FastMarching<DIM, Pixel, sign>::get_alive_point(unsigned i)
00212 {
00213 return m_alive_tab[i];
00214 }
00215
00216 template<unsigned DIM, typename Pixel, int sign>
00217 void FastMarching<DIM, Pixel, sign>::add_alive_point(const Index& ind)
00218 {
00219 if (base::operator()(ind) == eFar) {
00220 base::operator()(ind) = eAlive;
00221 m_alive_tab[m_nb_alive++] = ind;
00222 }
00223 }
00224
00225 template<unsigned DIM, typename Pixel, int sign>
00226 void FastMarching<DIM, Pixel, sign>::add_trial_point(const Index& ind)
00227 {
00228 if (base::operator()(ind) == eFar) {
00229 base::operator()(ind) = eTrial;
00230 m_image_queue_position(ind) = m_trial_queue.push(ind, sign*(*m_phi)(ind));
00231 }
00232 }
00233
00234 template<unsigned DIM, typename Pixel, int sign>
00235 void FastMarching<DIM, Pixel, sign>::add_forbidden_point(const Index& ind)
00236 {
00237 if (base::operator()(ind) == eFar) {
00238 base::operator()(ind) = eForbidden;
00239 }
00240 }
00241
00242 template<unsigned DIM, typename Pixel, int sign>
00243 void FastMarching<DIM, Pixel, sign>::init_trial_from_alive()
00244 {
00245
00246
00247 if (nb_alive_points() > 0){
00248 Index min_ind = get_alive_point(0);
00249 Pixel min_val = sign * (*m_phi)(min_ind);
00250
00251 for (unsigned int i = 0 ; i < nb_alive_points() ; i++)
00252 {
00253 const Index& ind = get_alive_point(i);
00254 Pixel val = sign * (*m_phi)(ind);
00255 if (val < min_val){
00256 min_ind = ind;
00257 min_val = val;
00258 }
00259 }
00260
00261
00262 m_trial_queue.push(min_ind, min_val);
00263 }
00264
00265
00266 for (unsigned int j = 0 ; j < nb_alive_points() ; j++)
00267 {
00268 const Index& ind = get_alive_point(j);
00269
00270 for (int i=1 ; i<=DIM ; i++){
00271 Index inf = ind;
00272 Index sup = ind;
00273 inf(i)--;
00274 sup(i)++;
00275
00276 if (sup(i)<m_phi->extent(i-1)) __update_point(sup);
00277 if (inf(i)>=0) __update_point(inf);
00278 }
00279 }
00280
00281
00282 if (nb_alive_points() > 0)
00283 m_trial_queue.pop();
00284 }
00285
00286 template<unsigned DIM, typename Pixel, int sign>
00287 void FastMarching<DIM, Pixel, sign>::clear()
00288 {
00289 m_nb_alive = 0;
00290 base::operator=(eFar);
00291 m_trial_queue.clear();
00292 m_image_queue_position = QueuePosition();
00293 }
00294
00295
00297
00298
00299
00300 template<unsigned DIM, typename Pixel, int sign>
00301 void FastMarching<DIM, Pixel, sign>::run()
00302 {
00303 run( (sign>0) ? m_big : -m_big );
00304 }
00305
00306 template<unsigned DIM, typename Pixel, int sign>
00307 void FastMarching<DIM, Pixel, sign>::run(Pixel _limit)
00308 {
00309
00310 while(!m_trial_queue.empty()) {
00311
00312
00313 Index ind = m_trial_queue.top();
00314
00315
00316 if (sign*(*m_phi)(ind)>=sign*_limit) {
00317
00318 while (!m_trial_queue.empty()) {
00319 ind = m_trial_queue.top();
00320 m_trial_queue.pop();
00321 base::operator()(ind) = eFar;
00322 m_image_queue_position(ind) = QueuePosition();
00323 (*m_phi)(ind) = _limit;
00324 }
00325 return;
00326 }
00327
00328
00329 for (int i=1 ; i<=DIM ; i++){
00330 Index inf = ind;
00331 Index sup = ind;
00332 inf(i)--;
00333 sup(i)++;
00334
00335 if (sup(i)<m_phi->extent(i-1)) __update_point(sup);
00336 if (inf(i)>=0) __update_point(inf);
00337 }
00338
00339
00340 m_trial_queue.pop();
00341 m_image_queue_position(ind) = QueuePosition();
00342 base::operator()(ind) = eAlive;
00343 m_alive_tab[m_nb_alive++] = ind;
00344 }
00345 }
00346
00347
00349
00350
00351
00352 template<unsigned DIM, typename Pixel, int sign>
00353 Pixel FastMarching<DIM, Pixel, sign>::_get_value(const Index& ind) const
00354 {
00355 if (base::operator()(ind) <= eTrial)
00356 return sign*(*m_phi)(ind);
00357 return m_big;
00358 }
00359
00360 template<unsigned DIM, typename Pixel, int sign>
00361 bool FastMarching<DIM, Pixel, sign>::_solve_trinome(const Pixel a, const Pixel b, const Pixel c, Pixel &sol_max, Pixel &sol_min) const
00362 {
00363 const Pixel delta = b*b - 4*a*c;
00364 if (delta < 0) return false;
00365 const Pixel sqrtDelta = std::sqrt(delta);
00366 sol_max = (- b + sqrtDelta) / a / 2;
00367 sol_min = (- b - sqrtDelta) / a / 2;
00368 return true;
00369 }
00370
00371 template<unsigned DIM, typename Pixel, int sign>
00372 void FastMarching<DIM, Pixel, sign>::__update_point(const Index& ind)
00373 {
00374 const unsigned st = base::operator()(ind);
00375 if (st == eFar) {
00376
00377 base::operator()(ind) = eTrial;
00378 const Pixel val = _update_value(ind);
00379 (*m_phi)(ind) = sign*val;
00380 m_image_queue_position(ind) = m_trial_queue.push(ind, val);
00381 }
00382 else if (st == eTrial) {
00383
00384 const Pixel val = _update_value(ind);
00385
00386 if (val<sign*(*m_phi)(ind)) {
00387
00388 m_image_queue_position(ind) = m_trial_queue.increase_priority(ind, m_image_queue_position(ind), val);
00389 (*m_phi)(ind) = sign*val;
00390 }
00391 }
00392 }
00393
00394
00396
00397
00398
00399 template<unsigned DIM, typename Pixel, int sign>
00400 Eikonal<DIM, Pixel, sign>::Eikonal()
00401 : base(), m_metric(NULL)
00402 { }
00403
00404 template<unsigned DIM, typename Pixel, int sign>
00405 Eikonal<DIM, Pixel, sign>::Eikonal(ImageType *_phi)
00406 : base(_phi), m_metric(NULL)
00407 { }
00408
00409 template<unsigned DIM, typename Pixel, int sign>
00410 void Eikonal<DIM, Pixel, sign>::set_metric(ImageType * _metric)
00411 {
00412 m_metric = _metric;
00413 }
00414
00415 template<unsigned DIM, typename Pixel, int sign>
00416 Pixel Eikonal<DIM, Pixel, sign>::_update_value(const Index& ind) const
00417 {
00418 Pixel val[DIM];
00419 for (int i=1 ; i<=DIM ; i++){
00420 Index inf = ind;
00421 Index sup = ind;
00422 inf(i)--;
00423 sup(i)++;
00424
00425 if (sup(i)>=base::extent(i-1)) val[i-1] = base::_get_value(inf);
00426 else if (inf(i)<0) val[i-1] = base::_get_value(sup);
00427 else val[i-1] = std::min(base::_get_value(inf), base::_get_value(sup));
00428 }
00429
00430 return _solve(ind,val);
00431 }
00432
00433 template<unsigned DIM, typename Pixel, int sign>
00434 Pixel Eikonal<DIM, Pixel, sign>::_solve(const Index& ind, Pixel val[DIM]) const
00435 {
00436
00437 std::sort(val, val+DIM);
00438
00439
00440 Pixel a[DIM];
00441 Pixel b[DIM];
00442 Pixel c[DIM];
00443
00444 a[0] = 1;
00445 b[0] = -2*val[0];
00446 c[0] = val[0]*val[0] - ((m_metric == NULL)?1:Maths::sqr((*m_metric)(ind)));
00447
00448 for (int i=1; i<DIM ; i++){
00449 a[i] = a[i-1] + 1;
00450 b[i] = b[i-1] - 2*val[i];
00451 c[i] = c[i-1] + val[i]*val[i];
00452 }
00453
00454
00455 Pixel sol_max, sol_min;
00456 for (int i=DIM-1 ; i>0 ; i--)
00457 if ((val[i]<base::m_big) && _solve_trinome(a[i], b[i], c[i], sol_max, sol_min) && sol_max+Globals::EPS>=val[i])
00458 return sol_max;
00459
00460 return val[0] + ((m_metric == NULL)? 1 : (*m_metric)(ind));
00461 }
00462 }
00463
00464
00465 #endif // FAST_MARCHING_H