core/vil/algo/vil_trace_8con_boundary.cxx
Go to the documentation of this file.
00001 //:
00002 // \file
00003 // \brief Function to trace 8-connected boundary around region in bool image
00004 // \author Tim Cootes
00005 
00006 #include "vil_trace_8con_boundary.h"
00007 
00008 //: Move (i,j) to next boundary point
00009 //  Start looking in direction dir (0=++x,1=++y,2=--x,3=--y)
00010 //  *p is current point (i,j).
00011 //  On exit (i,j) and p are updated to move to neighbour
00012 inline void vil_next_8con_boundary_point(int& i, int& j, int& dir, const bool* &p,
00013                                          int ni1, int nj1,
00014                                          vcl_ptrdiff_t istep, vcl_ptrdiff_t jstep)
00015 {
00016   for (int k=0;k<8;++k)
00017   {
00018     switch ((dir+k)%8)
00019     {
00020      case 0:   // Try at (i+1,j)
00021       if (i<ni1 && p[istep]) { ++i; p+=istep; dir=5; return; }
00022      case 1:   // Try at (i+1,j+1)
00023       if (i<ni1 && j<nj1 && p[istep+jstep]) {
00024         ++i; ++j; p+=(istep+jstep); dir=6; return; }
00025      case 2:   // Try at (i,j+1)
00026       if (j<nj1 && p[jstep]) { ++j; p+=jstep; dir=7; return; }
00027      case 3:   // Try at (i-1,j+1)
00028       if (i>0 && j<nj1 && p[jstep-istep]) {
00029         --i; ++j; p+=(jstep-istep); dir=0; return; }
00030      case 4:   // Try at (i-1,j)
00031       if (i>0 && p[-istep])  { --i; p-=istep; dir=1; return; }
00032      case 5:   // Try at (i-1,j-1)
00033       if (i>0 && j>0 && p[-jstep-istep]) {
00034         --i; --j; p+=(-jstep-istep); dir=2; return; }
00035      case 6:   // Try at (i,j-1)
00036       if (j>0 && p[-jstep])  { --j; p-=jstep; dir=3; return; }
00037      case 7:   // Try at (i+1,j-1)
00038       if (i<ni1 && j>0 && p[istep-jstep]) {
00039         ++i; --j; p+=(istep-jstep); dir=4; return; }
00040      default:
00041        break; // this can never be reached
00042     }
00043   }
00044 }
00045 
00046 static inline int vil_first_direction(unsigned int i, unsigned int j, const vil_image_view<bool>& image)
00047 {
00048   if (i>=image.ni() || j>=image.nj() || !image(i,j)) return -1;
00049 
00050   // Find first neighbour outside
00051 
00052   // Check for border pixels
00053   if (i+1>=image.ni()) return 0;
00054   if (j+1>=image.nj()) return 2;
00055   if (i==0) return 4;
00056   if (j==0) return 6;
00057 
00058   if (!image(i+1,j))   return 0;
00059   if (!image(i+1,j+1)) return 1;
00060   if (!image(i,j+1))   return 2;
00061   if (!image(i-1,j+1)) return 3;
00062   if (!image(i-1,j))   return 4;
00063   if (!image(i-1,j-1)) return 5;
00064   if (!image(i,j-1))   return 6;
00065   if (!image(i+1,j-1)) return 7;
00066 
00067   return -1; // No neighbours are outside
00068 }
00069 
00070 
00071 //: Trace 8-connected boundary around region in boolean image
00072 //  Assumes that (i0,j0) is a boundary point.
00073 //  Searches for the boundary pixels and runs around until it gets back to beginning.
00074 //  On exit the boundary points are given by (bi[k],bj[k])
00075 void vil_trace_8con_boundary(vcl_vector<int>& bi, vcl_vector<int>& bj,
00076                              const vil_image_view<bool>& image,
00077                              int i0, int j0)
00078 {
00079   bi.resize(0); bj.resize(0);
00080   unsigned int ni1 = image.ni()-1;
00081   unsigned int nj1 = image.nj()-1;
00082   vcl_ptrdiff_t istep = image.istep(), jstep=image.jstep();
00083 
00084   int i = i0, j = j0;
00085   const bool* p = &image(i,j);
00086 
00087   // Check that p is a boundary pixel
00088   int dir = vil_first_direction(i,j,image);
00089 
00090   if (dir<0) return;  // Not a boundary point!
00091 
00092   do
00093   {
00094     bi.push_back(i); bj.push_back(j);
00095     vil_next_8con_boundary_point(i,j,dir,p,ni1,nj1,istep,jstep);
00096   }
00097   while (i!=i0 || j!=j0);
00098 
00099   if (bi.size()==1) return;  // Isolated pixel (how sad).
00100 
00101   // Got back to start.
00102   // However, if start is part of a 1 pixel wide line, we need to
00103   // investigate the other side of the line
00104   // To check for this, find the next boundary point and check that it
00105   // is the same as was found during the first pass
00106   // This can happen up to four times (I think) in worst case
00107   vil_next_8con_boundary_point(i,j,dir,p,ni1,nj1,istep,jstep);
00108   while (i!=bi[1] || j!=bj[1])
00109   {
00110     // Second pass is different from first
00111     // Investigate the other side of the blob
00112     bi.push_back(i0); bj.push_back(j0);
00113     do
00114     {
00115       bi.push_back(i); bj.push_back(j);
00116       vil_next_8con_boundary_point(i,j,dir,p,ni1,nj1,istep,jstep);
00117     }
00118     while (i!=i0 || j!=j0);
00119 
00120     vil_next_8con_boundary_point(i,j,dir,p,ni1,nj1,istep,jstep);
00121   }
00122 }