contrib/oxl/osl/osl_canny_base.cxx
Go to the documentation of this file.
00001 // This is oxl/osl/osl_canny_base.cxx
00002 #include "osl_canny_base.h"
00003 //:
00004 //  \file
00005 
00006 #include <osl/osl_canny_port.h>
00007 #include <vcl_cmath.h>
00008 #include <vcl_list.h>
00009 #include <vcl_cassert.h>
00010 
00011 //--------------------------------------------------------------
00012 
00013 osl_canny_base::osl_canny_base(float sigma, float low, float high, bool v)
00014   : xstart_(0), ystart_(0)
00015   , xsize_(0), ysize_(0)
00016 
00017   , smooth_(0)
00018   , dx_(0)
00019   , dy_(0)
00020   , grad_(0)
00021 
00022   , thick_(0)
00023   , thin_(0)
00024   , theta_(0)
00025 
00026   , junction_(0)
00027   , jx_(0)
00028   , jy_(0)
00029   , xjunc_(0)
00030   , yjunc_(0)
00031   , vlist_(0)
00032 
00033   , kernel_(0)
00034 {
00035   verbose =v;
00036   sigma_ = sigma;
00037   low_ = low;
00038   high_ = high;
00039 }
00040 
00041 //: Destructor does nothing at all.
00042 osl_canny_base::~osl_canny_base() {  }
00043 
00044 
00045 //-----------------------------------------------------------------------------
00046 
00047 //:
00048 // Following routine looking for connectiveness of edgel chains
00049 // and accounts for single pixel gaps in the chains.
00050 void osl_canny_base::Initial_follow(float * const *thin, int xsize, int ysize, float low,
00051                                     int x, int y,
00052                                     vcl_list<int> *xc,
00053                                     vcl_list<int> *yc,
00054                                     vcl_list<float> *grad)
00055 {
00056   // Make sure that we are not likely to overun the border of the image
00057   if ( (x<=0) || (x>=xsize-1) || (y<=0) || (y>=ysize-1) )
00058     return;
00059 
00060   // Add the current point to the coordinate lists, and delete from
00061   // the edge image
00062   xc->push_front(x);
00063   yc->push_front(y);
00064   grad->push_front(thin[x][y]);
00065   thin[x][y] = 0.0;
00066 
00067   // Now recursively look for connected eight-neighbours
00068   if ( thin[x][y-1] > low )
00069     Initial_follow(thin, xsize, ysize, low, x  ,y-1,xc,yc,grad);
00070   if ( thin[x-1][y  ] > low )
00071     Initial_follow(thin, xsize, ysize, low, x-1,y  ,xc,yc,grad);
00072   if ( thin[x  ][y+1] > low )
00073     Initial_follow(thin, xsize, ysize, low, x  ,y+1,xc,yc,grad);
00074   if ( thin[x+1][y  ] > low )
00075     Initial_follow(thin, xsize, ysize, low, x+1,y  ,xc,yc,grad);
00076   if ( thin[x+1][y-1] > low )
00077     Initial_follow(thin, xsize, ysize, low, x+1,y-1,xc,yc,grad);
00078   if ( thin[x-1][y-1] > low )
00079     Initial_follow(thin, xsize, ysize, low, x-1,y-1,xc,yc,grad);
00080   if ( thin[x-1][y+1] > low )
00081     Initial_follow(thin, xsize, ysize, low, x-1,y+1,xc,yc,grad);
00082   if ( thin[x+1][y+1] > low )
00083     Initial_follow(thin, xsize, ysize, low, x+1,y+1,xc,yc,grad);
00084 }
00085 
00086 
00087 //-----------------------------------------------------------------------------
00088 
00089 //:
00090 // Following routine looking for connectiveness of edgel chains
00091 // and accounts for single pixel gaps in the chains.
00092 void osl_canny_base::Final_follow(int x, int y,
00093                                   vcl_list<int> *xc,
00094                                   vcl_list<int> *yc,
00095                                   vcl_list<float> *grad,
00096                                   int reverse)
00097 {
00098   // Make sure that we do not overun the border of the image
00099   assert ( x>0 && y>0);
00100   assert ( (unsigned int)x+1<xsize_);
00101   assert ( (unsigned int)y+1<ysize_);
00102 
00103   // Add the current point to the coordinate lists, and delete from
00104   // the edge image
00105   if (!reverse) {
00106     xc->push_front(x);
00107     yc->push_front(y);
00108     grad->push_front(thin_[x][y]);
00109   }
00110   thin_[x][y] = 0.0;
00111 
00112   // Now recursively look for connected eight-neighbours
00113   if      ( (thin_[x  ][y-1]>low_) && (junction_[x  ][y-1]==0) )
00114     Final_follow(x,y-1,xc,yc,grad,0);
00115   else if ( (thin_[x-1][y  ]>low_) && (junction_[x-1][y  ]==0) )
00116     Final_follow(x-1,y,xc,yc,grad,0);
00117   else if ( (thin_[x  ][y+1]>low_) && (junction_[x  ][y+1]==0) )
00118     Final_follow(x,y+1,xc,yc,grad,0);
00119   else if ( (thin_[x+1][y  ]>low_) && (junction_[x+1][y  ]==0) )
00120     Final_follow(x+1,y,xc,yc,grad,0);
00121   else if ( (thin_[x+1][y-1]>low_) && (junction_[x+1][y-1]==0) )
00122     Final_follow(x+1,y-1,xc,yc,grad,0);
00123   else if ( (thin_[x-1][y-1]>low_) && (junction_[x-1][y-1]==0) )
00124     Final_follow(x-1,y-1,xc,yc,grad,0);
00125   else if ( (thin_[x-1][y+1]>low_) && (junction_[x-1][y+1]==0) )
00126     Final_follow(x-1,y+1,xc,yc,grad,0);
00127   else if ( (thin_[x+1][y+1]>low_) && (junction_[x+1][y+1]==0) )
00128     Final_follow(x+1,y+1,xc,yc,grad,0);
00129 
00130   // Else see if there is a junction nearby, and record it. The chain_no_
00131   // variable is used to prevent the same junction being inserted at both
00132   // ends of the EdgelChains when reversel occurs next to the junction
00133   // (in that case there will only be two stored points: the edge and the junction)
00134   else if ( junction_[x  ][y-1] && ((xc->size()>2)||(junction_[x  ][y-1]!=chain_no_)) ) {
00135     xc->push_front(jx_[x  ][y-1]);  yc->push_front(jy_[x  ][y-1]);  grad->push_front(jval_);
00136     junction_[x  ][y-1] = chain_no_;
00137   }
00138   else if ( junction_[x-1][y  ] && ((xc->size()>2)||(junction_[x-1][y  ]!=chain_no_)) ) {
00139     xc->push_front(jx_[x-1][y  ]);  yc->push_front(jy_[x-1][y  ]);  grad->push_front(jval_);
00140     junction_[x-1][y  ] = chain_no_;
00141   }
00142   else if ( junction_[x  ][y+1] && ((xc->size()>2)||(junction_[x  ][y+1]!=chain_no_)) ) {
00143     xc->push_front(jx_[x  ][y+1]);  yc->push_front(jy_[x  ][y+1]);  grad->push_front(jval_);
00144     junction_[x  ][y+1] = chain_no_;
00145   }
00146   else if ( junction_[x+1][y  ] && ((xc->size()>2)||(junction_[x+1][y  ]!=chain_no_)) ) {
00147     xc->push_front(jx_[x+1][y  ]);  yc->push_front(jy_[x+1][y  ]);  grad->push_front(jval_);
00148     junction_[x+1][y  ] = chain_no_;
00149   }
00150   else if ( junction_[x+1][y-1] && ((xc->size()>2)||(junction_[x+1][y-1]!=chain_no_)) ) {
00151     xc->push_front(jx_[x+1][y-1]);  yc->push_front(jy_[x+1][y-1]);  grad->push_front(jval_);
00152     junction_[x+1][y-1] = chain_no_;
00153   }
00154   else if ( junction_[x-1][y-1] && ((xc->size()>2)||(junction_[x-1][y-1]!=chain_no_)) ) {
00155     xc->push_front(jx_[x-1][y-1]);  yc->push_front(jy_[x-1][y-1]);  grad->push_front(jval_);
00156     junction_[x-1][y-1] = chain_no_;
00157   }
00158   else if ( junction_[x-1][y+1] && ((xc->size()>2)||(junction_[x-1][y+1]!=chain_no_)) ) {
00159     xc->push_front(jx_[x-1][y+1]);  yc->push_front(jy_[x-1][y+1]);  grad->push_front(jval_);
00160     junction_[x-1][y+1] = chain_no_;
00161   }
00162   else if ( junction_[x+1][y+1] && ((xc->size()>2)||(junction_[x+1][y+1]!=chain_no_)) ) {
00163     xc->push_front(jx_[x+1][y+1]);  yc->push_front(jy_[x+1][y+1]);  grad->push_front(jval_);
00164     junction_[x+1][y+1] = chain_no_;
00165   }
00166 }
00167 
00168 //-----------------------------------------------------------------------------
00169 //
00170 //: Following routine looking for searching out junction clusters.
00171 //
00172 void osl_canny_base::Follow_junctions(int * const *junction,
00173                                       int x, int y,
00174                                       vcl_list<int> *xc,
00175                                       vcl_list<int> *yc)
00176 {
00177   // Add the current junction to the coordinate lists, and delete from
00178   // the junction image
00179   xc->push_front(x);
00180   yc->push_front(y);
00181   junction[x][y] = 0;
00182 
00183   // Now recursively look for connected eight-neighbours
00184   if ( junction[x  ][y-1] )
00185     Follow_junctions(junction,x  ,y-1,xc,yc);
00186   if ( junction[x-1][y  ] )
00187     Follow_junctions(junction,x-1,y  ,xc,yc);
00188   if ( junction[x  ][y+1] )
00189     Follow_junctions(junction,x  ,y+1,xc,yc);
00190   if ( junction[x+1][y  ] )
00191     Follow_junctions(junction,x+1,y  ,xc,yc);
00192   if ( junction[x+1][y-1] )
00193     Follow_junctions(junction,x+1,y-1,xc,yc);
00194   if ( junction[x-1][y-1] )
00195     Follow_junctions(junction,x-1,y-1,xc,yc);
00196   if ( junction[x-1][y+1] )
00197     Follow_junctions(junction,x-1,y+1,xc,yc);
00198   if ( junction[x+1][y+1] )
00199     Follow_junctions(junction,x+1,y+1,xc,yc);
00200 }
00201 
00202 
00203 //-----------------------------------------------------------------------------
00204 
00205 //: Finds which member of the lists lies closest to the centre of gravity of the lists.
00206 void osl_canny_base::Cluster_centre_of_gravity(int * const *jx, int * const *jy,
00207                                                vcl_list<int> &xc,
00208                                                vcl_list<int> &yc,
00209                                                int &x0, int &y0)
00210 {
00211   typedef vcl_list<int>::iterator it;
00212 
00213   if ( xc.empty() )
00214     return;
00215 
00216   // First find the CofG
00217   double x=0.0,y=0.0;
00218   for (it i=xc.begin(),j=yc.begin(); i!=xc.end() && j!=yc.end(); ++i, ++j) {
00219     //for (xc.reset(),yc.reset(); xc.next(),yc.next(); )
00220     x += *i;//xc.value();
00221     y += *j;//yc.value();
00222   }
00223   x /= xc.size();  y /= yc.size();
00224 
00225   // Now find the point closest to the CofG
00226   double dist = -1; // an invalid number
00227   for (it i=xc.begin(),j=yc.begin(); i!=xc.end() && j!=yc.end(); ++i, ++j) {
00228     //xc.reset(),yc.reset();xc.next(),yc.next();)
00229     //float newdist = hypot(x- *i/*xc.value()*/,y- *j/*yc.value()*/);
00230     double newdist;
00231     { double dx = x- *i/*xc.value()*/, dy = y- *j/*yc.value()*/; newdist = vcl_sqrt(dx*dx + dy*dy); }
00232     if ( dist<0 || newdist < dist ) {
00233       x0 = *i;//xc.value();
00234       y0 = *j;//yc.value();
00235       dist = newdist;
00236     }
00237   }
00238 
00239   // Set up the (jx,jy) arrays to point to the cluster centre
00240   for (it i=xc.begin(),j=yc.begin(); i!=xc.end() && j!=yc.end(); ++i,++j) {
00241     //xc.reset(),yc.reset();xc.next(),yc.next();)
00242     jx[*i/*xc.value()*/][*j/*yc.value()*/] = x0;
00243     jy[*i/*xc.value()*/][*j/*yc.value()*/] = y0;
00244   }
00245 }
00246 
00247 
00248 //-----------------------------------------------------------------------------
00249 //
00250 //: Determines whether the point (x,y) is a neighbour to a junction.
00251 //
00252 int osl_canny_base::Junction_neighbour(int const * const *junction, int x, int y) {
00253   // Find the neighbour of (x][y) in the image
00254   if ( junction[x-1][y-1] || junction[x  ][y-1] || junction[x+1][y-1] ||
00255        junction[x-1][y  ] ||                       junction[x+1][y  ] ||
00256        junction[x-1][y+1] || junction[x  ][y+1] || junction[x+1][y+1]
00257        )
00258     return 1;
00259   else
00260     return 0;
00261 }
00262 
00263 
00264 //-----------------------------------------------------------------------------
00265 
00266 //: Returns an m*n array of Ts.
00267 template <class T>
00268 T **osl_canny_base_make_raw_image(int m, int n, T * /*dummy*/) {
00269   T *array = new T[m*n];
00270   T **data = new T* [m];
00271   for (int i =0; i < m; ++i)
00272     data[i] = &array[i*n];
00273   return data;
00274 }
00275 
00276 //: Initialise an m*n array of Ts with value
00277 template <class T>
00278 void osl_canny_base_fill_raw_image(T * * image, int sizex, int sizey, T value) {
00279   for (int x =0; x < sizex; ++x)
00280     for (int y =0; y < sizey; ++y)
00281       image[x][y] = value;
00282 }
00283 
00284 //: Frees an m*n array of Ts.
00285 template <class T>
00286 void osl_canny_base_free_raw_image(T **ptr) {
00287   T *array = ptr[0];
00288   fsm_delete_array array;
00289   fsm_delete_array ptr;
00290 }
00291 
00292 //: Copies image1 to image2.
00293 template <class S, class T>
00294 void osl_canny_base_copy_raw_image(S const * const *image1, T * const *image2, int m, int n) //
00295 {
00296   for (int x=0; x<m; ++x)
00297     for (int y=0; y<n; ++y)
00298       image2[x][y] = image1[x][y];
00299 }
00300 
00301 
00302 #define inst(T) \
00303 template T     **osl_canny_base_make_raw_image(int, int, T *dummy); \
00304 template void    osl_canny_base_fill_raw_image(T **, int, int, T value); \
00305 template void    osl_canny_base_free_raw_image(T **); \
00306 template void osl_canny_base_copy_raw_image(T const * const *, T * const *, int, int);
00307 inst(float);
00308 inst(int);
00309 #undef inst