/home/oan/prosjekt/gotools/segmentation/gpl_distro/lsseg_1.0_gpl/src/LevelSetFunction_reinitialize.C

Go to the documentation of this file.
00001 //===========================================================================
00002 // The Level-Set Segmentation Library (LSSEG)
00003 //
00004 //
00005 // Copyright (C) 2000-2005 SINTEF ICT, Applied Mathematics, Norway.
00006 //
00007 // This program is free software; you can redistribute it and/or          
00008 // modify it under the terms of the GNU General Public License            
00009 // as published by the Free Software Foundation version 2 of the License. 
00010 //
00011 // This program is distributed in the hope that it will be useful,        
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of         
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          
00014 // GNU General Public License for more details.                           
00015 //
00016 // You should have received a copy of the GNU General Public License      
00017 // along with this program; if not, write to the Free Software            
00018 // Foundation, Inc.,                                                      
00019 // 59 Temple Place - Suite 330,                                           
00020 // Boston, MA  02111-1307, USA.                                           
00021 //
00022 // Contact information: e-mail: tor.dokken@sintef.no                      
00023 // SINTEF ICT, Department of Applied Mathematics,                         
00024 // P.O. Box 124 Blindern,                                                 
00025 // 0314 Oslo, Norway.                                                     
00026 // 
00027 //
00028 // Other licenses are also available for this software, notably licenses
00029 // for:
00030 // - Building commercial software.                                        
00031 // - Building software whose source code you wish to keep private.        
00032 //
00033 //===========================================================================
00034 //===========================================================================
00035 //                                                                           
00036 // File: LevelSetFunction_reinitialize.C                                     
00037 //                                                                           
00038 // Created: Mon Feb 20 11:50:38 2006                                         
00039 //                                                                           
00040 // Author: Odd A. Andersen <Odd.Andersen@sintef.no>
00041 //                                                                           
00042 // Revision: $Id: LevelSetFunction_reinitialize.C,v 1.9 2006/11/22 15:23:00 oan Exp $
00043 //                                                                           
00044 // Description:
00049 //                                                                           
00050 //===========================================================================
00051 
00052 #include <map>
00053 #include <set>
00054 #include <vector>
00055 #include <limits>
00056 #include <stdexcept>
00057 #include "Image.h"
00058 #include "LevelSetFunction.h"
00059 #include "Mask.h"
00060 #include "cimg_dependent.h" // @@ for debug purposes
00061 #include <iostream> // @@ for debug purposes
00062 
00063 // UNDEF_VAL should be LARGER than any number that we can expect from the
00064 // computations.  It should under NO CIRCUMSTANCES be negative.
00065 
00066 const double UNDEF_VAL = 100000; 
00067 
00068 using namespace std;
00069 using namespace lsseg;
00070 using namespace boost;
00071 
00072 namespace { // anonymous namespace
00073 
00074 
00075 //typedef tuple<int, int> Coord2D;
00076 //typedef tuple<int, int, int> Coord3D;
00077 //===========================================================================
00078 struct Coord2D
00079 //===========================================================================
00080 {
00081     Coord2D(int x, int y) : x_(x), y_(y) {}
00082     template<int I> const int& get() const ;
00083 
00084     int x_, y_;
00085 };
00086 inline bool operator<(const Coord2D& c1, const Coord2D& c2) { 
00087     if (c1.y_ != c2.y_) 
00088         return (c1.y_ < c2.y_); 
00089     return (c1.x_ < c2.x_); 
00090 }
00091 inline bool operator==(const Coord2D& c1, const Coord2D& c2) {
00092     return (c1.x_ == c2.x_) && (c1.y_ == c2.y_);
00093 }
00094 template<> const int& Coord2D::get<0>() const {return x_;}
00095 template<> const int& Coord2D::get<1>() const {return y_;}
00096 
00097 template<size_t MUL>
00098 class HashCoord2D
00099 {
00100 public:
00101     size_t operator()(const Coord2D& c) const {return c.y_ * MUL + c.x_;}
00102 };
00103 
00104 //===========================================================================
00105 struct Coord3D
00106 //===========================================================================
00107 {
00108     Coord3D(int x, int y, int z) : x_(x), y_(y), z_(z) {}
00109     template<int I> const int& get() const ;
00110 
00111     int x_, y_, z_;
00112 };
00113 inline bool operator<(const Coord3D& c1, const Coord3D& c2) {
00114     if (c1.z_ != c2.z_) return (c1.z_ < c2.z_); 
00115     if (c1.y_ != c2.y_) return (c1.y_ < c2.y_);
00116     return (c1.x_ < c2.x_);
00117 }
00118 
00119 inline bool operator==(const Coord3D& c1, const Coord3D& c2) {
00120     return (c1.x_ == c2.x_) && (c1.y_ == c2.y_) && (c1.z_ == c2.z_);
00121 }
00122 
00123 template<> const int& Coord3D::get<0>() const {return x_;}
00124 template<> const int& Coord3D::get<1>() const {return y_;}
00125 template<> const int& Coord3D::get<2>() const {return z_;}
00126 
00127 template<size_t MUL>
00128 class HashCoord3D
00129 {
00130 public:
00131     size_t operator()(const Coord3D& c) const {return c.x_ + MUL * (c.y_ + MUL * c.z_);}
00132 };
00133 
00134 const size_t MAX_ANTICIPATED_RES=10000;
00135 typedef multimap<double, Coord2D > dist_map_2D; // sparse distance map in 2D
00136 typedef multimap<double, Coord3D > dist_map_3D; // sparse distance map in 3D
00137 typedef map<Coord2D, dist_map_2D::iterator> coord_map_2D; // inverse of dist_map_2D
00138 typedef map<Coord3D, dist_map_3D::iterator> coord_map_3D; // inverse of dist_map_3D
00139 
00140 
00141 void init_zero_level_interface_2D(const LevelSetFunction&, LevelSetFunction&, const Mask* m);
00142 void init_zero_level_interface_3D(const LevelSetFunction&, LevelSetFunction&, const Mask* m);
00143     
00144 void init_tentative_values_2D(const LevelSetFunction&, dist_map_2D&, dist_map_2D&, const Mask* m);
00145 void init_tentative_values_3D(const LevelSetFunction&, dist_map_3D&, dist_map_3D&, const Mask* m);
00146 
00147 double compute_dist_estimate_2D(const double x1, const double x2, 
00148                                 const double y1, const double y2);
00149 double compute_dist_estimate_3D(const double x1, const double x2, 
00150                                 const double y1, const double y2, 
00151                                 const double z1, const double z2);
00152 
00153 void march_out_2D(dist_map_2D& tentatives, 
00154                   coord_map_2D& inv_tent, 
00155                   LevelSetFunction& target,
00156                   const Mask* m,
00157                   bool negative);
00158 void march_out_3D(dist_map_3D& tentatives, 
00159                   coord_map_3D& inv_tent, 
00160                   LevelSetFunction& target,
00161                   const Mask* m,
00162                   bool negative);
00163 inline double distance_poly(double d1, double d2);
00164 inline double distance_poly(double d1, double d2, double d3);
00165 }; // end anonymous namespace
00166 
00167 namespace lsseg {
00168 
00169 //===========================================================================
00170 void LevelSetFunction::reinitialize2D(const Mask* m)
00171 //===========================================================================
00172 {
00173     // for the moment, this routine uses a first-order accurate fast marching
00174     // method.  (A different approach could be the reinitialization equation
00175     // using a higher-order HJ WENO scheme). 
00176 
00177     MESSAGE_IF(dimz() > 1, "Warning: applying 2D method on a grid with dim(z) > 1");
00178     assert(!m || size_compatible(*m));
00179 
00180     // detecting zero-level interface and computing neighbour distance values
00181     // (1-band)
00182 
00183     static LevelSetFunction res; // made static because memory allocation is expensive,
00184                                  // and this function is typically called (very) frequently!
00185     res.resize(*this);
00186     res = UNDEF_VAL;
00187 
00188     init_zero_level_interface_2D(*this, res, m);
00189 
00190     // initializing tentative values (those that have a defined neighbour while themselves 
00191     // being undefined)
00192     dist_map_2D pos_tentatives, neg_tentatives;
00193     coord_map_2D pos_tent_inv, neg_tent_inv;
00194     init_tentative_values_2D(res, pos_tentatives, neg_tentatives, m);
00195     
00196     // computing inverse maps  (there might be a more efficient way of carrying
00197     // out the task solved by these maps, possible optimization @@)
00198     for (dist_map_2D::iterator it = pos_tentatives.begin(); it != pos_tentatives.end(); ++it) {
00199         pos_tent_inv[it->second] = it;
00200     }
00201     for (dist_map_2D::iterator it = neg_tentatives.begin(); it != neg_tentatives.end(); ++it) {
00202         neg_tent_inv[it->second] = it;
00203     }
00204 
00205     // growing outwards
00206     march_out_2D(pos_tentatives, pos_tent_inv, res, m, false);
00207     // growing inwards
00208     march_out_2D(neg_tentatives, neg_tent_inv, res, m, true);
00209 
00210     assert(pos_tentatives.empty());
00211     assert(neg_tentatives.empty());
00212     assert(pos_tent_inv.empty());
00213     assert(neg_tent_inv.empty());
00214     
00215     if (!m) { // res has been updated everywhere, and we can just swap it
00216         swap(res);
00217     } else {
00218         // copying the defined values, leaving the rest as it is
00219         const double* res_pt = res.begin();
00220         const char* mask_pt = m->begin();
00221         for (double* phi_pt = begin(); phi_pt != end(); ++phi_pt, ++res_pt, ++mask_pt) {
00222             if (*mask_pt) {
00223                 if (*res_pt != UNDEF_VAL) {
00224                     *phi_pt = *res_pt;
00225                 } else {
00226                     // this part has not been reached by the marching alrogithm.  It must
00227                     // be separated from the interface by the mask (the whole area it 
00228                     // belongs to has the same sign
00229                     *phi_pt = (*phi_pt > 0) ? 1: -1;
00230                 }
00231             }
00232         }
00233     }
00234 }
00235 
00236 //===========================================================================
00237 void LevelSetFunction::reinitialize3D(const Mask* m)
00238 //===========================================================================
00239 {
00240     // for the moment, this routine uses a first-order accurate fast marching
00241     // method.  (A different approach could be the reinitialization equation
00242     // using a higher-order HJ WENO scheme). 
00243     assert(!m || size_compatible(*m));
00244 
00245     if (dimz() == 1) {
00246         return reinitialize2D(m); // not necessary to call the 3D routine
00247     }
00248 
00249     // detecting zero-level interface and computing neighbour distance values
00250     // (1-band)
00251 
00252     static LevelSetFunction res; // made static because memory allocation is expensive,
00253                                  // and this function is typically called (very) frequently!
00254     res.resize(*this);
00255     res = UNDEF_VAL;
00256     init_zero_level_interface_3D(*this, res, m);
00257 
00258     // initializing tentative values (those that have a defined neighbour while themselves 
00259     // being undefined)
00260     dist_map_3D pos_tentatives, neg_tentatives;
00261     coord_map_3D pos_tent_inv, neg_tent_inv;
00262     init_tentative_values_3D(res, pos_tentatives, neg_tentatives, m);
00263     
00264     // computing inverse maps  (there might be a more efficient way of carrying
00265     // out the task solved by these maps, possible optimization @@)
00266     for (dist_map_3D::iterator it = pos_tentatives.begin(); it != pos_tentatives.end(); ++it) {
00267         pos_tent_inv[it->second] = it;
00268     }
00269     for (dist_map_3D::iterator it = neg_tentatives.begin(); it != neg_tentatives.end(); ++it) {
00270         neg_tent_inv[it->second] = it;
00271     }
00272 
00273     // growing outwards
00274     march_out_3D(pos_tentatives, pos_tent_inv, res, m, false);
00275     // growing inwards
00276     march_out_3D(neg_tentatives, neg_tent_inv, res, m, true);
00277 
00278     assert(pos_tentatives.empty());
00279     assert(neg_tentatives.empty());
00280     assert(pos_tent_inv.empty());
00281     assert(neg_tent_inv.empty());
00282     
00283     if (!m) { // res has been updated everywhere, and we can just swap it
00284         swap(res);
00285     } else {
00286         // copying the defined values, leaving the rest as it is
00287         double* res_pt = res.begin();
00288         for (double* phi_pt = begin(); phi_pt != end(); ++phi_pt, ++res_pt) {
00289             if (*res_pt != UNDEF_VAL) {
00290                 *phi_pt = *res_pt;
00291             }
00292         }
00293     }
00294 }
00295 
00296 
00297 }; // end anonymous namespace
00298 
00299 namespace { // anonymous namespace
00300 
00301 //===========================================================================
00302 void init_zero_level_interface_2D(const lsseg::LevelSetFunction& src, 
00303                                   lsseg::LevelSetFunction& trg,
00304                                   const Mask* m)
00305 //===========================================================================
00306 {
00307     // @@ NB: Mask not taken into consideration when checking for a sign change.
00308     //    It seems to work OK though, and it saves some checks, but this might
00309     //    have to be rewritten.
00310     const double EPS = 1.0e-10;
00311     const int X = src.dimx();
00312     const int Y = src.dimy();
00313     vector<double> scratch(4);
00314     trg.resize(src);
00315     size_t mask_it = 0;
00316     for (int y = 0; y < Y; ++y) {
00317         for (int x = 0; x < X; ++x) {
00318             if (m && !(*m)[mask_it++]) {
00319                 continue; // outside mask
00320             }
00321             scratch.clear();
00322             const double cur = src(x, y);
00323             if (cur == 0.0) { // necessary when a pixel is found to be EXACTLY on the interface
00324                 trg(x, y) = 0;
00325                 continue;
00326             }
00327             // we know now that cur is not exactly zero and thus MUST have a sign
00328             if (x > 0 && cur * src(x - 1, y) <= 0) {
00329                 // estimating position of interface by linear interpolation
00330                 const double neigh = src(x - 1, y);
00331                 const double val = cur / (cur - neigh);
00332                 assert (val >= 0 && val <= 1);
00333                 scratch.push_back((val > EPS) ? val : EPS);
00334             }
00335             if (x < X - 1 && cur * src(x + 1, y) <= 0) {
00336                 // estimating position of interface by linear interpolation
00337                 const double neigh = src(x + 1, y);
00338                 const double val = cur / (cur - neigh);
00339                 assert (val >= 0 && val <= 1);
00340                 scratch.push_back((val > EPS) ? val : EPS);
00341             }
00342             if (y > 0 && cur * src(x, y - 1) <= 0) {
00343                 // estimating position of interface by linear interpolation
00344                 const double neigh = src(x, y - 1);
00345                 const double val = cur / (cur - neigh);
00346                 assert (val >= 0 && val <= 1);
00347                 scratch.push_back((val > EPS) ? val : EPS);
00348             }
00349             if (y < Y - 1 && cur * src(x, y + 1) <= 0 ) {
00350                 // estimating position of interface by linear interpolation
00351                 const double neigh = src(x, y + 1);
00352                 const double val = cur / (cur - neigh);
00353                 assert (val >= 0 && val <= 1);
00354                 scratch.push_back((val > EPS) ? val : EPS);
00355             }
00356             if (!scratch.empty()) {
00357                 trg(x, y) = *min_element(scratch.begin(), scratch.end());
00358                 if (cur < 0) {
00359                     trg(x, y) *= -1;
00360                 }
00361             }
00362         }
00363     }
00364 }
00365 
00366 //===========================================================================
00367 void init_zero_level_interface_3D(const lsseg::LevelSetFunction& src, 
00368                                   lsseg::LevelSetFunction& trg,
00369                                   const Mask* m)
00370 //===========================================================================
00371 {
00372     const double EPS = 1.0e-10;
00373     const int X = src.dimx();
00374     const int Y = src.dimy();
00375     const int Z = src.dimz();
00376     vector<double> scratch(6);
00377     trg.resize(src);
00378     size_t mask_it = 0;
00379     for (int z = 0; z < Z; ++z) {
00380         for (int y = 0; y < Y; ++y) {
00381             for (int x = 0; x < X; ++x) {
00382                 if (m && !(*m)[mask_it++]) {
00383                     continue; // outside mask
00384                 }
00385                 scratch.clear();
00386                 const double cur = src(x, y, z);
00387                 if (cur == 0.0) { // necessary when a pixel is found to be EXACTLY on the interface
00388                     trg(x, y, z) = 0;
00389                     continue;
00390                 }
00391                 // we know now that cur is not exactly zero and thus MUST have a sign
00392                 if (x > 0 && cur * src(x - 1, y, z) <= 0) {
00393                     // estimating position of interface by linear interpolation
00394                     const double neigh = src(x - 1, y, z);
00395                     const double val = cur / (cur - neigh);
00396                     assert (val >= 0 && val <= 1);
00397                     scratch.push_back((val > EPS) ? val : EPS);
00398                 }
00399                 if (x < X - 1 && cur * src(x + 1, y, z) <= 0) {
00400                     // estimating position of interface by linear interpolation
00401                     const double neigh = src(x + 1, y, z);
00402                     const double val = cur / (cur - neigh);
00403                     assert (val >= 0 && val <= 1);
00404                     scratch.push_back((val > EPS) ? val : EPS);
00405                 }
00406                 if (y > 0 && cur * src(x, y - 1, z) <= 0) {
00407                     // estimating position of interface by linear interpolation
00408                     const double neigh = src(x, y - 1, z);
00409                     const double val = cur / (cur - neigh);
00410                     assert (val >= 0 && val <= 1);
00411                     scratch.push_back((val > EPS) ? val : EPS);
00412                 }
00413                 if (y < Y - 1 && cur * src(x, y + 1, z) <= 0 ) {
00414                     // estimating position of interface by linear interpolation
00415                     const double neigh = src(x, y + 1, z);
00416                     const double val = cur / (cur - neigh);
00417                     assert (val >= 0 && val <= 1);
00418                     scratch.push_back((val > EPS) ? val : EPS);
00419                 }
00420                 if (z > 0 && cur * src(x, y ,z - 1) <= 0) {
00421                     // estimating position of interface by linear interpolation
00422                     const double neigh = src(x, y, z - 1);
00423                     const double val = cur / (cur - neigh);
00424                     assert(val >= 0 && val <= 1);
00425                     scratch.push_back((val > EPS) ? val : EPS);
00426                 }
00427                 if (z < Z - 1 && cur * src(x, y, z + 1) <= 0) {
00428                     // estimating position of interface by linear interpolation
00429                     const double neigh = src(x, y, z+1);
00430                     const double val = cur / (cur - neigh);
00431                     assert(val >= 0 && val <= 1);
00432                     scratch.push_back((val > EPS) ? val : EPS);
00433                 }
00434                 if (!scratch.empty()) {
00435                     trg(x, y, z) = *min_element(scratch.begin(), scratch.end());
00436                     if (cur < 0) {
00437                         trg(x, y, z) *= -1;
00438                     }
00439                 }
00440             }
00441         }
00442     }
00443 }
00444 
00445 //===========================================================================
00446 void init_tentative_values_2D(const lsseg::LevelSetFunction& phi, 
00447                               dist_map_2D& positive_map,
00448                               dist_map_2D& negative_map, 
00449                               const Mask* m)
00450 //===========================================================================
00451 {
00452     positive_map.clear();
00453     negative_map.clear();
00454     const int X = phi.dimx();
00455     const int Y = phi.dimy();
00456 
00457     // mapping all coordinate pair that are undefined but having a defined neighbour
00458     set<Coord2D > candidates;
00459     if (!m) { // no mask
00460         for (int y = 0; y < Y; ++y) {
00461             for (int x = 0; x < X; ++x) {
00462                 if (phi(x, y) != UNDEF_VAL) {
00463                     // checking neighbours
00464                     if (x > 0 && phi(x-1, y) == UNDEF_VAL) {
00465                         candidates.insert(Coord2D(x-1, y));
00466                     }
00467                     if (x < X-1 && phi(x+1, y) == UNDEF_VAL) {
00468                         candidates.insert(Coord2D(x+1, y));
00469                     }
00470                     if (y > 0 && phi(x, y-1) == UNDEF_VAL) {
00471                         candidates.insert(Coord2D(x, y-1));
00472                     }
00473                     if (y < Y-1 && phi(x, y+1) == UNDEF_VAL) {
00474                         candidates.insert(Coord2D(x, y+1));
00475                     }
00476                 }
00477             }
00478         }
00479     } else { // mask is present
00480         size_t mask_it = 0;
00481         for (int y = 0; y < Y; ++y) {
00482             for (int x = 0; x < X; ++x) {
00483                 if ((*m)[mask_it++]) {
00484                     if (phi(x, y) != UNDEF_VAL) {
00485                         // checking neighbours
00486                         if (x > 0 && phi(x-1, y) == UNDEF_VAL && (*m)(x-1, y)) {
00487                             candidates.insert(Coord2D(x-1, y));
00488                         }
00489                         if (x < X-1 && phi(x+1, y) == UNDEF_VAL && (*m)(x+1, y)) {
00490                             candidates.insert(Coord2D(x+1, y));
00491                         }
00492                         if (y > 0 && phi(x, y-1) == UNDEF_VAL && (*m)(x, y-1)) {
00493                             candidates.insert(Coord2D(x, y-1));
00494                         }
00495                         if (y < Y-1 && phi(x, y+1) == UNDEF_VAL && (*m)(x, y+1)) {
00496                             candidates.insert(Coord2D(x, y+1));
00497                         }
00498                     }
00499                 }
00500             }
00501         }
00502     }
00503 
00504     // looping through candidates and computing their distance to the interface
00505     set<Coord2D >::const_iterator it;
00506     double l, r, b, t; // left, right, bottom, top...
00507     for (it = candidates.begin(); it != candidates.end(); ++it) {
00508         const int x = it->get<0>();
00509         const int y = it->get<1>();
00510         l = (x > 0)   ? phi(x-1, y) : UNDEF_VAL;
00511         r = (x < X-1) ? phi(x+1, y) : UNDEF_VAL;
00512         b = (y > 0)   ? phi(x, y-1) : UNDEF_VAL;
00513         t = (y < Y-1) ? phi(x, y+1) : UNDEF_VAL;
00514 
00515         double estimate = compute_dist_estimate_2D(l, r, b, t);
00516 
00517         if (estimate > 0) {
00518             positive_map.insert(pair<double, Coord2D >(estimate, *it)); 
00519         } else {
00520             negative_map.insert(pair<double, Coord2D >(estimate, *it)); 
00521         }       
00522     }
00523 }
00524 
00525 //===========================================================================
00526 void init_tentative_values_3D(const lsseg::LevelSetFunction& phi, 
00527                               dist_map_3D& positive_map,
00528                               dist_map_3D& negative_map, 
00529                               const Mask* m)
00530 //===========================================================================
00531 {
00532     positive_map.clear();
00533     negative_map.clear();
00534     const int X = phi.dimx();
00535     const int Y = phi.dimy();
00536     const int Z = phi.dimz();
00537 
00538     // mapping all coordinate pair that are undefined but having a defined neighbour
00539     set<Coord3D > candidates;
00540     if (!m) { // no mask
00541         for (int z = 0; z < Z; ++z) {
00542             for (int y = 0; y < Y; ++y) {
00543                 for (int x = 0; x < X; ++x) {
00544                     if (phi(x, y, z) != UNDEF_VAL) {
00545                         // checking neighbours
00546                         if (x > 0 && phi(x-1, y, z) == UNDEF_VAL) {
00547                             candidates.insert(Coord3D(x-1, y, z));
00548                         }
00549                         if (x < X-1 && phi(x+1, y, z) == UNDEF_VAL) {
00550                             candidates.insert(Coord3D(x+1, y, z));
00551                         }
00552                         if (y > 0 && phi(x, y-1, z) == UNDEF_VAL) {
00553                             candidates.insert(Coord3D(x, y-1, z));
00554                         }
00555                         if (y < Y-1 && phi(x, y+1, z) == UNDEF_VAL) {
00556                             candidates.insert(Coord3D(x, y+1, z));
00557                         }
00558                         if (z > 0 && phi(x, y, z-1) == UNDEF_VAL) {
00559                             candidates.insert(Coord3D(x, y, z-1));
00560                         }
00561                         if (z < Z-1 && phi(x, y, z+1) == UNDEF_VAL) {
00562                             candidates.insert(Coord3D(x, y, z+1));
00563                         }
00564                     }
00565                 }
00566             }
00567         }
00568     } else { // mask is present
00569         size_t mask_it = 0;
00570         for (int z = 0; z < Z; ++z) {
00571             for (int y = 0; y < Y; ++y) {
00572                 for (int x = 0; x < X; ++x) {
00573                     if ((*m)[mask_it++]) {
00574                         if (phi(x, y, z) != UNDEF_VAL) {
00575                             // checking neighbours
00576                             if (x > 0 && phi(x-1, y, z) == UNDEF_VAL && (*m)(x-1, y, z)) {
00577                                 candidates.insert(Coord3D(x-1, y, z));
00578                             }
00579                             if (x < X-1 && phi(x+1, y, z) == UNDEF_VAL && (*m)(x+1, y, z)) {
00580                                 candidates.insert(Coord3D(x+1, y, z));
00581                             }
00582                             if (y > 0 && phi(x, y-1, z) == UNDEF_VAL && (*m)(x, y-1, z)) {
00583                                 candidates.insert(Coord3D(x, y-1, z));
00584                             }
00585                             if (y < Y-1 && phi(x, y+1, z) == UNDEF_VAL && (*m)(x, y+1, z)) {
00586                                 candidates.insert(Coord3D(x, y+1, z));
00587                             }
00588                             if (z > 0 && phi(x, y, z-1) == UNDEF_VAL && (*m)(x, y, z-1)) {
00589                                 candidates.insert(Coord3D(x, y, z-1));
00590                             }
00591                             if (z < Z-1 && phi(x, y, z+1) == UNDEF_VAL && (*m)(x, y, z+1)) {
00592                                 candidates.insert(Coord3D(x, y, z+1));
00593                             }
00594                         }
00595                     }
00596                 }
00597             }
00598         }
00599     }
00600 
00601     // looping through candidates and computing their distance to the interface
00602     set<Coord3D >::const_iterator it;
00603     double l, r, f, b, u, d; // left, right, front, back, up, down
00604     for (it = candidates.begin(); it != candidates.end(); ++it) {
00605         const int x = it->get<0>();
00606         const int y = it->get<1>();
00607         const int z = it->get<2>();
00608         l = (x > 0) ? phi(x-1, y, z) : UNDEF_VAL;
00609         r = (x < X-1) ? phi(x+1, y, z) : UNDEF_VAL;
00610         f = (y > 0) ? phi(x, y-1, z) : UNDEF_VAL;
00611         b = (y < Y-1) ? phi(x, y+1, z) : UNDEF_VAL;
00612         u = (z > 0) ? phi(x, y, z-1) : UNDEF_VAL;
00613         d = (z < Z-1) ? phi(x, y, z+1) : UNDEF_VAL;
00614 
00615         double estimate = compute_dist_estimate_3D(l, r, f, b, u, d);
00616 
00617         if (estimate > 0) {
00618             positive_map.insert(pair<double, Coord3D >(estimate, *it)); 
00619         } else {
00620             negative_map.insert(pair<double, Coord3D >(estimate, *it)); 
00621         }       
00622     }
00623 }
00624 
00625 //===========================================================================
00626 double compute_dist_estimate_2D(const double x1, const double x2,
00627                                 const double y1, const double y2)
00628 //===========================================================================
00629 {
00630     assert(x1 * x2 >= 0 || (x1 == UNDEF_VAL || x2 == UNDEF_VAL));
00631     assert(y1 * y2 >= 0 || (y1 == UNDEF_VAL || y2 == UNDEF_VAL)); // should have same sign
00632     assert(x1 * y1 >= 0 || (x1 == UNDEF_VAL || y1 == UNDEF_VAL)); // should have same sign
00633 
00634     const double fac = (x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0) ? -1 : 1; // sign
00635     const double x_min = fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2);
00636     const double y_min = fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2);
00637 
00638     if (x_min == UNDEF_VAL) {
00639         assert (y_min != UNDEF_VAL);
00640         return fac * (y_min + 1);
00641     } 
00642     if (y_min == UNDEF_VAL) {
00643         assert (x_min != UNDEF_VAL);
00644         return fac * (x_min + 1);
00645     }
00646 
00647     // both x_min and y_min have defined values, we have to solve a quadratic
00648     // equation with a non-zero discriminant  (ref. book "Level Set Methods and 
00649     // Dynamic Implicit Surfaces" (Osher/Sethian), page 73.)
00650 
00651     // no numerical trouble, proceed with resolution of quadratic equation
00652     return fac * distance_poly(x_min, y_min);
00653 }
00654 
00655 //===========================================================================
00656 double compute_dist_estimate_3D(const double x1, const double x2,
00657                                 const double y1, const double y2,
00658                                 const double z1, const double z2)
00659 //===========================================================================
00660 {
00661     assert(x1 * x2 >= 0 || (x1 == UNDEF_VAL || x2 == UNDEF_VAL));
00662     assert(y1 * y2 >= 0 || (y1 == UNDEF_VAL || y2 == UNDEF_VAL)); // should have same sign
00663     assert(z1 * z2 >= 0 || (z1 == UNDEF_VAL || z2 == UNDEF_VAL));
00664     assert(x1 * y1 >= 0 || (x1 == UNDEF_VAL || y1 == UNDEF_VAL)); // should have same sign
00665     assert(x1 * z1 >= 0 || (x1 == UNDEF_VAL || z1 == UNDEF_VAL));
00666 
00667     const double fac = 
00668         (x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0 || z1 < 0 || z2 < 0) ? -1 : 1; // sign
00669 
00670     const double x_min = fabs(x1) < fabs(x2) ? fabs(x1) : fabs(x2);
00671     const double y_min = fabs(y1) < fabs(y2) ? fabs(y1) : fabs(y2);
00672     const double z_min = fabs(z1) < fabs(z2) ? fabs(z1) : fabs(z2); 
00673 
00674     // for an explanation of the below, read the text in the book
00675     // "Level Set Methods and Dynamic Implicit Surfaces" by Osher/Sethian, page 73.
00676 
00677     if (y_min == UNDEF_VAL && z_min == UNDEF_VAL) {
00678         assert(x_min != UNDEF_VAL);
00679         return fac * (x_min + 1);
00680     } else if (x_min == UNDEF_VAL && z_min == UNDEF_VAL) {
00681         assert(y_min != UNDEF_VAL);
00682         return fac * (y_min + 1);
00683     } else if (x_min == UNDEF_VAL && y_min == UNDEF_VAL) {
00684         assert(z_min != UNDEF_VAL);
00685         return fac * (z_min + 1);
00686     } else if (x_min == UNDEF_VAL) {
00687         assert(y_min != UNDEF_VAL && z_min != UNDEF_VAL);
00688         return fac * distance_poly(y_min, z_min); 
00689     } else if (y_min == UNDEF_VAL) {
00690         assert(x_min != UNDEF_VAL && z_min != UNDEF_VAL);
00691         return fac * distance_poly(x_min, z_min);
00692     } else if (z_min == UNDEF_VAL) {
00693         assert(x_min != UNDEF_VAL && y_min != UNDEF_VAL);
00694         return fac * distance_poly(x_min, y_min);
00695     } 
00696 
00697     // if we got here, then x_min, y_min and z_min should all be defined.
00698     return fac * distance_poly(x_min, y_min, z_min);
00699 }
00700 
00701 //===========================================================================
00702 double distance_poly(double d1, double d2)
00703 //===========================================================================
00704 {
00705     // consistency check
00706     double ccheck = fabs(d1 - d2);
00707     if (ccheck > 1) {
00708         // numerical trouble, resort to "backup" solution, which is
00709         // the smallest distance + 1 (which is considered pixel distance)
00710         return d1 < d2 ? (d1 + 1) : (d2 + 1);
00711     }
00712 
00713     const double b = -2 * (d1 + d2);
00714     const double c = (d1 * d1) + (d2 * d2) - 1;
00715     const double discriminant = b * b - 8 * c;
00716     assert(discriminant >= 0); // should be assured before calling this function
00717     return 0.25 * (-b + sqrt(discriminant));
00718 }
00719 
00720 
00721 //===========================================================================
00722 double distance_poly(double d1, double d2, double d3)
00723 //===========================================================================
00724 {
00725     // bubble-sorting d1, d2 and d3 according to increasing value
00726     if (d1 > d2) swap(d1, d2);
00727     if (d2 > d3) swap(d2, d3);
00728     if (d1 > d2) swap(d1, d2);
00729     assert(d1 <= d2 && d2 <= d3);
00730 
00731     // consistency check
00732     const double tmp1 = d3 - d1;
00733     const double tmp2 = d3 - d2;
00734     const double ccheck = (tmp1 * tmp1) + (tmp2 * tmp2);
00735     if (ccheck > 1) {
00736         // try solving poly with two variables
00737         return distance_poly(d1, d2);
00738     } 
00739     
00740     const double six_inv = double(1) / double(6);
00741     // (a is equal to 3, but this is hardcoded into the solution)
00742     const double b = -2 * (d1 + d2 + d3);
00743     const double c = (d1 * d1) + (d2 * d2) + (d3 * d3) - 1;
00744     const double discriminant = (b * b - 12 * c);
00745     assert(discriminant >= 0); // should be assured before calling this function
00746     return six_inv * (-b + sqrt(discriminant));
00747 }
00748 
00749 
00750 //===========================================================================
00751 void march_out_2D(dist_map_2D& tentatives, 
00752                   coord_map_2D& inv_tent, 
00753                   lsseg::LevelSetFunction& target, 
00754                   const Mask* m,
00755                   bool negative)
00756 //===========================================================================
00757 {
00758     const int X = target.dimx();
00759     const int Y = target.dimy();
00760     
00761     dist_map_2D::iterator tmp_it, cur_it;
00762     coord_map_2D::iterator c_it;
00763     
00764     double l, r, b, t; // left, right, bottom, top, ...
00765 
00766     while (!tentatives.empty()) {
00767         if (negative) {
00768             cur_it = tentatives.end();
00769             --cur_it;
00770         } else {
00771             cur_it = tentatives.begin();
00772         }
00773 
00774         const int x = cur_it->second.get<0>();
00775         const int y = cur_it->second.get<1>();
00776         target(x, y) = cur_it->first;
00777         
00778         // updating neighbours
00779         if (x > 0 && target(x-1, y) == UNDEF_VAL && (!m || (*m)(x-1, y))) {  // value to the left of current
00780             r = cur_it->first;
00781             l = (x > 1) ? target(x-2, y) : UNDEF_VAL;
00782             b = (y > 0) ? target(x-1, y-1) : UNDEF_VAL;
00783             t = (y < Y-1) ? target(x-1, y+1) : UNDEF_VAL;
00784             const double dist = compute_dist_estimate_2D(l, r, b, t);
00785             const Coord2D xy(x-1, y);
00786             c_it = inv_tent.find(xy);
00787             if (c_it != inv_tent.end()) {
00788                 tentatives.erase(c_it->second);
00789             }
00790             tmp_it = tentatives.insert(pair<double, Coord2D >( dist, xy));
00791             inv_tent[xy]= tmp_it;
00792         }
00793         if (x < X-1 && target(x+1, y) == UNDEF_VAL && (!m || (*m)(x+1, y))) { // value to the right of current
00794             r = (x < X-2) ? target(x+2, y) : UNDEF_VAL;
00795             l = cur_it->first;
00796             b = (y > 0) ? target(x+1,y-1) : UNDEF_VAL;
00797             t = (y < Y-1) ? target(x+1, y+1) : UNDEF_VAL;
00798             const double dist = compute_dist_estimate_2D(l, r, b, t);
00799             const Coord2D xy(x+1, y);
00800             c_it = inv_tent.find(xy);
00801             if (c_it != inv_tent.end()) {
00802                 tentatives.erase(c_it->second);
00803             }
00804             tmp_it = tentatives.insert(pair<double, Coord2D >(dist,xy));
00805             inv_tent[xy] = tmp_it;
00806         }
00807         if (y > 0 && target(x, y-1) == UNDEF_VAL && (!m || (*m)(x, y-1))) { // value on the bottom of current
00808             r = (x < X-1) ? target(x+1, y-1) : UNDEF_VAL;
00809             l = (x > 0) ? target(x-1, y-1) : UNDEF_VAL;
00810             b = (y > 1) ? target(x, y-2) : UNDEF_VAL;
00811             t = cur_it->first;
00812             const double dist = compute_dist_estimate_2D(l, r, b, t);
00813             const Coord2D xy(x, y-1);
00814             c_it = inv_tent.find(xy);
00815             if (c_it != inv_tent.end()) {
00816                 tentatives.erase(c_it->second);
00817             }
00818             tmp_it = tentatives.insert(pair<double, Coord2D >(dist, xy));
00819             inv_tent[xy] = tmp_it;
00820         }
00821         if (y < Y-1 && target(x, y+1) == UNDEF_VAL && (!m || (*m)(x, y+1))) { // value on top of current
00822             r = (x < X-1) ? target(x+1, y+1) : UNDEF_VAL;
00823             l = (x > 0) ? target(x-1, y+1): UNDEF_VAL;
00824             b = cur_it->first;
00825             t = (Y < Y-2) ? target(x, y+2) : UNDEF_VAL;
00826             const double dist = compute_dist_estimate_2D(l, r, b, t);
00827             const Coord2D xy(x, y+1);
00828             c_it= inv_tent.find(xy);
00829             if (c_it != inv_tent.end()) {
00830                 tentatives.erase(c_it->second);
00831             }
00832             tmp_it = tentatives.insert(pair<double, Coord2D >(dist, xy));
00833             inv_tent[xy] = tmp_it;
00834         }
00835         assert(inv_tent.size() == tentatives.size());
00836         
00837         // removing element
00838         assert(inv_tent[cur_it->second] == cur_it);
00839         inv_tent.erase(cur_it->second);
00840         tentatives.erase(cur_it);
00841     }
00842 }
00843 
00844 //===========================================================================
00845 void march_out_3D(dist_map_3D& tentatives, 
00846                   coord_map_3D& inv_tent, 
00847                   LevelSetFunction& target,
00848                   const Mask* m,
00849                   bool negative)
00850 //===========================================================================
00851 {
00852     const int X = target.dimx();
00853     const int Y = target.dimy();
00854     const int Z = target.dimz();
00855     
00856     dist_map_3D::iterator tmp_it, cur_it;
00857     coord_map_3D::iterator c_it;
00858 
00859     double l, r, f, b, u, d; // left, right, front, back, up, down
00860 
00861     while (!tentatives.empty()) {
00862         if (negative) {
00863             cur_it = tentatives.end();
00864             --cur_it;
00865         } else {
00866             cur_it = tentatives.begin();
00867         }
00868 
00869         const int x = cur_it->second.get<0>();
00870         const int y = cur_it->second.get<1>();
00871         const int z = cur_it->second.get<2>();
00872         target(x, y, z) = cur_it->first;
00873         
00874         // updating neighbours
00875 
00876         // value to the left of current (x-axis)
00877         if (x > 0 && target(x-1, y, z) == UNDEF_VAL && (!m || (*m)(x-1, y, z))) {  
00878             r = cur_it->first;
00879             l = (x > 1) ? target(x-2, y, z) : UNDEF_VAL;
00880             b = (y > 0) ? target(x-1, y-1, z) : UNDEF_VAL;
00881             f = (y < Y-1) ? target(x-1, y+1, z) : UNDEF_VAL;
00882             d = (z > 0) ? target(x-1, y, z-1) : UNDEF_VAL;
00883             u = (z < Z-1) ? target(x-1, y, z+1) : UNDEF_VAL;
00884             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00885             const Coord3D xyz(x-1, y, z);
00886             c_it = inv_tent.find(xyz);
00887             if (c_it != inv_tent.end()) {
00888                 tentatives.erase(c_it->second);
00889             }
00890             tmp_it = tentatives.insert(pair<double, Coord3D >( dist, xyz));
00891             inv_tent[xyz]= tmp_it;
00892         }
00893 
00894         // value to the right of current (x-axis)
00895         if (x < X-1 && target(x+1, y, z) == UNDEF_VAL && (!m || (*m)(x+1, y, z))) { 
00896             r = (x < X-2) ? target(x+2, y, z) : UNDEF_VAL;
00897             l = cur_it->first;
00898             b = (y > 0) ? target(x+1,y-1, z) : UNDEF_VAL;
00899             f = (y < Y-1) ? target(x+1, y+1, z) : UNDEF_VAL;
00900             d = (z > 0) ? target(x+1, y, z-1) : UNDEF_VAL;
00901             u = (z < Z-1) ? target(x+1, y, z+1) : UNDEF_VAL;
00902             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00903             const Coord3D xyz(x+1, y, z);
00904             c_it = inv_tent.find(xyz);
00905             if (c_it != inv_tent.end()) {
00906                 tentatives.erase(c_it->second);
00907             }
00908             tmp_it = tentatives.insert(pair<double, Coord3D >(dist,xyz));
00909             inv_tent[xyz] = tmp_it;
00910         }
00911 
00912         // value on the back of current (y-axis)
00913         if (y > 0 && target(x, y-1, z) == UNDEF_VAL && (!m || (*m)(x, y-1, z))) { 
00914             r = (x < X-1) ? target(x+1, y-1, z) : UNDEF_VAL;
00915             l = (x > 0) ? target(x-1, y-1, z) : UNDEF_VAL;
00916             b = (y > 1) ? target(x, y-2, z) : UNDEF_VAL;
00917             f = cur_it->first;
00918             d = (z > 0) ? target(x, y-1, z-1) : UNDEF_VAL;
00919             u = (z < Z-1) ? target(x, y-1, z+1) : UNDEF_VAL;
00920             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00921             const Coord3D xyz(x, y-1, z);
00922             c_it = inv_tent.find(xyz);
00923             if (c_it != inv_tent.end()) {
00924                 tentatives.erase(c_it->second);
00925             }
00926             tmp_it = tentatives.insert(pair<double, Coord3D >(dist, xyz));
00927             inv_tent[xyz] = tmp_it;
00928         }
00929 
00930         // value on front of current (y-axis)
00931         if (y < Y-1 && target(x, y+1, z) == UNDEF_VAL && (!m || (*m)(x, y+1, z))) { 
00932             r = (x < X-1) ? target(x+1, y+1, z) : UNDEF_VAL;
00933             l = (x > 0) ? target(x-1, y+1, z): UNDEF_VAL;
00934             b = cur_it->first;
00935             f = (Y < Y-2) ? target(x, y+2, z) : UNDEF_VAL;
00936             d = (z > 0) ? target(x, y+1, z-1) : UNDEF_VAL;
00937             u = (z < Z-1) ? target(x, y+1, z+1) : UNDEF_VAL;
00938             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00939             const Coord3D xyz(x, y+1, z);
00940             c_it= inv_tent.find(xyz);
00941             if (c_it != inv_tent.end()) {
00942                 tentatives.erase(c_it->second);
00943             }
00944             tmp_it = tentatives.insert(pair<double, Coord3D >(dist, xyz));
00945             inv_tent[xyz] = tmp_it;
00946         }
00947         // value below current (z-axis)
00948         if (z > 0 && target(x, y, z-1) == UNDEF_VAL && (!m || (*m)(x, y, z-1))) {
00949             r = (x < X-1) ? target(x+1, y, z-1) : UNDEF_VAL;
00950             l = (x > 0) ? target(x-1, y, z-1) : UNDEF_VAL;
00951             b = (y > 0) ? target(x, y-1, z-1) : UNDEF_VAL;
00952             f = (y < Y-1) ? target(x, y+1, z-1) : UNDEF_VAL;
00953             d = (z > 1) ? target(x, y, z-2) : UNDEF_VAL;
00954             u = cur_it->first;
00955             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00956             const Coord3D xyz(x, y, z-1);
00957             c_it = inv_tent.find(xyz);
00958             if (c_it != inv_tent.end()) {
00959                 tentatives.erase(c_it->second);
00960             }
00961             tmp_it = tentatives.insert(pair<double, Coord3D >(dist, xyz));
00962             inv_tent[xyz] = tmp_it;
00963         }
00964 
00965         // value above current (z-axis)
00966         if (z < Z-1 && target(x, y, z+1) == UNDEF_VAL && (!m || (*m)(x, y, z+1))) {
00967             r = (x < X-1) ? target(x+1, y, z+1) : UNDEF_VAL;
00968             l = (x > 0) ? target(x-1, y, z+1) : UNDEF_VAL;
00969             b = (y > 0) ? target(x, y-1, z+1) : UNDEF_VAL;
00970             f = (y < Y-1) ? target(x, y+1, z+1) : UNDEF_VAL;
00971             d = cur_it->first;
00972             u = (z < Z-2) ? target(x, y, z+2) : UNDEF_VAL;
00973             const double dist = compute_dist_estimate_3D(l, r, b, f, d, u);
00974             const Coord3D xyz(x, y, z+1);
00975             c_it = inv_tent.find(xyz);
00976             if (c_it != inv_tent.end()) {
00977                 tentatives.erase(c_it->second);
00978             }
00979             tmp_it = tentatives.insert(pair<double, Coord3D>(dist, xyz));
00980             inv_tent[xyz] = tmp_it;
00981         }
00982         assert(inv_tent.size() == tentatives.size());
00983         
00984         // removing element
00985         tentatives.erase(cur_it);
00986         assert(inv_tent[cur_it->second] == cur_it);
00987         inv_tent.erase(cur_it->second);
00988     }
00989 }
00990 
00991 }; // end anonymous namespace
00992 

Generated on Tue Nov 28 18:35:47 2006 for lsseg by  doxygen 1.4.7