contrib/mul/vil3d/algo/vil3d_fill_boundary.cxx
Go to the documentation of this file.
00001 #include "vil3d_fill_boundary.h"
00002 //:
00003 // \file
00004 // \brief Fill in contour bounded regions in slices of 3D image
00005 // \author Kola Babalola
00006 
00007 #include <vil3d/vil3d_image_view.h>
00008 #include <vcl_vector.h>
00009 #include <vcl_stack.h>
00010 #include <vil3d/vil3d_convert.h>
00011 #include <vil3d/algo/vil3d_threshold.h>
00012 
00013 //: Compute a mask where the regions in each slice of a 3D image bounded by contours are set to "on"
00014 void vil3d_fill_boundary(vil3d_image_view<bool>& bool_image)
00015 {
00016   unsigned ni = bool_image.ni();
00017   unsigned nj = bool_image.nj();
00018   unsigned nk = bool_image.nk();
00019   unsigned nplanes = bool_image.nplanes();
00020 
00021   // input image is binary, converted to int (need to speak to tim about data types accepted by threshold
00022   vil3d_image_view<int> image(ni,nj,nk,nplanes);
00023   vil3d_convert_cast(bool_image,image);
00024 
00025   vcl_ptrdiff_t istep = image.istep();
00026 
00027   // scan the image and look for a boundary pixel
00028   int *page0 = image.origin_ptr();
00029 
00030   int *p0 = page0;
00031 
00032   int boundary_label;
00033   int background_label = 2;
00034   for (unsigned int k = 0; k < nk; ++k)
00035   {
00036     boundary_label = 3;
00037     for (unsigned int j = 0; j < nj; ++j)
00038     {
00039       for (unsigned int i = 0; i < ni; ++i, p0+=istep)
00040       {
00041         if (image(i,j,k) == 1)
00042         {
00043           label_boundary_and_bkg(image,i,j,k,boundary_label,background_label);
00044           fill_boundary(image,j,k,boundary_label,background_label);
00045           boundary_label+=1;
00046           reset_background(image,background_label);
00047         }
00048       }
00049     }
00050   }
00051 
00052   // threshold the image to obtain the binary mask
00053   vil3d_threshold_above(image,bool_image,3);
00054 }
00055 
00056 //: Follow the current boundary in the current slice.
00057 //  labeling boundary pixels and background pixels that border the boundary.
00058 void label_boundary_and_bkg(vil3d_image_view<int> &image,int i,int j, int k, int boundary_label, int background_label)
00059 {
00060   unsigned ni = image.ni();
00061   unsigned nj = image.nj();
00062 
00063   vcl_vector<int> x_offset(8); vcl_vector<int> y_offset(8);
00064 
00065   vcl_vector<int> next_dir(8);
00066 
00067   // assign the x and y offsets for the 8-neighbourhood
00068   x_offset[0] = -1; y_offset[0] =  0;
00069   x_offset[1] = -1; y_offset[1] = -1;
00070   x_offset[2] = 0;  y_offset[2] = -1;
00071   x_offset[3] = 1;  y_offset[3] = -1;
00072   x_offset[4] = 1;  y_offset[4] =  0;
00073   x_offset[5] = 1;  y_offset[5] =  1;
00074   x_offset[6] = 0;  y_offset[6] =  1;
00075   x_offset[7] = -1; y_offset[7] =  1;
00076 
00077   // assign the offsets for the next direction to look in
00078   next_dir[0] = next_dir[1] = 7;//-istep+jstep;
00079   next_dir[2] = next_dir[3] = 1;//-istep-jstep;
00080   next_dir[4] = next_dir[5] = 3;//istep-jstep;
00081   next_dir[6] = next_dir[7] = 5;//istep+jstep;
00082 
00083   int m,offset=0;
00084   int i0 = i,j0 = j;
00085   int i1, j1;
00086 
00087   // check the 8-neighbourhood of the pixels on the boundary
00088 //  while (image(i0,j0,k) != boundary_label || (i!=i0 && j!=j0))
00089 //    while (image(i0,j0,k) != boundary_label || ((i==i0 && j==j0) && (offset != 0 || offset != 1)))
00090   while (image(i0,j0,k) != boundary_label || (i != i0 || j != j0) ||
00091          (i == i0 && j == j0 && offset == 7))
00092   {
00093     image(i0,j0,k) = boundary_label;
00094 
00095     for (m = 0; m < 8; ++m)
00096     {
00097       i1 = i0+x_offset[offset];
00098       j1 = j0+y_offset[offset];
00099       if (i1 >= int(ni) || j1 >= int(nj) || i1 < 0 || j1 < 0)
00100         offset = (offset+1)%8;
00101       else
00102       {
00103         if (image(i1,j1,k)==1 || image(i1,j1,k) == boundary_label) // this means we visit some
00104         {                                                          // pixels more than once.
00105           i0 = i1; j0 = j1;                                        // Needed for degenerate cases
00106           offset = next_dir[offset];
00107           break;
00108         }
00109         else if (image(i1,j1,k)==background_label)
00110         {
00111           offset = (offset+1)%8;
00112           break;
00113         }
00114         else
00115         {
00116           image(i1,j1,k) = background_label;
00117           offset = (offset+1)%8;
00118         }
00119       }
00120     }
00121   }
00122 }
00123 
00124 
00125 //:  Fill interior of current boundary.
00126 void fill_boundary(vil3d_image_view<int> &image, int j, int k, int boundary_label, int background_label)
00127 {
00128   unsigned ni = image.ni();
00129   unsigned nj = image.nj();
00130 
00131   vcl_stack<int> x_stack, y_stack;
00132   int i=0, m;
00133 
00134   // push all boundary pixels onto stack. Needed for degenerate cases
00135 
00136   for (;j<int(nj);++j,i=0) // Why do i=0 here instead of in normal place on next line? No idea...
00137     for (;i<int(ni);++i)
00138     {
00139       if (image(i,j,k) == boundary_label)
00140       {
00141         x_stack.push(i);
00142         y_stack.push(j);
00143       }
00144     }
00145 
00146   // assign the x and y offsets for the 8-neighbourhood
00147   vcl_vector<int> x_offset(8); vcl_vector<int> y_offset(8);
00148   x_offset[0] = -1; y_offset[0] =  0;
00149   x_offset[1] = -1; y_offset[1] = -1;
00150   x_offset[2] = 0;  y_offset[2] = -1;
00151   x_offset[3] = 1;  y_offset[3] = -1;
00152   x_offset[4] = 1;  y_offset[4] =  0;
00153   x_offset[5] = 1;  y_offset[5] =  1;
00154   x_offset[6] = 0;  y_offset[6] =  1;
00155   x_offset[7] = -1; y_offset[7] =  1;
00156 
00157   int i1,j1;
00158 
00159   // Starting from first pixel on boundary, iteratively fill neighbours in boundary
00160   while (!x_stack.empty())
00161   {
00162     i = x_stack.top();
00163     j = y_stack.top();
00164     x_stack.pop();
00165     y_stack.pop();
00166     for (m = 0; m < 8; ++m)
00167     {
00168       i1 = i+x_offset[m];
00169       j1 = j+y_offset[m];
00170       if (i1<int(ni) && i1>=0 && j1<int(nj) && j1 >=0)
00171       {
00172         if (image(i1,j1,k) != boundary_label && image(i1,j1,k) != background_label)
00173         {
00174           image(i1,j1,k) = boundary_label;
00175           x_stack.push(i1);
00176           y_stack.push(j1);
00177         }
00178       }
00179     }
00180   }
00181 }
00182 
00183 //:  Reset background pixels to 0
00184 void reset_background(vil3d_image_view<int> &image, int background_label)
00185 {
00186   for (unsigned k = 0; k < image.nk(); k++)
00187   {
00188     for (unsigned j = 0; j < image.nj(); j++)
00189     {
00190       for (unsigned i = 0; i < image.ni(); i++)
00191       {
00192         if (image(i,j,k) == background_label)
00193           image(i,j,k) = 0;
00194       }
00195     }
00196   }
00197   return;
00198 }