contrib/mul/vil3d/algo/vil3d_distance_transform.cxx
Go to the documentation of this file.
00001 #include "vil3d_distance_transform.h"
00002 //:
00003 // \file
00004 // \brief Compute distance transform using chamfer distance
00005 // \author Kola Babalola
00006 
00007 #include <vil3d/vil3d_image_view.h>
00008 #include <vil3d/algo/vil3d_fill_boundary.h>
00009 #include <vil3d/algo/vil3d_threshold.h>
00010 #include <vil3d/vil3d_slice.h>
00011 #include <vil/vil_fill.h>
00012 #include <vcl_cassert.h>
00013 #include <vcl_algorithm.h>
00014 
00015 //: Compute signed distance transform in 3d from zeros in original image.
00016 //  Image is assumed to be filled with max_dist
00017 //  where there is background, and zero in the places of interest.
00018 //  On exit, the values are the signed 26-connected distance
00019 //  to the nearest original zero region. Positive values are
00020 //  outside the bounded region and negative values are inside.
00021 //  The values on the boundary are zero
00022 void vil3d_signed_distance_transform(vil3d_image_view<float>& image, const float distance_link_i, const float distance_link_j, const float distance_link_k)
00023 {
00024   unsigned ni = image.ni(),nj = image.nj(), nk = image.nk();
00025   unsigned nplanes = image.nplanes();
00026   // calculate a binary mask in which interior voxels are "on"
00027   // need to convert the image to a short datatype with "1" on boundary
00028   vil3d_image_view<bool> image2(ni,nj,nk,nplanes);
00029   vil3d_threshold_below(image,image2,0.1f);
00030   vil3d_fill_boundary(image2);
00031 
00032   // calculate the distance transform as usual
00033   vil3d_distance_transform(image,distance_link_i,distance_link_j,distance_link_k);
00034 
00035   // set all voxels in mask to negative values
00036   vcl_ptrdiff_t istep0 = image.istep();
00037   vcl_ptrdiff_t istep2 = image2.istep();
00038   float *p0 = image.origin_ptr();
00039   bool *p1 = image2.origin_ptr();
00040 
00041   for (unsigned int k=0; k<nk; ++k)
00042     for (unsigned int j=0; j<nj; ++j)
00043       for (unsigned int i=0; i<ni; ++i,p0+=istep0,p1+=istep2)
00044       {
00045         if (*p1)
00046           *p0 *= -1.0f;
00047       }
00048 }
00049 
00050 //  Print function to help debugging
00051 template<class T> void print_values(const vil_image_view<T> &img)
00052 {
00053     for (int j = 0; j < img.nj(); j++)
00054     {
00055       for (int i = 0; i < img.ni(); i++)
00056         vcl_cout << img(i,j) << ' ';
00057       vcl_cout << vcl_endl;
00058     }
00059 }
00060 
00061 template<class T> void print_values(const vil3d_image_view<T> &img)
00062 {
00063   for (int k = 0; k < img.nk(); k++)
00064     for (int j = 0; j < img.nj(); j++)
00065     {
00066       for (int i = 0; i < img.ni(); i++)
00067         vcl_cout << img(i,j,k) << ' ';
00068       vcl_cout << vcl_endl;
00069     }
00070 }
00071 
00072 
00073 //: Compute 3d signed distance transform from true elements in mask.
00074 //  On exit, values are 26 connected distance from the 'true' boundary.
00075 //  There are no zero values because the true boundary is the infinitesimally
00076 //  thin edge of the true and false regions of the mask. The values inside
00077 //  the mask are negative and those outside are positive
00078 void vil3d_signed_distance_transform(const vil3d_image_view<bool>& mask,
00079                                      vil3d_image_view<float>& image,
00080                                      float max_dist,
00081                                      const float distance_link_i,
00082                                      const float distance_link_j,
00083                                      const float distance_link_k)
00084 {
00085   image.set_size(mask.ni(),mask.nj(),mask.nk(),mask.nplanes());
00086   image.fill(max_dist);
00087 
00088   unsigned ni = image.ni();
00089   unsigned nj = image.nj();
00090   unsigned nk = image.nk(), k;
00091   unsigned nplanes = image.nplanes();
00092 
00093   vil_image_view<bool> mask_slice(mask.ni(),mask.nk(),mask.nplanes());
00094   vil_image_view<float> image_slice(ni,nj,nplanes);
00095 
00096   image.fill(max_dist);
00097 
00098   vil3d_image_view<float> image_inverse(ni,nj,nk,nplanes);
00099   image_inverse.fill(0.0f);
00100 
00101   for (k=0;k<nk;k++)
00102   {
00103     mask_slice = vil3d_slice_ij(mask,k);
00104     image_slice = vil3d_slice_ij(image,k);
00105     vil_fill_mask(image_slice,mask_slice,0.0f);
00106     image_slice = vil3d_slice_ij(image_inverse,k);
00107     vil_fill_mask(image_slice,mask_slice,max_dist);
00108   }
00109 
00110   // find distance transform of image and inverse image and subtract
00111   vil3d_distance_transform(image,distance_link_i,distance_link_j,distance_link_k);
00112   vil3d_distance_transform(image_inverse,distance_link_i,distance_link_j,distance_link_k);
00113 
00114   float *p0 = image.origin_ptr();
00115   float *p1 = image_inverse.origin_ptr();
00116 
00117   for (unsigned int k=0; k<nk; ++k)
00118     for (unsigned int j=0; j<nj; ++j)
00119       for (unsigned int i=0; i<ni; ++i,p0+=image.istep(),p1+=image_inverse.istep())
00120         *p0 -= *p1;
00121 }
00122 
00123 //: Compute distance transform in 3d from zeros in original image.
00124 //  Image is assumed to be filled with max_dist where
00125 //  there is background, and zero in the places of interest.
00126 //  On exit, the values are the 8-connected distance to the
00127 //  nearest original zero region.
00128 void vil3d_distance_transform(vil3d_image_view<float>& image, const float distance_link_i, const float distance_link_j, const float distance_link_k)
00129 {
00130   // Low to high pass
00131   vil3d_distance_transform_one_way(image,distance_link_i,distance_link_j,distance_link_k);
00132 
00133   // Flip to achieve high to low pass
00134   unsigned ni = image.ni(), nj = image.nj(), nk = image.nk();
00135   vil3d_image_view<float> flip_image(image.memory_chunk(),
00136                                      &image(ni-1,nj-1,nk-1), ni,nj,nk,1,
00137                                      -image.istep(), -image.jstep(), -image.kstep(),
00138                                      image.nplanes());
00139   vil3d_distance_transform_one_way(flip_image,distance_link_i,distance_link_j,distance_link_k);
00140 }
00141 
00142 //: Compute distance transform in 3d from zeros in original image.
00143 //  Image is assumed to be filled with max_dist where
00144 //  there is background, and zero in the places of interest.
00145 //  On exit, the values are the 8-connected distance to the
00146 //  nearest original zero region.
00147 void vil3d_distance_transform_with_dir(vil3d_image_view<float>& image,
00148                                        vil3d_image_view<vil_rgb<float> >& orient,
00149                                        const float distance_link_i,
00150                                        const float distance_link_j,
00151                                        const float distance_link_k)
00152 {
00153   // Low to high pass
00154   vil3d_distance_transform_one_way_with_dir(image,orient,distance_link_i,distance_link_j,distance_link_k);
00155 
00156   // Flip to achieve high to low pass
00157   unsigned ni = image.ni(), nj = image.nj(), nk = image.nk();
00158   vil3d_image_view<float> flip_image(image.memory_chunk(),
00159                                      &image(ni-1,nj-1,nk-1), ni,nj,nk,1,
00160                                      -image.istep(), -image.jstep(), -image.kstep(),
00161                                      image.nplanes());
00162 
00163   // reverse the directions
00164   vil3d_image_view<vil_rgb<float> >::iterator it = orient.begin();
00165   while (it != orient.end()) {
00166     vil_rgb<float>& v = *it;
00167     v*=-1.0;
00168     it++;
00169   }
00170 
00171   //Flip the directions too
00172   vil3d_image_view<vil_rgb<float> > flip_orient(orient.memory_chunk(),
00173                                                 &orient(ni-1,nj-1,nk-1), ni,nj,nk,1,
00174                                                 -orient.istep(), -orient.jstep(), -orient.kstep(),
00175                                                 orient.nplanes());
00176 
00177 
00178   vil3d_distance_transform_one_way_with_dir(flip_image,flip_orient,distance_link_i,distance_link_j,distance_link_k);
00179 }
00180 
00181 //: Compute directed 3D distance function from zeros in original image.
00182 //  Image is assumed to be filled with max_dist where there is
00183 //  background, and zero at the places of interest.
00184 //  On exit, the values are the 8-connected distance to the nearest
00185 //  original zero region above or to the left of current point.
00186 //  One pass of distance transform, going from low to high i,j,k.
00187 void vil3d_distance_transform_one_way(vil3d_image_view<float>& image,
00188                                       const float distance_link_i,
00189                                       const float distance_link_j,
00190                                       const float distance_link_k)
00191 {
00192   assert(image.nplanes()==1);
00193   unsigned ni = image.ni();
00194   unsigned nj = image.nj();
00195   unsigned nk = image.nk();
00196   unsigned ni2 = ni-2;
00197   unsigned nj2 = nj-2;
00198 
00199   vcl_ptrdiff_t istep = image.istep(), jstep = image.jstep(), kstep = image.kstep();
00200   vcl_ptrdiff_t o1 = -istep, o2 = -jstep-istep, o3 = -jstep, o4 = -jstep+istep;
00201   vcl_ptrdiff_t o5 = -kstep, o6 = -kstep-istep, o7 = -kstep-jstep-istep;
00202   vcl_ptrdiff_t o8 = -kstep-jstep, o9 = -kstep-jstep+istep, o10 = -kstep+istep;
00203   vcl_ptrdiff_t o11 = -kstep+jstep+istep, o12 = -kstep+jstep, o13 = -kstep+jstep-istep;
00204 
00205   float *page0 = image.origin_ptr();
00206 
00207   const float distance_link_ij=vcl_sqrt(distance_link_i*distance_link_i+distance_link_j*distance_link_j);
00208   const float distance_link_ik=vcl_sqrt(distance_link_i*distance_link_i+distance_link_k*distance_link_k);
00209   const float distance_link_jk=vcl_sqrt(distance_link_j*distance_link_j+distance_link_k*distance_link_k);
00210   const float distance_link_ijk=vcl_sqrt(distance_link_i*distance_link_i+distance_link_j*distance_link_j+distance_link_k*distance_link_k);
00211 
00212   // Process the first page
00213   float *p0 = page0 + istep;
00214 
00215   // Process the first row of first page
00216   for (unsigned i=0;i<=ni2;++i,p0+=istep)
00217   {
00218     *p0 = vcl_min(p0[-istep]+distance_link_i,*p0);
00219   }
00220 
00221   // Process subsequent rows of first page
00222   float *row0 = page0+jstep;
00223 
00224   for (unsigned j=1;j<nj;++j,row0+=jstep)
00225   {
00226     // for first column - special case
00227     *row0 = vcl_min(row0[o3]+distance_link_j,*row0);
00228     *row0 = vcl_min(row0[o4]+distance_link_ij,*row0);
00229 
00230     // for subsequent columns
00231     float *p0 = row0+istep;
00232     for (unsigned i=0;i<ni2;i++,p0+=istep)
00233     {
00234       *p0 = vcl_min(p0[o1]+distance_link_i ,*p0);  // (-1,0)
00235       *p0 = vcl_min(p0[o2]+distance_link_ij,*p0);  // (-1,-1)
00236       *p0 = vcl_min(p0[o3]+distance_link_j ,*p0);  // (0,-1)
00237       *p0 = vcl_min(p0[o4]+distance_link_ij,*p0);  // (1,-1)
00238     }
00239 
00240     // for last column - special case
00241     *p0 = vcl_min(p0[o1]+distance_link_i ,*p0);  // (-1,0)
00242     *p0 = vcl_min(p0[o2]+distance_link_ij,*p0);  // (-1,-1)
00243     *p0 = vcl_min(p0[o3]+distance_link_j ,*p0);  // (0,-1)
00244   }
00245 
00246   // process subsequent pages
00247   page0 += kstep;
00248   for (unsigned k=1;k<nk;k++,page0+=kstep)
00249   {
00250     row0 = page0;
00251 
00252     // first row is still special, and this is first column of first row
00253     *row0 = vcl_min(row0[o5] +distance_link_k, *row0);
00254     *row0 = vcl_min(row0[o10]+distance_link_ik,*row0);
00255     *row0 = vcl_min(row0[o11]+distance_link_ijk,*row0);
00256     *row0 = vcl_min(row0[o12]+distance_link_jk,*row0);
00257 
00258     float *p0 = row0+istep;
00259     // subsequent columns of first row
00260     for (unsigned i=0;i<ni2;i++,p0+=istep)
00261     {
00262       *p0 = vcl_min(p0[o1] +distance_link_i ,*p0);
00263       *p0 = vcl_min(p0[o5] +distance_link_k ,*p0);
00264       *p0 = vcl_min(p0[o6] +distance_link_ik,*p0);
00265       *p0 = vcl_min(p0[o10]+distance_link_ik,*p0);
00266       *p0 = vcl_min(p0[o11]+distance_link_ijk,*p0);
00267       *p0 = vcl_min(p0[o12]+distance_link_jk,*p0);
00268       *p0 = vcl_min(p0[o13]+distance_link_ijk,*p0);
00269     }
00270 
00271     // last column of first row
00272     *p0 = vcl_min(p0[o1] +distance_link_i ,*p0);
00273     *p0 = vcl_min(p0[o5] +distance_link_k ,*p0);
00274     *p0 = vcl_min(p0[o6] +distance_link_ik,*p0);
00275     *p0 = vcl_min(p0[o12]+distance_link_jk,*p0);
00276     *p0 = vcl_min(p0[o13]+distance_link_ijk,*p0);
00277 
00278     // process subsequent rows
00279     row0 += jstep;
00280 
00281     for (unsigned j=0;j<nj2;j++,row0+=jstep)
00282     {
00283       // again first column is special case
00284       *row0 = vcl_min(row0[o3] +distance_link_j, *row0);
00285       *row0 = vcl_min(row0[o4] +distance_link_ij,*row0);
00286       *row0 = vcl_min(row0[o5] +distance_link_k, *row0);
00287       *row0 = vcl_min(row0[o8] +distance_link_jk,*row0);
00288       *row0 = vcl_min(row0[o9] +distance_link_ijk,*row0);
00289       *row0 = vcl_min(row0[o10]+distance_link_ik,*row0);
00290       *row0 = vcl_min(row0[o11]+distance_link_ijk,*row0);
00291       *row0 = vcl_min(row0[o12]+distance_link_jk,*row0);
00292 
00293       // process subsequent columns
00294       p0 = row0 + istep;
00295       for (unsigned i=0;i<ni2;i++,p0+=istep)
00296       {
00297         *p0 = vcl_min(p0[o1] +distance_link_i, *p0);
00298         *p0 = vcl_min(p0[o2] +distance_link_ij,*p0);
00299         *p0 = vcl_min(p0[o3] +distance_link_j, *p0);
00300         *p0 = vcl_min(p0[o4] +distance_link_ij,*p0);
00301         *p0 = vcl_min(p0[o5] +distance_link_k, *p0);
00302         *p0 = vcl_min(p0[o6] +distance_link_ik,*p0);
00303         *p0 = vcl_min(p0[o7] +distance_link_ijk,*p0);
00304         *p0 = vcl_min(p0[o8] +distance_link_jk,*p0);
00305         *p0 = vcl_min(p0[o9] +distance_link_ijk,*p0);
00306         *p0 = vcl_min(p0[o10]+distance_link_ik,*p0);
00307         *p0 = vcl_min(p0[o11]+distance_link_ijk,*p0);
00308         *p0 = vcl_min(p0[o12]+distance_link_jk,*p0);
00309         *p0 = vcl_min(p0[o13]+distance_link_ijk,*p0);
00310       }
00311 
00312       // last column
00313       *p0 = vcl_min(p0[o1] +distance_link_i, *p0);
00314       *p0 = vcl_min(p0[o2] +distance_link_ij,*p0);
00315       *p0 = vcl_min(p0[o3] +distance_link_j, *p0);
00316       *p0 = vcl_min(p0[o5] +distance_link_k, *p0);
00317       *p0 = vcl_min(p0[o6] +distance_link_ik,*p0);
00318       *p0 = vcl_min(p0[o7] +distance_link_ijk,*p0);
00319       *p0 = vcl_min(p0[o8] +distance_link_jk,*p0);
00320       *p0 = vcl_min(p0[o12]+distance_link_jk,*p0);
00321       *p0 = vcl_min(p0[o13]+distance_link_ijk,*p0);
00322     }
00323 
00324     // process last row
00325 
00326     // process fist column of last row
00327     *row0 = vcl_min(row0[o3] +distance_link_j, *row0);
00328     *row0 = vcl_min(row0[o4] +distance_link_ij,*row0);
00329     *row0 = vcl_min(row0[o5] +distance_link_k, *row0);
00330     *row0 = vcl_min(row0[o8] +distance_link_jk,*row0);
00331     *row0 = vcl_min(row0[o9] +distance_link_ijk,*row0);
00332     *row0 = vcl_min(row0[o10]+distance_link_ik,*row0);
00333 
00334     // subsequent columns of last row
00335     p0 = row0 + istep;
00336     for (unsigned i=0;i<ni2;i++,p0+=istep)
00337     {
00338       *p0 = vcl_min(p0[o1] +distance_link_i, *p0);
00339       *p0 = vcl_min(p0[o2] +distance_link_ij,*p0);
00340       *p0 = vcl_min(p0[o3] +distance_link_j, *p0);
00341       *p0 = vcl_min(p0[o4] +distance_link_ij,*p0);
00342       *p0 = vcl_min(p0[o5] +distance_link_k, *p0);
00343       *p0 = vcl_min(p0[o6] +distance_link_ik,*p0);
00344       *p0 = vcl_min(p0[o7] +distance_link_ijk,*p0);
00345       *p0 = vcl_min(p0[o8] +distance_link_jk,*p0);
00346       *p0 = vcl_min(p0[o9] +distance_link_ijk,*p0);
00347       *p0 = vcl_min(p0[o10]+distance_link_ik,*p0);
00348     }
00349 
00350     // last column of last row
00351     *p0 = vcl_min(p0[o1] +distance_link_i, *p0);
00352     *p0 = vcl_min(p0[o2] +distance_link_ij,*p0);
00353     *p0 = vcl_min(p0[o3] +distance_link_j, *p0);
00354     *p0 = vcl_min(p0[o5] +distance_link_k, *p0);
00355     *p0 = vcl_min(p0[o6] +distance_link_ik,*p0);
00356     *p0 = vcl_min(p0[o7] +distance_link_ijk,*p0);
00357     *p0 = vcl_min(p0[o8] +distance_link_jk,*p0);
00358   }
00359 }
00360 
00361 float vil3d_min_comp(float const& a, float const& b, bool& comp)
00362 {
00363   if (a < b)
00364     comp=true;
00365   else
00366     comp=false;
00367   return vcl_min(a,b);
00368 }
00369 
00370 //: Compute directed 3D distance function from zeros in original image.
00371 //  Image is assumed to be filled with max_dist where there is
00372 //  background, and zero at the places of interest.
00373 //  Directions are assumed to be filled with max_dist.
00374 //  On exit, the values are the 8-connected distance to the nearest
00375 //  original zero region above or to the left of current point. The
00376 //  direction shows the relative position of the closest pixel with value 0.
00377 //  e.g. pixel (10,10,10) has vector (-2,-2,-2), so the closest 0 is at (8,8,8).
00378 //  One pass of distance transform, going from low to high i,j,k.
00379 void vil3d_distance_transform_one_way_with_dir(vil3d_image_view<float>& image,
00380                                                vil3d_image_view<vil_rgb<float> >& orient,
00381                                                const float distance_link_i,
00382                                                const float distance_link_j,
00383                                                const float distance_link_k)
00384 {
00385   assert(image.nplanes()==1);
00386   unsigned ni = image.ni();
00387   unsigned nj = image.nj();
00388   unsigned nk = image.nk();
00389   assert(ni == orient.ni() && nj == orient.nj() && nk == orient.nk());
00390   unsigned ni2 = ni-2;
00391   unsigned nj2 = nj-2;
00392 
00393   vcl_ptrdiff_t istep = image.istep(), jstep = image.jstep(), kstep = image.kstep();
00394   vcl_ptrdiff_t orient_istep = orient.istep(), orient_jstep = orient.jstep(), orient_kstep = orient.kstep();
00395 
00396   vcl_ptrdiff_t o1 = -istep, o2 = -jstep-istep, o3 = -jstep, o4 = -jstep+istep;
00397   vcl_ptrdiff_t o5 = -kstep, o6 = -kstep-istep, o7 = -kstep-jstep-istep;
00398   vcl_ptrdiff_t o8 = -kstep-jstep, o9 = -kstep-jstep+istep, o10 = -kstep+istep;
00399   vcl_ptrdiff_t o11 = -kstep+jstep+istep, o12 = -kstep+jstep, o13 = -kstep+jstep-istep;
00400 
00401   vcl_ptrdiff_t oo1 = -orient_istep;
00402   vcl_ptrdiff_t oo2 = -orient_jstep-orient_istep;
00403   vcl_ptrdiff_t oo3 = -orient_jstep;
00404   vcl_ptrdiff_t oo4 = -orient_jstep+orient_istep;
00405   vcl_ptrdiff_t oo5 = -orient_kstep;
00406   vcl_ptrdiff_t oo6 = -orient_kstep-orient_istep;
00407   vcl_ptrdiff_t oo7 = -orient_kstep-orient_jstep-orient_istep;
00408   vcl_ptrdiff_t oo8 = -orient_kstep-orient_jstep;
00409   vcl_ptrdiff_t oo9 = -orient_kstep-orient_jstep+orient_istep;
00410   vcl_ptrdiff_t oo10 = -orient_kstep+orient_istep;
00411   vcl_ptrdiff_t oo11 = -orient_kstep+orient_jstep+orient_istep;
00412   vcl_ptrdiff_t oo12 = -orient_kstep+orient_jstep;
00413   vcl_ptrdiff_t oo13 = -orient_kstep+orient_jstep-orient_istep;
00414 
00415 
00416   // distance vectors to the neighbors of a pixel
00417   vil_rgb<float> v1(1,0,0);
00418   vil_rgb<float> v2(1,1,0);
00419   vil_rgb<float> v3(0,1,0);
00420   vil_rgb<float> v4(-1,1,0);
00421   vil_rgb<float> v5(0,0,1);
00422   vil_rgb<float> v6(1,0,1);
00423   vil_rgb<float> v7(1,1,1);
00424   vil_rgb<float> v8(0,1,1);
00425   vil_rgb<float> v9(-1,1,1);
00426   vil_rgb<float> v10(-1,0,1);
00427   vil_rgb<float> v11(-1,-1,1);
00428   vil_rgb<float> v12(0,-1,1);
00429   vil_rgb<float> v13(1,-1,1);
00430 
00431   float *page0 = image.origin_ptr();
00432   vil_rgb<float> *orient_page0 = orient.origin_ptr();
00433 
00434   const float distance_link_ij=vcl_sqrt(distance_link_i*distance_link_i+distance_link_j*distance_link_j);
00435   const float distance_link_ik=vcl_sqrt(distance_link_i*distance_link_i+distance_link_k*distance_link_k);
00436   const float distance_link_jk=vcl_sqrt(distance_link_j*distance_link_j+distance_link_k*distance_link_k);
00437   const float distance_link_ijk=vcl_sqrt(distance_link_i*distance_link_i+distance_link_j*distance_link_j+distance_link_k*distance_link_k);
00438 
00439   // Process the first page
00440   float *p0 = page0 + istep;
00441   vil_rgb<float> *orient_p0 = orient_page0 + orient_istep;
00442 
00443   bool found;  // set to true if a smaller value found and to be replaced at the pixel
00444 
00445   // Process the first row of first page
00446   for (unsigned i=0;i<=ni2;++i,p0+=istep,orient_p0+=orient_istep)
00447   {
00448     *p0 = vil3d_min_comp(p0[-istep]+distance_link_i,*p0,found);
00449     if (found) *orient_p0 = orient_p0[-orient_istep]+v1;
00450   }
00451 
00452   // Process subsequent rows of first page
00453   float *row0 = page0+jstep;
00454   vil_rgb<float> *orient_row0 = orient_page0 + orient_jstep;
00455 
00456   for (unsigned j=1;j<nj;++j,row0+=jstep,orient_row0+=orient_jstep)
00457   {
00458     // for first column - special case
00459     *row0 = vil3d_min_comp(row0[o3]+distance_link_j,*row0,found);
00460     if (found) *orient_row0=orient_row0[oo3]+v3;
00461 
00462     *row0 = vil3d_min_comp(row0[o4]+distance_link_ij,*row0,found);
00463     if (found) *orient_row0=orient_row0[oo4]+v4;
00464 
00465     // for subsequent columns
00466     float *p0 = row0+istep;
00467     vil_rgb<float> *orient_p0 = orient_row0 + orient_istep;
00468     for (unsigned i=0;i<ni2;i++,p0+=istep,orient_p0+=orient_istep)
00469     {
00470       *p0 = vil3d_min_comp(p0[o1]+distance_link_i ,*p0,found);  // (-1,0)
00471       if (found) *orient_p0=orient_p0[oo1]+v1;
00472       *p0 = vil3d_min_comp(p0[o2]+distance_link_ij,*p0,found);  // (-1,-1)
00473       if (found) *orient_p0=orient_p0[oo2]+v2;
00474       *p0 = vil3d_min_comp(p0[o3]+distance_link_j ,*p0,found);  // (0,-1)
00475       if (found) *orient_p0=orient_p0[oo3]+v3;
00476       *p0 = vil3d_min_comp(p0[o4]+distance_link_ij,*p0,found);  // (1,-1)
00477       if (found) *orient_p0=orient_p0[oo4]+v4;
00478     }
00479 
00480     // for last column - special case
00481     *p0 = vil3d_min_comp(p0[o1]+distance_link_i ,*p0,found);  // (-1,0)
00482     if (found) *orient_p0=orient_p0[oo1]+v1;
00483     *p0 = vil3d_min_comp(p0[o2]+distance_link_ij,*p0,found);  // (-1,-1)
00484     if (found) *orient_p0=orient_p0[oo2]+v2;
00485     *p0 = vil3d_min_comp(p0[o3]+distance_link_j ,*p0,found);  // (0,-1)
00486     if (found) *orient_p0=orient_p0[oo3]+v3;
00487   }
00488 
00489   // process subsequent pages
00490   page0 += kstep;
00491   orient_page0+=orient_kstep;
00492   for (unsigned k=1;k<nk;k++,page0+=kstep, orient_page0+=orient_kstep)
00493   {
00494     row0 = page0;
00495     orient_row0 = orient_page0;
00496     // first row is still special, and this is first column of first row
00497     *row0 = vil3d_min_comp(row0[o5] +distance_link_k, *row0,found);
00498     if (found) *orient_row0 = orient_row0[oo5]+v5;
00499     *row0 = vil3d_min_comp(row0[o10]+distance_link_ik,*row0,found);
00500     if (found) *orient_row0 = orient_row0[oo10]+v10;
00501     *row0 = vil3d_min_comp(row0[o11]+distance_link_ijk,*row0,found);
00502     if (found) *orient_row0 = orient_row0[oo11]+v11;
00503     *row0 = vil3d_min_comp(row0[o12]+distance_link_jk,*row0,found);
00504     if (found) *orient_row0 = orient_row0[oo12]+v12;
00505 
00506     float *p0 = row0+istep;
00507     vil_rgb<float> *orient_p0 = orient_row0+orient_istep;
00508     // subsequent columns of first row
00509     for (unsigned i=0;i<ni2;i++,p0+=istep,orient_p0+=orient_istep)
00510     {
00511       *p0 = vil3d_min_comp(p0[o1] +distance_link_i ,*p0,found);
00512       if (found) *orient_p0=orient_p0[oo1]+v1;
00513       *p0 = vil3d_min_comp(p0[o5] +distance_link_k ,*p0,found);
00514       if (found) *orient_p0=orient_p0[oo5]+v5;
00515       *p0 = vil3d_min_comp(p0[o6] +distance_link_ik,*p0,found);
00516       if (found) *orient_p0=orient_p0[oo6]+v6;
00517       *p0 = vil3d_min_comp(p0[o10]+distance_link_ik,*p0,found);
00518       if (found) *orient_p0=orient_p0[oo10]+v10;
00519       *p0 = vil3d_min_comp(p0[o11]+distance_link_ijk,*p0,found);
00520       if (found) *orient_p0=orient_p0[oo11]+v11;
00521       *p0 = vil3d_min_comp(p0[o12]+distance_link_jk,*p0,found);
00522       if (found) *orient_p0=orient_p0[oo12]+v12;
00523       *p0 = vil3d_min_comp(p0[o13]+distance_link_ijk,*p0,found);
00524       if (found) *orient_p0=orient_p0[oo13]+v13;
00525     }
00526 
00527     // last column of first row
00528     *p0 = vil3d_min_comp(p0[o1] +distance_link_i ,*p0,found);
00529     if (found) *orient_p0=orient_p0[oo1]+v1;
00530     *p0 = vil3d_min_comp(p0[o5] +distance_link_k ,*p0,found);
00531     if (found) *orient_p0=orient_p0[oo5]+v5;
00532     *p0 = vil3d_min_comp(p0[o6] +distance_link_ik,*p0,found);
00533     if (found) *orient_p0=orient_p0[oo6]+v6;
00534     *p0 = vil3d_min_comp(p0[o12]+distance_link_jk,*p0,found);
00535     if (found) *orient_p0=orient_p0[oo12]+v12;
00536     *p0 = vil3d_min_comp(p0[o13]+distance_link_ijk,*p0,found);
00537     if (found) *orient_p0=orient_p0[oo13]+v13;
00538 
00539     // process subsequent rows
00540     row0 += jstep;
00541     orient_row0 += orient_jstep;
00542     for (unsigned j=0;j<nj2;j++,row0+=jstep,orient_row0+=orient_jstep)
00543     {
00544       // again first column is special case
00545       *row0 = vil3d_min_comp(row0[o3] +distance_link_j, *row0,found);
00546       if (found) *orient_row0=orient_row0[oo3]+v3;
00547       *row0 = vil3d_min_comp(row0[o4] +distance_link_ij,*row0,found);
00548       if (found) *orient_row0=orient_row0[oo4]+v4;
00549       *row0 = vil3d_min_comp(row0[o5] +distance_link_k, *row0,found);
00550       if (found) *orient_row0=orient_row0[oo5]+v5;
00551       *row0 = vil3d_min_comp(row0[o8] +distance_link_jk,*row0,found);
00552       if (found) *orient_row0=orient_row0[oo8]+v8;
00553       *row0 = vil3d_min_comp(row0[o9] +distance_link_ijk,*row0,found);
00554       if (found) *orient_row0=orient_row0[oo9]+v9;
00555       *row0 = vil3d_min_comp(row0[o10]+distance_link_ik,*row0,found);
00556       if (found) *orient_row0=orient_row0[oo10]+v10;
00557       *row0 = vil3d_min_comp(row0[o11]+distance_link_ijk,*row0,found);
00558       if (found) *orient_row0=orient_row0[oo11]+v11;
00559       *row0 = vil3d_min_comp(row0[o12]+distance_link_jk,*row0,found);
00560       if (found) *orient_row0=orient_row0[oo12]+v12;
00561 
00562       // process subsequent columns
00563       p0 = row0 + istep;
00564       orient_p0 = orient_row0 + orient_istep;
00565       for (unsigned i=0;i<ni2;i++,p0+=istep,orient_p0+=orient_istep)
00566       {
00567         *p0 = vil3d_min_comp(p0[o1] +distance_link_i, *p0,found);
00568         if (found) *orient_p0=orient_p0[oo1]+v1;
00569         *p0 = vil3d_min_comp(p0[o2] +distance_link_ij,*p0,found);
00570         if (found) *orient_p0=orient_p0[oo2]+v2;
00571         *p0 = vil3d_min_comp(p0[o3] +distance_link_j, *p0,found);
00572         if (found) *orient_p0=orient_p0[oo3]+v3;
00573         *p0 = vil3d_min_comp(p0[o4] +distance_link_ij,*p0,found);
00574         if (found) *orient_p0=orient_p0[oo4]+v4;
00575         *p0 = vil3d_min_comp(p0[o5] +distance_link_k, *p0,found);
00576         if (found) *orient_p0=orient_p0[oo5]+v5;
00577         *p0 = vil3d_min_comp(p0[o6] +distance_link_ik,*p0,found);
00578         if (found) *orient_p0=orient_p0[oo6]+v6;
00579         *p0 = vil3d_min_comp(p0[o7] +distance_link_ijk,*p0,found);
00580         if (found) *orient_p0=orient_p0[oo7]+v7;
00581         *p0 = vil3d_min_comp(p0[o8] +distance_link_jk,*p0,found);
00582         if (found) *orient_p0=orient_p0[oo8]+v8;
00583         *p0 = vil3d_min_comp(p0[o9] +distance_link_ijk,*p0,found);
00584         if (found) *orient_p0=orient_p0[oo9]+v9;
00585         *p0 = vil3d_min_comp(p0[o10]+distance_link_ik,*p0,found);
00586         if (found) *orient_p0=orient_p0[oo10]+v10;
00587         *p0 = vil3d_min_comp(p0[o11]+distance_link_ijk,*p0,found);
00588         if (found) *orient_p0=orient_p0[oo11]+v11;
00589         *p0 = vil3d_min_comp(p0[o12]+distance_link_jk,*p0,found);
00590         if (found) *orient_p0=orient_p0[oo12]+v12;
00591         *p0 = vil3d_min_comp(p0[o13]+distance_link_ijk,*p0,found);
00592         if (found) *orient_p0=orient_p0[oo13]+v13;
00593       }
00594 
00595       // last column
00596       *p0 = vil3d_min_comp(p0[o1] +distance_link_i, *p0,found);
00597       if (found) *orient_p0=orient_p0[oo1]+v1;
00598       *p0 = vil3d_min_comp(p0[o2] +distance_link_ij,*p0,found);
00599       if (found) *orient_p0=orient_p0[oo2]+v2;
00600       *p0 = vil3d_min_comp(p0[o3] +distance_link_j, *p0,found);
00601       if (found) *orient_p0=orient_p0[oo3]+v3;
00602       *p0 = vil3d_min_comp(p0[o5] +distance_link_k, *p0,found);
00603       if (found) *orient_p0=orient_p0[oo5]+v5;
00604       *p0 = vil3d_min_comp(p0[o6] +distance_link_ik,*p0,found);
00605       if (found) *orient_p0=orient_p0[oo6]+v6;
00606       *p0 = vil3d_min_comp(p0[o7] +distance_link_ijk,*p0,found);
00607       if (found) *orient_p0=orient_p0[oo7]+v7;
00608       *p0 = vil3d_min_comp(p0[o8] +distance_link_jk,*p0,found);
00609       if (found) *orient_p0=orient_p0[oo8]+v8;
00610       *p0 = vil3d_min_comp(p0[o12]+distance_link_jk,*p0,found);
00611       if (found) *orient_p0=orient_p0[oo12]+v12;
00612       *p0 = vil3d_min_comp(p0[o13]+distance_link_ijk,*p0,found);
00613       if (found) *orient_p0=orient_p0[oo13]+v13;
00614     }
00615 
00616     // process last row
00617 
00618     // process fist column of last row
00619     *row0 = vil3d_min_comp(row0[o3] +distance_link_j, *row0,found);
00620     if (found) *orient_row0=orient_row0[oo3]+v3;
00621     *row0 = vil3d_min_comp(row0[o4] +distance_link_ij,*row0,found);
00622     if (found) *orient_row0=orient_row0[oo4]+v4;
00623     *row0 = vil3d_min_comp(row0[o5] +distance_link_k, *row0,found);
00624     if (found) *orient_row0=orient_row0[oo5]+v5;
00625     *row0 = vil3d_min_comp(row0[o8] +distance_link_jk,*row0,found);
00626     if (found) *orient_row0=orient_row0[oo8]+v8;
00627     *row0 = vil3d_min_comp(row0[o9] +distance_link_ijk,*row0,found);
00628     if (found) *orient_row0=orient_row0[oo9]+v9;
00629     *row0 = vil3d_min_comp(row0[o10]+distance_link_ik,*row0,found);
00630     if (found) *orient_row0=orient_row0[oo10]+v10;
00631 
00632     // subsequent columns of last row
00633     p0 = row0 + istep;
00634     orient_p0 = orient_row0 + orient_istep;
00635     for (unsigned i=0;i<ni2;i++,p0+=istep,orient_p0+=orient_istep)
00636     {
00637       *p0 = vil3d_min_comp(p0[o1] +distance_link_i, *p0,found);
00638       if (found) *orient_p0=orient_p0[oo1]+v1;
00639       *p0 = vil3d_min_comp(p0[o2] +distance_link_ij,*p0,found);
00640       if (found) *orient_p0=orient_p0[oo2]+v2;
00641       *p0 = vil3d_min_comp(p0[o3] +distance_link_j, *p0,found);
00642       if (found) *orient_p0=orient_p0[oo3]+v3;
00643       *p0 = vil3d_min_comp(p0[o4] +distance_link_ij,*p0,found);
00644       if (found) *orient_p0=orient_p0[oo4]+v4;
00645       *p0 = vil3d_min_comp(p0[o5] +distance_link_k, *p0,found);
00646       if (found) *orient_p0=orient_p0[oo5]+v5;
00647       *p0 = vil3d_min_comp(p0[o6] +distance_link_ik,*p0,found);
00648       if (found) *orient_p0=orient_p0[oo6]+v6;
00649       *p0 = vil3d_min_comp(p0[o7] +distance_link_ijk,*p0,found);
00650       if (found) *orient_p0=orient_p0[oo7]+v7;
00651       *p0 = vil3d_min_comp(p0[o8] +distance_link_jk,*p0,found);
00652       if (found) *orient_p0=orient_p0[oo8]+v8;
00653       *p0 = vil3d_min_comp(p0[o9] +distance_link_ijk,*p0,found);
00654       if (found) *orient_p0=orient_p0[oo9]+v9;
00655       *p0 = vil3d_min_comp(p0[o10]+distance_link_ik,*p0,found);
00656       if (found) *orient_p0=orient_p0[oo10]+v10;
00657     }
00658 
00659     // last column of last row
00660     *p0 = vil3d_min_comp(p0[o1] +distance_link_i, *p0,found);
00661     if (found) *orient_p0=orient_p0[oo1]+v1;
00662     *p0 = vil3d_min_comp(p0[o2] +distance_link_ij,*p0,found);
00663     if (found) *orient_p0=orient_p0[oo2]+v2;
00664     *p0 = vil3d_min_comp(p0[o3] +distance_link_j, *p0,found);
00665     if (found) *orient_p0=orient_p0[oo3]+v3;
00666     *p0 = vil3d_min_comp(p0[o5] +distance_link_k, *p0,found);
00667     if (found) *orient_p0=orient_p0[oo5]+v5;
00668     *p0 = vil3d_min_comp(p0[o6] +distance_link_ik,*p0,found);
00669     if (found) *orient_p0=orient_p0[oo6]+v6;
00670     *p0 = vil3d_min_comp(p0[o7] +distance_link_ijk,*p0,found);
00671     if (found) *orient_p0=orient_p0[oo7]+v7;
00672     *p0 = vil3d_min_comp(p0[o8] +distance_link_jk,*p0,found);
00673     if (found) *orient_p0=orient_p0[oo8]+v8;
00674   }
00675 }
00676 
00677 
00678 //: Compute 3D distance function from true elements in mask.
00679 //  On exit, the values are the 8-connected distance to the
00680 //  nearest original zero region (or max_dist, if that is smaller).
00681 void vil3d_distance_transform(const vil3d_image_view<bool>& mask,
00682                               vil3d_image_view<float>& distance_image,
00683                               float max_dist)
00684 {
00685   distance_image.set_size(mask.ni(),mask.nj(),mask.nk());
00686   distance_image.fill(max_dist);
00687   //vil3d_fill_mask(distance_image,mask,0.0f); // function not yet written
00688 
00689   vil3d_distance_transform(distance_image);
00690 }
00691