core/vil/algo/vil_flood_fill.h
Go to the documentation of this file.
00001 #ifndef vil_flood_fill_h_
00002 #define vil_flood_fill_h_
00003 //:
00004 // \file
00005 // \brief Fills a connected region with a given value.
00006 // \author Tim Cootes
00007 
00008 #include <vil/vil_image_view.h>
00009 #include <vcl_vector.h>
00010 #include <vcl_utility.h> // for vcl_pair
00011 #include <vil/vil_chord.h>
00012 
00013 //: Search along i direction either side for limits of pixels matching v
00014 //  Fills in all such pixels with new_v.  Returns limits in ilo and ihi
00015 // \relatesalso vil_image_view
00016 template<class T>
00017 inline void vil_flood_fill_row(vil_image_view<T>& image,
00018                                unsigned i, unsigned j,
00019                                T v, T new_v,
00020                                unsigned& ilo, unsigned& ihi)
00021 {
00022   T* row=image.top_left_ptr() + j*image.jstep();
00023   unsigned ni1=image.ni()-1;
00024   vcl_ptrdiff_t istep=image.istep();
00025   ilo=i;
00026   T* p=row+(i-1)*istep;
00027   while (ilo>0 && *p==v) { ilo--; *p=new_v; p-=istep; }
00028   ihi=i;
00029   p=row+(i+1)*istep;
00030   while (ihi<ni1 && *p==v) { ihi++; *p=new_v; p+=istep;}
00031 }
00032 
00033 //: Flood fill on a 4-connected region
00034 //  Find every point in 4-connected region with values image(i,j)==v
00035 //  containing (seed_i,seed_j), and change their values to new_v
00036 //
00037 //  Note, currently uses inefficient (x,y) access to image. Could be improved
00038 //  using fast pointer access to work along the rows.
00039 // \relatesalso vil_image_view
00040 template<class T>
00041 void vil_flood_fill4(vil_image_view<T>& image,
00042                      unsigned seed_i, unsigned seed_j,
00043                      T v, T new_v)
00044 {
00045   unsigned ni1=image.ni()-1;
00046   unsigned nj1=image.nj()-1;
00047   vcl_vector<vcl_pair<unsigned,unsigned> > q;  // List of points to visit
00048   if (seed_i>ni1 || seed_j>nj1) return;  // Seed outside image
00049 
00050   // Initialise the queue with the seed
00051   q.push_back(vcl_pair<unsigned,unsigned>(seed_i,seed_j));
00052 
00053   unsigned k=0;
00054   while (k<q.size())
00055   {
00056     unsigned i=q[k].first, j=q[k].second;
00057     if (image(i,j)==v)
00058     {
00059       image(i,j)=new_v;
00060       // Search to left and right for limit of this line
00061       unsigned ilo,ihi;
00062       vil_flood_fill_row(image,i,j,v,new_v,ilo,ihi);
00063 
00064       if (j>0)
00065       {
00066         // Consider row above
00067         for (unsigned i1=ilo;i1<=ihi;++i1)
00068           if (image(i1,j-1)==v)
00069             q.push_back(vcl_pair<unsigned,unsigned>(i1,j-1));
00070       }
00071       if (j<nj1)
00072       {
00073         // Consider row below
00074         for (unsigned i1=ilo;i1<=ihi;++i1)
00075           if (image(i1,j+1)==v)
00076             q.push_back(vcl_pair<unsigned,unsigned>(i1,j+1));
00077       }
00078     }
00079     k++;
00080   }
00081 }
00082 
00083 //: Flood fill on a 4-connected region, and record region
00084 //  Find every point in 4-connected region with values image(i,j)==v
00085 //  containing (seed_i,seed_j), and change their values to new_v
00086 //
00087 //  On exit region is filled with a set of image chords which cover the
00088 //  region.
00089 //
00090 //  Note, currently uses inefficient (x,y) access to image. Could be improved
00091 //  using fast pointer access to work along the rows.
00092 // \relatesalso vil_image_view
00093 template<class T>
00094 void vil_flood_fill4(vil_image_view<T>& image,
00095                      unsigned seed_i, unsigned seed_j,
00096                      T v, T new_v,
00097                      vcl_vector<vil_chord>& region)
00098 {
00099   region.resize(0);
00100   unsigned ni1=image.ni()-1;
00101   unsigned nj1=image.nj()-1;
00102   vcl_vector<vcl_pair<unsigned,unsigned> > q;  // List of points to visit
00103   if (seed_i>ni1 || seed_j>nj1) return;  // Seed outside image
00104 
00105   // Initialise the queue with the seed
00106   q.push_back(vcl_pair<unsigned,unsigned>(seed_i,seed_j));
00107 
00108   unsigned k=0;
00109   while (k<q.size())
00110   {
00111     unsigned i=q[k].first, j=q[k].second;
00112     if (image(i,j)==v)
00113     {
00114       image(i,j)=new_v;
00115       // Search to left and right for limit of this line
00116       unsigned ilo,ihi;
00117       vil_flood_fill_row(image,i,j,v,new_v,ilo,ihi);
00118 
00119       region.push_back(vil_chord(ilo,ihi,j));
00120 
00121       if (j>0)
00122       {
00123         // Consider row above
00124         for (unsigned i1=ilo;i1<=ihi;++i1)
00125           if (image(i1,j-1)==v)
00126             q.push_back(vcl_pair<unsigned,unsigned>(i1,j-1));
00127       }
00128       if (j<nj1)
00129       {
00130         // Consider row below
00131         for (unsigned i1=ilo;i1<=ihi;++i1)
00132           if (image(i1,j+1)==v)
00133             q.push_back(vcl_pair<unsigned,unsigned>(i1,j+1));
00134       }
00135     }
00136     k++;
00137   }
00138 }
00139 
00140 
00141 //: Flood fill on a 8-connected region
00142 //  Find every point in 8-connected region with values image(i,j)==v
00143 //  containing (seed_i,seed_j), and change their values to new_v
00144 //
00145 //  Note, currently uses inefficient (x,y) access to image. Could be improved
00146 //  using fast pointer access to work along the rows.
00147 // \relatesalso vil_image_view
00148 template<class T>
00149 void vil_flood_fill8(vil_image_view<T>& image,
00150                      unsigned seed_i, unsigned seed_j,
00151                      T v, T new_v)
00152 {
00153   unsigned ni1=image.ni()-1;
00154   unsigned nj1=image.nj()-1;
00155   vcl_vector<vcl_pair<unsigned,unsigned> > q;  // List of points to visit
00156   if (seed_i>ni1 || seed_j>nj1) return;  // Seed outside image
00157 
00158   // Initialise the queue with the seed
00159   q.push_back(vcl_pair<unsigned,unsigned>(seed_i,seed_j));
00160 
00161   unsigned k=0;
00162   while (k<q.size())
00163   {
00164     unsigned i=q[k].first, j=q[k].second;
00165     if (image(i,j)==v)
00166     {
00167       image(i,j)=new_v;
00168       // Search to left and right for limit of this line
00169       unsigned ilo,ihi;
00170       vil_flood_fill_row(image,i,j,v,new_v,ilo,ihi);
00171 
00172       // Expand by one to allow all 8 neighbours to be examined
00173       if (ilo>0) ilo--;
00174       if (ihi<ni1) ihi++;
00175       if (j>0)
00176       {
00177         // Consider row above
00178         for (unsigned i1=ilo;i1<=ihi;++i1)
00179           if (image(i1,j-1)==v)
00180             q.push_back(vcl_pair<unsigned,unsigned>(i1,j-1));
00181       }
00182       if (j<nj1)
00183       {
00184         // Consider row below
00185         for (unsigned i1=ilo;i1<=ihi;++i1)
00186           if (image(i1,j+1)==v)
00187             q.push_back(vcl_pair<unsigned,unsigned>(i1,j+1));
00188       }
00189     }
00190     k++;
00191   }
00192 }
00193 
00194 //: Flood fill on a 8-connected region, and record region
00195 //  Find every point in 8-connected region with values image(i,j)==v
00196 //  containing (seed_i,seed_j), and change their values to new_v
00197 //
00198 //  On exit region is filled with a set of image chords which cover the
00199 //  region.
00200 //
00201 //  Note, currently uses inefficient (x,y) access to image. Could be improved
00202 //  using fast pointer access to work along the rows.
00203 // \relatesalso vil_image_view
00204 template<class T>
00205 void vil_flood_fill8(vil_image_view<T>& image,
00206                      unsigned seed_i, unsigned seed_j,
00207                      T v, T new_v,
00208                      vcl_vector<vil_chord>& region)
00209 {
00210   region.resize(0);
00211   unsigned ni1=image.ni()-1;
00212   unsigned nj1=image.nj()-1;
00213   vcl_vector<vcl_pair<unsigned,unsigned> > q;  // List of points to visit
00214   if (seed_i>ni1 || seed_j>nj1) return;  // Seed outside image
00215 
00216   // Initialise the queue with the seed
00217   q.push_back(vcl_pair<unsigned,unsigned>(seed_i,seed_j));
00218 
00219   unsigned k=0;
00220   while (k<q.size())
00221   {
00222     unsigned i=q[k].first, j=q[k].second;
00223     if (image(i,j)==v)
00224     {
00225       image(i,j)=new_v;
00226       // Search to left and right for limit of this line
00227       unsigned ilo,ihi;
00228       vil_flood_fill_row(image,i,j,v,new_v,ilo,ihi);
00229 
00230       region.push_back(vil_chord(ilo,ihi,j));
00231 
00232       // Expand by one to allow all 8 neighbours to be examined
00233       if (ilo>0) ilo--;
00234       if (ihi<ni1) ihi++;
00235       if (j>0)
00236       {
00237         // Consider row above
00238         for (unsigned i1=ilo;i1<=ihi;++i1)
00239           if (image(i1,j-1)==v)
00240             q.push_back(vcl_pair<unsigned,unsigned>(i1,j-1));
00241       }
00242       if (j<nj1)
00243       {
00244         // Consider row below
00245         for (unsigned i1=ilo;i1<=ihi;++i1)
00246           if (image(i1,j+1)==v)
00247             q.push_back(vcl_pair<unsigned,unsigned>(i1,j+1));
00248       }
00249     }
00250     k++;
00251   }
00252 }
00253 
00254 #endif // vil_flood_fill_h_