core/vil/algo/vil_distance_transform.cxx

Go to the documentation of this file.
00001 #include "vil_distance_transform.h"
00002 //:
00003 // \file
00004 // \brief Compute distance function
00005 // \author Tim Cootes
00006 
00007 #include <vil/vil_fill.h>
00008 #include <vcl_algorithm.h>
00009 #include <vcl_cassert.h>
00010 
00011 //: Compute distance function from zeros in original image
00012 //  Image is assumed to be filled with max_dist where there
00013 //  is background, and zero at the places of interest.
00014 //  On exit, the values are the 8-connected distance to the
00015 //  nearest original zero region.
00016 void vil_distance_transform(vil_image_view<float>& image)
00017 {
00018   // Low to high pass
00019   vil_distance_transform_one_way(image);
00020 
00021   // Flip to achieve high to low pass
00022   // Don't use vil_flip* as they assume const images.
00023   unsigned ni = image.ni(), nj = image.nj();
00024   vil_image_view<float> flip_image(image.memory_chunk(),
00025                                    &image(ni-1,nj-1), ni,nj,1,
00026                                    -image.istep(), -image.jstep(),
00027                                    image.nplanes());
00028   vil_distance_transform_one_way(flip_image);
00029 }
00030 
00031 //: Compute directed distance function from zeros in original image
00032 //  Image is assumed to be filled with max_dist where there
00033 //  is background, and zero at the places of interest.
00034 //  On exit, the values are the 8-connected distance to the
00035 //  nearest original zero region above or to the left of current point.
00036 //  One pass of distance transform, going from low to high i,j.
00037 void vil_distance_transform_one_way(vil_image_view<float>& image)
00038 {
00039   assert(image.nplanes()==1);
00040   unsigned ni = image.ni();
00041   unsigned nj = image.nj();
00042   unsigned ni1 = ni-1;
00043   vcl_ptrdiff_t istep = image.istep(),  jstep = image.jstep();
00044   vcl_ptrdiff_t o1 = -istep, o2 = -jstep-istep, o3 = -jstep, o4 = istep-jstep;
00045   float* row0 = image.top_left_ptr();
00046 
00047   const float sqrt2 = 1.4142135f;
00048 
00049   // Process the first row
00050   float* p0 = row0+istep;
00051   for (unsigned i=1;i<ni;++i,p0+=istep)
00052   {
00053       *p0 = vcl_min(p0[-istep]+1.0f,*p0);
00054   }
00055 
00056   row0 += jstep;  // Move to next row
00057 
00058   // Process each subsequent row from low to high values of j
00059   for (unsigned j=1;j<nj;++j,row0+=jstep)
00060   {
00061     // Check first element against first two in previous row
00062     *row0 = vcl_min(row0[o3]+1.0f,*row0);
00063     *row0 = vcl_min(row0[o4]+sqrt2,*row0);
00064 
00065     float* p0 = row0+istep;
00066     for (unsigned i=1;i<=ni1;++i,p0+=istep)
00067     {
00068       *p0 = vcl_min(p0[o1]+1.0f ,*p0); // (-1,0)
00069       *p0 = vcl_min(p0[o2]+sqrt2,*p0); // (-1,-1)
00070       *p0 = vcl_min(p0[o3]+1.0f ,*p0); // (0,-1)
00071       *p0 = vcl_min(p0[o4]+sqrt2,*p0); // (1,-1)
00072     }
00073 
00074     // Check last element in row
00075     *p0 = vcl_min(p0[o1]+1.0f ,*p0); // (-1,0)
00076     *p0 = vcl_min(p0[o2]+sqrt2,*p0); // (-1,-1)
00077     *p0 = vcl_min(p0[o3]+1.0f ,*p0); // (0,-1)
00078   }
00079 }
00080 
00081 //: Compute distance function from true elements in mask
00082 //  On exit, the values are the 8-connected distance to the
00083 //  nearest original zero region (or max_dist, if that is smaller).
00084 void vil_distance_transform(const vil_image_view<bool>& mask,
00085                             vil_image_view<float>& distance_image,
00086                             float max_dist)
00087 {
00088   distance_image.set_size(mask.ni(),mask.nj());
00089   distance_image.fill(max_dist);
00090   vil_fill_mask(distance_image,mask,0.0f);
00091 
00092   vil_distance_transform(distance_image);
00093 }
00094 
00095 //: Distance function, using neighbours +/-2 in x,y
00096 //  More accurate thand vil_distance_function_one_way
00097 void vil_distance_transform_r2_one_way(vil_image_view<float>& image)
00098 {
00099   assert(image.nplanes()==1);
00100   unsigned ni = image.ni();
00101   unsigned nj = image.nj();
00102   unsigned ni2 = ni-2;
00103   vcl_ptrdiff_t istep = image.istep(),  jstep = image.jstep();
00104 
00105   //   Kernel defining points to consider (relative to XX)
00106   //   -- o6 -- o7 --
00107   //   o5 o2 o3 o4 o8
00108   //   -- o1 XX -- --
00109   vcl_ptrdiff_t o1 = -istep, o2 = -jstep-istep;
00110   vcl_ptrdiff_t o3 = -jstep, o4 = istep-jstep;
00111   vcl_ptrdiff_t o5 = -2*istep-jstep;
00112   vcl_ptrdiff_t o6 = -istep-2*jstep;
00113   vcl_ptrdiff_t o7 =  istep-2*jstep;
00114   vcl_ptrdiff_t o8 =  2*istep-jstep;
00115 
00116   float* row0 = image.top_left_ptr();
00117 
00118   const float sqrt2 = 1.4142135f;
00119   const float sqrt5 = 2.236068f;
00120 
00121   // Process the first row
00122   float* p0 = row0+istep;
00123   for (unsigned i=1;i<ni;++i,p0+=istep)
00124   {
00125       *p0 = vcl_min(p0[-istep]+1.0f,*p0);
00126   }
00127 
00128   row0 += jstep;  // Move to next row
00129 
00130   // ==== Process second row ====
00131   // Check first element against elements in previous row
00132   *row0 = vcl_min(row0[o3]+1.0f,*row0);  // (0,-1)
00133   *row0 = vcl_min(row0[o4]+sqrt5,*row0); // (1,-1)
00134   *row0 = vcl_min(row0[o8]+sqrt5,*row0); // (2,-1)
00135 
00136   p0 = row0+istep;  // Move to element 1
00137   *p0 = vcl_min(p0[o1]+1.0f,*p0); // (-1,0)
00138   *p0 = vcl_min(p0[o2]+sqrt2,*p0); // (-1,-1)
00139   *p0 = vcl_min(p0[o3]+1.0f,*p0); // (0,-1)
00140   *p0 = vcl_min(p0[o4]+sqrt2,*p0); // (1,-1)
00141   *p0 = vcl_min(p0[o8]+sqrt5,*p0); // (2,-1)
00142 
00143   p0+=istep;  // Move to element 2
00144   for (unsigned i=2;i<ni2;++i,p0+=istep)
00145   {
00146     *p0 = vcl_min(p0[o1]+1.0f,*p0); // (-1,0)
00147     *p0 = vcl_min(p0[o2]+sqrt2,*p0); // (-1,-1)
00148     *p0 = vcl_min(p0[o3]+1.0f,*p0); // (0,-1)
00149     *p0 = vcl_min(p0[o4]+sqrt2,*p0); // (1,-1)
00150     *p0 = vcl_min(p0[o5]+sqrt5,*p0); // (-2,-1)
00151     *p0 = vcl_min(p0[o8]+sqrt5,*p0); // (2,-1)
00152   }
00153 
00154   // Check element ni-2
00155   *p0 = vcl_min(p0[o1]+1.0f,*p0); // (-1,0)
00156   *p0 = vcl_min(p0[o2]+sqrt2,*p0); // (-1,-1)
00157   *p0 = vcl_min(p0[o3]+1.0f,*p0); // (0,-1)
00158   *p0 = vcl_min(p0[o4]+sqrt2,*p0); // (1,-1)
00159   *p0 = vcl_min(p0[o5]+sqrt5,*p0); // (-2,-1)
00160 
00161   p0+=istep;  // Move to element ni-1
00162   // Check last element in row
00163   *p0 = vcl_min(p0[o1]+1.0f,*p0); // (-1,0)
00164   *p0 = vcl_min(p0[o2]+sqrt2,*p0); // (-1,-1)
00165   *p0 = vcl_min(p0[o3]+1.0f,*p0); // (0,-1)
00166   *p0 = vcl_min(p0[o5]+sqrt5,*p0); // (-2,-1)
00167 
00168   row0 += jstep;  // Move to next row (2)
00169 
00170   // Process each subsequent row from low to high values of j
00171   for (unsigned j=2;j<nj;++j,row0+=jstep)
00172   {
00173     // Check first element
00174     *row0 = vcl_min(row0[o3]+1.0f,*row0);  // (0,-1)
00175     *row0 = vcl_min(row0[o4]+sqrt2,*row0); // (1,-1)
00176     *row0 = vcl_min(row0[o7]+sqrt5,*row0); // (1,-2)
00177     *row0 = vcl_min(row0[o8]+sqrt5,*row0); // (2,-1)
00178 
00179     float* p0 = row0+istep;  // Element 1
00180     // Check second element, allowing for boundary conditions
00181     *p0 = vcl_min(p0[o1]+1.0f,*p0); // (-1,0)
00182     *p0 = vcl_min(p0[o2]+sqrt2,*p0); // (-1,-1)
00183     *p0 = vcl_min(p0[o3]+1.0f,*p0); // (0,-1)
00184     *p0 = vcl_min(p0[o4]+sqrt2,*p0); // (1,-1)
00185     *p0 = vcl_min(p0[o6]+sqrt5,*p0); // (-1,-2)
00186     *p0 = vcl_min(p0[o7]+sqrt5,*p0); // (1,-2)
00187     *p0 = vcl_min(p0[o8]+sqrt5,*p0); // (2,-1)
00188 
00189     p0+=istep;  // Move to next element (2)
00190     for (unsigned i=2;i<ni2;++i,p0+=istep)
00191     {
00192       *p0 = vcl_min(p0[o1]+1.0f,*p0); // (-1,0)
00193       *p0 = vcl_min(p0[o2]+sqrt2,*p0); // (-1,-1)
00194       *p0 = vcl_min(p0[o3]+1.0f,*p0); // (0,-1)
00195       *p0 = vcl_min(p0[o4]+sqrt2,*p0); // (1,-1)
00196       *p0 = vcl_min(p0[o5]+sqrt5,*p0); // (-2,-1)
00197       *p0 = vcl_min(p0[o6]+sqrt5,*p0); // (-1,-2)
00198       *p0 = vcl_min(p0[o7]+sqrt5,*p0); // (1,-2)
00199       *p0 = vcl_min(p0[o8]+sqrt5,*p0); // (2,-1)
00200     }
00201     // p0 points to element (ni-2,y)
00202 
00203     // Check last but one element in row
00204     *p0 = vcl_min(p0[o1]+1.0f,*p0); // (-1,0)
00205     *p0 = vcl_min(p0[o2]+sqrt2,*p0); // (-1,-1)
00206     *p0 = vcl_min(p0[o3]+1.0f,*p0); // (0,-1)
00207     *p0 = vcl_min(p0[o4]+sqrt2,*p0); // (1,-1)
00208     *p0 = vcl_min(p0[o5]+sqrt5,*p0); // (-2,-1)
00209     *p0 = vcl_min(p0[o6]+sqrt5,*p0); // (-1,-2)
00210     *p0 = vcl_min(p0[o7]+sqrt5,*p0); // (1,-2)
00211 
00212     p0+=istep; // Move to last element (ni-1,y)
00213     // Process last element in row
00214     *p0 = vcl_min(p0[o1]+1.0f,*p0); // (-1,0)
00215     *p0 = vcl_min(p0[o2]+sqrt2,*p0); // (-1,-1)
00216     *p0 = vcl_min(p0[o3]+1.0f,*p0); // (0,-1)
00217     *p0 = vcl_min(p0[o5]+sqrt5,*p0); // (-2,-1)
00218     *p0 = vcl_min(p0[o6]+sqrt5,*p0); // (-1,-2)
00219   }
00220 }
00221 
00222 //: Compute distance function from zeros in original image
00223 //  Image is assumed to be filled with max_dist where there
00224 //  is background, and zero at the places of interest.
00225 //  On exit, the values are the 24-connected distance to the
00226 //  nearest original zero region. (ie considers neighbours in
00227 //  a +/-2 pixel region around each point).
00228 //  More accurate than vil_distance_transform(image), but
00229 //  approximately twice the processing required.
00230 void vil_distance_transform_r2(vil_image_view<float>& image)
00231 {
00232   // Low to high pass
00233   vil_distance_transform_r2_one_way(image);
00234 
00235   // Flip to achieve high to low pass
00236   // Don't use vil_flip* as they assume const images.
00237   unsigned ni = image.ni(), nj = image.nj();
00238   vil_image_view<float> flip_image(image.memory_chunk(),
00239                                    &image(ni-1,nj-1), ni,nj,1,
00240                                    -image.istep(), -image.jstep(),
00241                                    image.nplanes());
00242   vil_distance_transform_r2_one_way(flip_image);
00243 }
00244 

Generated on Mon Mar 8 05:08:44 2010 for core/vil by  doxygen 1.5.1