contrib/brl/bseg/brip/brip_watershed.cxx
Go to the documentation of this file.
00001 #include "brip_watershed.h"
00002 //:
00003 // \file
00004 #include <vcl_cmath.h>
00005 #include <vnl/vnl_numeric_traits.h>
00006 #include <vnl/vnl_math.h>
00007 #include <vgl/vgl_point_2d.h>
00008 #include <vil1/vil1_rgb.h>
00009 #include "brip_vil1_float_ops.h"
00010 
00011 //Define 8-connected neighbors
00012 static int n_col[8]={-1, 0, 1,-1,1,-1,0,1};
00013 static int n_row[8]={-1,-1,-1, 0,0, 1,1,1};
00014 
00015 brip_watershed::brip_watershed(brip_watershed_params const& bwp)
00016   : brip_watershed_params(bwp)
00017 {
00018   max_region_label_ = 1;
00019 }
00020 
00021 brip_watershed::~brip_watershed()
00022 {
00023   for (vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator
00024        mit = region_adjacency_.begin();
00025        mit != region_adjacency_.end(); mit++)
00026     delete (*mit).second;
00027 }
00028 
00029 //: Print the region label array
00030 void brip_watershed::print_region_array()
00031 {
00032   vcl_cout << "\n\n";
00033   int rows = region_label_array_.rows(), cols = region_label_array_.cols();
00034   for (int r = 0; r<rows; r++)
00035   {
00036     for (int c = 0; c<cols; c++)
00037       vcl_cout << region_label_array_[r][c] << ' ';
00038     vcl_cout << '\n';
00039   }
00040   vcl_cout << vcl_endl << vcl_endl;
00041 }
00042 
00043 void brip_watershed::print_neighborhood(int col, int row, unsigned int lab)
00044 {
00045   int rows = region_label_array_.rows(), cols = region_label_array_.cols();
00046   int k = 0, m = 0;
00047   for (int n = 0; n<8; n++, k++, m++)
00048   {
00049     int rn = row + n_row[n];
00050     int cn = col + n_col[n];
00051     if (rn<0||rn>=rows||cn<0||cn>=cols)
00052     {
00053       vcl_cout << "Neighborhood out of range\n";
00054       return;
00055     }
00056     if (k>2)
00057     {
00058       vcl_cout << '\n';
00059       k = 0;
00060     }
00061     if (m == 4)
00062     {
00063       vcl_cout << lab << ' ' << region_label_array_[rn][cn];
00064       k++;
00065     }
00066     else
00067       vcl_cout << region_label_array_[rn][cn] << ' ';
00068   }
00069   vcl_cout << vcl_endl;
00070 }
00071 
00072 void brip_watershed::print_adjacency_map()
00073 {
00074   for (vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator
00075        mit = region_adjacency_.begin();
00076        mit != region_adjacency_.end(); mit++)
00077   {
00078     unsigned int reg = (*mit).first;
00079     vcl_vector<unsigned int>* adj_regs = (*mit).second;
00080     vcl_cout << "R[" << reg << "]:(";
00081     if (adj_regs)
00082       for (vcl_vector<unsigned int>::iterator rit = adj_regs->begin();
00083            rit != adj_regs->end(); rit++)
00084         vcl_cout << (*rit) << ' ';
00085     vcl_cout << ")\n";
00086   }
00087 }
00088 
00089 void brip_watershed::set_image(vil1_memory_image_of<float> const& image)
00090 {
00091   image_ = image;
00092   int w = image_.width(), h = image_.height();
00093   vil1_memory_image_of<float> Ix(w, h), Iy(w, h);
00094   vil1_memory_image_of<float> gauss =
00095     brip_vil1_float_ops::gaussian(image_, sigma_);
00096   brip_vil1_float_ops::gradient_3x3(gauss, Ix, Iy);
00097   gradient_mag_image_.resize(w,h);
00098   for (int r = 0; r<h; r++)
00099   {
00100     for (int c = 0; c<w; c++)
00101     {
00102       float gx = Ix(c,r), gy = Iy(c,r);
00103       gradient_mag_image_(c,r) = vcl_sqrt(gx*gx+gy*gy);
00104    // vcl_cout << gradient_mag_image_(c,r) << ' ';
00105     }
00106  // vcl_cout << vcl_endl;
00107   }
00108   region_label_array_.resize(h,w);
00109   region_label_array_.fill(UNLABELED);
00110 }
00111 
00112 //==============================================================
00113 //: Find points of local minima in gradient magnitude.
00114 //  Label these points as seeds.
00115 bool brip_watershed::compute_seeds()
00116 {
00117   int w = gradient_mag_image_.width(), h = gradient_mag_image_.height();
00118   max_region_label_ = 1;
00119   for (int r = 2; r<h-2; r++)
00120     for (int c = 2;c<w-2;c++)
00121     {
00122       float min_grad = vnl_numeric_traits<float>::maxval;
00123       float max_grad = -min_grad;
00124       int min_i = 0, min_j=0;
00125       for (int i = -1;i<=1; i++)
00126         for (int j = -1;j<=1; j++)
00127         {
00128           float g = gradient_mag_image_(c+j, r+i);
00129           max_grad = vnl_math_max(max_grad, g);
00130           if (g<min_grad)
00131           {
00132             min_grad = g;
00133             min_i = i;
00134             min_j = j;
00135           }
00136         }
00137       float diff = max_grad-min_grad;
00138       //a seed is defined when the minimum is at the center of
00139       //local 3x3 neighborhood and gradient diff is greater than
00140       //a threshold.
00141       if (!min_i&&!min_j&&diff>thresh_)
00142       {
00143         max_region_label_++;
00144         region_label_array_[r][c] = max_region_label_;
00145         if (verbose_)
00146         {
00147           vcl_cout << "\nS(c:" << c << " r:" << r << ')' << vcl_endl;
00148           this->print_neighborhood(c, r, max_region_label_);
00149         }
00150       }
00151     }
00152   return max_region_label_ != 0;
00153 }
00154 
00155 //==============================================================
00156 //: Initialize the priority queue from the seeds give each region a new label
00157 bool brip_watershed::initialize_queue()
00158 {
00159   int w = gradient_mag_image_.width(), h = gradient_mag_image_.height();
00160   for (int r = 2; r<h-2; r++)
00161     for (int c = 2;c<w-2;c++)
00162       for (int n = 0;n<8; n++)
00163       {
00164         int cn = c+n_col[n], rn = r+n_row[n];
00165         unsigned int lab = region_label_array_[rn][cn];
00166         if (lab>BOUNDARY)
00167           //add a new region pixel to the priority queue
00168         {
00169           vgl_point_2d<int> location(c,r);
00170           vgl_point_2d<int> nearest(cn,rn);
00171           float cost = gradient_mag_image_(c, r);
00172           brip_region_pixel_sptr pix =
00173             new brip_region_pixel(location, nearest, cost, 0, lab);
00174           priority_queue_.push(pix);
00175         }
00176       }
00177   //  vcl_cout << *(priority_queue_.top()) << vcl_endl;
00178   return priority_queue_.size()>0;
00179 }
00180 
00181 //==============================================================
00182 //: Process the priority queue and grow regions
00183 bool brip_watershed::grow_regions()
00184 {
00185   int n_boundary_pix=0, n_region_pix = 0;
00186   int rs = region_label_array_.rows(), cs = region_label_array_.cols();
00187   while (priority_queue_.size() != 0)
00188   {
00189     //get the lowest cost pixel
00190     brip_region_pixel_sptr pix = priority_queue_.top();
00191     if (!pix)
00192       return false;
00193     priority_queue_.pop();
00194 
00195     unsigned int lab = pix->label_;
00196     if (lab <= BOUNDARY)
00197       continue;
00198     vgl_point_2d<int> location = pix->location_;
00199     vgl_point_2d<int> nearest =  pix->nearest_;
00200     if (verbose_)
00201     {
00202       vcl_cout << "\nN(c:" << location.x() << " r:" << location.y() << ")\n";
00203       this->print_neighborhood(location.x(), location.y(), lab);
00204     }
00205     for (int n = 0; n<8; n++)
00206     {
00207       //location of neighboring pixel
00208       int rn = location.y()+n_row[n];
00209       int cn = location.x()+n_col[n];
00210       if (rn<1||cn<1||rn>rs-2||cn>cs-2)
00211         continue;
00212       unsigned int n_lab = region_label_array_[rn][cn];
00213 
00214       //the neighbor is labeled but not my label then I become
00215       //a boundary point
00216       if (n_lab>BOUNDARY&&n_lab!=lab)
00217       {
00218         //note that the regions are adjacent
00219         this->add_adjacency(lab, n_lab);
00220         this->add_adjacency(n_lab, lab);
00221         lab = BOUNDARY;
00222         n_boundary_pix++;
00223         break;
00224       }
00225     }
00226     pix->label_=lab;
00227     region_label_array_[location.y()][location.x()]=lab;
00228     //If we didn't detect a boundary then add new region pixels
00229     if (lab>BOUNDARY)
00230       for (int n = 0; n<8; n++)
00231       {
00232         //location of neighboring pixel
00233         int rn = location.y()+n_row[n];
00234         int cn = location.x()+n_col[n];
00235         if (rn<1||cn<1||rn>rs-2||cn>cs-2)
00236           continue;
00237         unsigned int n_lab = region_label_array_[rn][cn];
00238         if (n_lab != UNLABELED)
00239           continue;
00240         //attributes of unlabeled neighboring pixel
00241         vgl_point_2d<int> n_location(cn, rn);
00242         float cost = gradient_mag_image_(cn, rn);
00243         brip_region_pixel_sptr pix =
00244           new brip_region_pixel(n_location, nearest, cost, 0, lab);
00245         priority_queue_.push(pix);
00246         //mark the label array
00247         region_label_array_[rn][cn] = lab;
00248         n_region_pix++;
00249       }
00250     if (verbose_)
00251     {
00252       vcl_cout << '\n';
00253       this->print_neighborhood(location.x(), location.y(), lab);
00254     }
00255   }
00256   if (verbose_)
00257     vcl_cout << "Found " << n_boundary_pix << " boundary pixels and "
00258              << n_region_pix << " region pixels\n";
00259   return n_region_pix>0||n_boundary_pix>0;
00260 }
00261 
00262 //:add a region adjacency relation.  Returns false if relation is already known.
00263 bool brip_watershed::add_adjacency(const unsigned int reg,
00264                                    const unsigned int adj_reg)
00265 {
00266   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator adi;
00267   adi = region_adjacency_.find(reg);
00268 
00269   if (adi !=region_adjacency_.end())
00270   {
00271     vcl_vector<unsigned int> * vec = region_adjacency_[reg];
00272 
00273     for (unsigned int i =0 ; i < vec->size(); i++)
00274       if ((*vec)[i] == adj_reg)
00275         return false; //adjacency relation already known
00276 
00277     vec->push_back(adj_reg);
00278   }
00279   else//make a new adjacent region array
00280   {
00281     vcl_vector<unsigned int>* adj_array = new vcl_vector<unsigned int>;
00282     adj_array->push_back(adj_reg);
00283     region_adjacency_[reg]=adj_array;
00284   }
00285   return true;
00286 }
00287 
00288 bool brip_watershed::adjacent_regions(const unsigned int reg,
00289                                       vcl_vector<unsigned int>& adj_regs)
00290 {
00291   adj_regs.clear();
00292   vcl_map<unsigned int, vcl_vector<unsigned int>* >::iterator adi;
00293   adi = region_adjacency_.find(reg);
00294 
00295   if (adi !=region_adjacency_.end())
00296   {
00297     adj_regs = *(region_adjacency_[reg]);
00298     return true;
00299   }
00300   else
00301     return false;
00302 }
00303 
00304 bool brip_watershed::compute_regions()
00305 {
00306   if (!compute_seeds())
00307   {
00308     vcl_cout << "In brip_watershed::compute_regions() - no seeds\n";
00309     return false;
00310   }
00311 
00312   if (!initialize_queue())
00313   {
00314     vcl_cout << "In brip_watershed::compute_regions() - queue initialization failed\n";
00315     return false;
00316   }
00317   if (!grow_regions())
00318   {
00319     vcl_cout << "In brip_watershed::grow_regions() - failed\n";
00320     return false;
00321   }
00322 
00323   return true;
00324 }
00325 
00326 //compute a color image with the original monochrome image and green
00327 //region boundary overlay
00328 vil1_image brip_watershed::overlay_image()
00329 {
00330   // convert the float image
00331   vil1_memory_image_of<unsigned char> cimage =
00332     brip_vil1_float_ops::convert_to_byte(image_);
00333   //create a rgb image
00334   int w = cimage.width(), h = cimage.height();
00335   vil1_memory_image_of<vil1_rgb<unsigned char> > overlay(w,h);
00336   for (int row = 0; row<h; row++)
00337     for (int col = 0; col<w; col++)
00338       if (region_label_array_[row][col]>BOUNDARY)
00339       {
00340         overlay(col,row).r = cimage(col,row);
00341         overlay(col,row).g = cimage(col,row);
00342         overlay(col,row).b = cimage(col,row);
00343       }
00344       else
00345       {
00346         overlay(col,row).r = 0;
00347         overlay(col,row).g = 255;
00348         overlay(col,row).b = 0;
00349       }
00350   return overlay;
00351 }