core/vil/algo/vil_line_filter.txx
Go to the documentation of this file.
00001 // This is core/vil/algo/vil_line_filter.txx
00002 #ifndef vil_line_filter_txx_
00003 #define vil_line_filter_txx_
00004 //:
00005 // \file
00006 // \brief Find line-like structures in a 2D image
00007 // \author Tim Cootes
00008 
00009 #include "vil_line_filter.h"
00010 #include <vil/vil_fill.h>
00011 #include <vcl_cassert.h>
00012 
00013 //: Find line like structures in image (light lines on dark backgrounds)
00014 //  On exit line_str contains line strength at each pixel,
00015 //  line_dir contains value indicating direction [0,4]
00016 //  0 = Undefined, 1 = horizontal, 2 = 45 degrees etc
00017 //  This version looks for light lines on a dark background only.
00018 template <class Type>
00019 void vil_line_filter<Type>::light_lines_3x3(vil_image_view<vxl_byte>& line_dir,
00020                                             vil_image_view<float>& line_str,
00021                                             vil_image_view<Type>const& image,
00022                                             float edge_thresh)
00023 {
00024   assert(image.nplanes()==1);
00025   unsigned ni = image.ni();
00026   unsigned nj = image.nj();
00027   vcl_ptrdiff_t istep = image.istep();
00028   vcl_ptrdiff_t jstep = image.jstep();
00029 
00030   line_dir.set_size(ni,nj,1);
00031   line_str.set_size(ni,nj,1);
00032 
00033   vcl_ptrdiff_t d_istep = line_dir.istep();
00034   vcl_ptrdiff_t d_jstep = line_dir.jstep();
00035   vxl_byte* d_data  = line_dir.top_left_ptr();
00036   vcl_ptrdiff_t s_istep = line_str.istep();
00037   vcl_ptrdiff_t s_jstep = line_str.jstep();
00038   float* s_data = line_str.top_left_ptr();
00039 
00040   // Cannot calculate line strength in borders
00041   vil_fill_line(d_data,ni,d_istep,vxl_byte(0));
00042   vil_fill_line(d_data+(nj-1)*d_jstep,ni,d_istep,vxl_byte(0));
00043   vil_fill_line(s_data,ni,s_istep,0.0f);
00044   vil_fill_line(s_data+(nj-1)*s_jstep,ni,s_istep,0.0f);
00045 
00046   d_data += d_jstep;
00047   s_data += s_jstep;
00048   const Type* im_data = image.top_left_ptr()+jstep+istep;
00049 
00050   int ni1 = ni-1;
00051   int nj1 = nj-1;
00052 
00053   // Relative positions of points to be sampled
00054   vcl_ptrdiff_t nistep = -istep;
00055   vcl_ptrdiff_t njstep = -jstep;
00056   vcl_ptrdiff_t xjstep = istep+jstep;
00057   vcl_ptrdiff_t ynistep = jstep-istep;
00058   vcl_ptrdiff_t xnjstep = istep-jstep;
00059   vcl_ptrdiff_t ninjstep = -istep-jstep;
00060 
00061   for (int y=1;y<nj1;++y)
00062   {
00063     vxl_byte* d_row = d_data; d_row[0]=0; d_row+=d_istep;
00064     float*    s_row = s_data; s_row[0]=0; s_row+=s_istep;
00065     const Type* i_row = im_data;
00066     for (int x=1;x<ni1;++x)
00067     {
00068       // Evaluate the line strength at each orientation
00069 
00070       float f1 = float(i_row[nistep])  +float(i_row[istep]);
00071       float f2 = float(i_row[ninjstep])+float(i_row[xjstep]);
00072       float f3 = float(i_row[njstep])  +float(i_row[jstep]);
00073       float f4 = float(i_row[ynistep]) +float(i_row[xnjstep]);
00074 
00075       // Look for highest value (ie bright line on dark background)
00076       vxl_byte best_d = 1;
00077       float max_f = f1;
00078       if (f2>max_f) { best_d=2; max_f=f2;}
00079       if (f3>max_f) { best_d=3; max_f=f3;}
00080       if (f4>max_f) { best_d=4; max_f=f4;}
00081 
00082       float edge_s = 0.5f*max_f + (*i_row)/3.0f -(f1+f2+f3+f4)/6.0f;
00083       if (edge_s>edge_thresh)
00084       {
00085         *d_row = best_d;
00086         *s_row = edge_s;
00087       }
00088       else
00089       {
00090         *d_row=0; *s_row=0;
00091       }
00092 
00093       d_row+=d_istep;
00094       s_row+=s_istep;
00095       i_row+=istep;
00096     }
00097     // Zero the last elements in the rows
00098     d_row[0]=0;
00099     s_row[0]=0;
00100 
00101     d_data += d_jstep;
00102     s_data += s_jstep;
00103     im_data += jstep;
00104   }
00105 }
00106 
00107 //: Find line like structures in image (dark lines on bright backgrounds)
00108 //  On exit line_str contains line strength at each pixel,
00109 //  line_dir contains value indicating direction [0,4]
00110 //  0 = Undefined, 1 = horizontal, 2 = 45 degrees etc
00111 template <class Type>
00112 void vil_line_filter<Type>::dark_lines_3x3(vil_image_view<vxl_byte>& line_dir,
00113                                            vil_image_view<float>& line_str,
00114                                            vil_image_view<Type>const& image,
00115                                            float edge_thresh)
00116 {
00117   assert(image.nplanes()==1);
00118   unsigned ni = image.ni();
00119   unsigned nj = image.nj();
00120   vcl_ptrdiff_t istep = image.istep();
00121   vcl_ptrdiff_t jstep = image.jstep();
00122 
00123   line_dir.set_size(ni,nj,1);
00124   line_str.set_size(ni,nj,1);
00125 
00126   vcl_ptrdiff_t d_istep = line_dir.istep();
00127   vcl_ptrdiff_t d_jstep = line_dir.jstep();
00128   vxl_byte* d_data  = line_dir.top_left_ptr();
00129   vcl_ptrdiff_t s_istep = line_str.istep();
00130   vcl_ptrdiff_t s_jstep = line_str.jstep();
00131   float* s_data = line_str.top_left_ptr();
00132 
00133   // Cannot calculate line strength in borders
00134   vil_fill_line(d_data,ni,d_istep,vxl_byte(0));
00135   vil_fill_line(d_data+(nj-1)*d_jstep,ni,d_istep,vxl_byte(0));
00136   vil_fill_line(s_data,ni,s_istep,0.0f);
00137   vil_fill_line(s_data+(nj-1)*s_jstep,ni,s_istep,0.0f);
00138 
00139   d_data += d_jstep;
00140   s_data += s_jstep;
00141   const Type* im_data = image.top_left_ptr()+jstep+istep;
00142 
00143   int ni1 = ni-1;
00144   int nj1 = nj-1;
00145 
00146   // Relative positions of points to be sampled
00147   vcl_ptrdiff_t nistep = -istep;
00148   vcl_ptrdiff_t njstep = -jstep;
00149   vcl_ptrdiff_t xjstep = istep+jstep;
00150   vcl_ptrdiff_t ynistep = jstep-istep;
00151   vcl_ptrdiff_t xnjstep = istep-jstep;
00152   vcl_ptrdiff_t ninjstep = -istep-jstep;
00153 
00154   for (int y=1;y<nj1;++y)
00155   {
00156     vxl_byte* d_row = d_data; d_row[0]=0; d_row+=d_istep;
00157     float*    s_row = s_data; s_row[0]=0; s_row+=s_istep;
00158     const Type* i_row = im_data;
00159     for (int x=1;x<ni1;++x)
00160     {
00161       // Evaluate the line strength at each orientation
00162 
00163       float f1 = float(i_row[nistep])  +float(i_row[istep]);
00164       float f2 = float(i_row[ninjstep])+float(i_row[xjstep]);
00165       float f3 = float(i_row[njstep])  +float(i_row[jstep]);
00166       float f4 = float(i_row[xnjstep]) +float(i_row[ynistep]);
00167 
00168       // Look for lowest value (ie dark line on light background)
00169       vxl_byte best_d = 1;
00170       float min_f = f1;
00171       if (f2<min_f) { best_d=2; min_f=f2;}
00172       if (f3<min_f) { best_d=3; min_f=f3;}
00173       if (f4<min_f) { best_d=4; min_f=f4;}
00174 
00175       float edge_s = (f1+f2+f3+f4)/6.0f - 0.5f*min_f - (*i_row)/3.0f;
00176       if (edge_s>edge_thresh)
00177       {
00178         *d_row = best_d;
00179         *s_row = edge_s;
00180       }
00181       else
00182       {
00183         *d_row=0; *s_row=0;
00184       }
00185 
00186       d_row+=d_istep;
00187       s_row+=s_istep;
00188       i_row+=istep;
00189     }
00190     // Zero the last elements in the rows
00191     d_row[0]=0;
00192     s_row[0]=0;
00193 
00194     d_data += d_jstep;
00195     s_data += s_jstep;
00196     im_data += jstep;
00197   }
00198 }
00199 
00200 //: Find line like structures in image (light lines on dark backgrounds)
00201 //  On exit line_str contains line strength at each pixel,
00202 //  line_dir contains value indicating direction [0,4]
00203 //  0 = Undefined, 1 = horizontal, 2 = 45 degrees etc
00204 //  This version looks for light lines on a dark background only.
00205 template <class Type>
00206 void vil_line_filter<Type>::light_lines_5x5(vil_image_view<vxl_byte>& line_dir,
00207                                             vil_image_view<float>& line_str,
00208                                             vil_image_view<Type>const& image,
00209                                             float edge_thresh)
00210 {
00211   assert(image.nplanes()==1);
00212   unsigned ni = image.ni();
00213   unsigned nj = image.nj();
00214   vcl_ptrdiff_t istep = image.istep();
00215   vcl_ptrdiff_t jstep = image.jstep();
00216 
00217   line_dir.set_size(ni,nj,1);
00218   line_str.set_size(ni,nj,1);
00219 
00220   vcl_ptrdiff_t d_istep = line_dir.istep();
00221   vcl_ptrdiff_t d_jstep = line_dir.jstep();
00222   vxl_byte* d_data  = line_dir.top_left_ptr();
00223   vcl_ptrdiff_t s_istep = line_str.istep();
00224   vcl_ptrdiff_t s_jstep = line_str.jstep();
00225   float* s_data = line_str.top_left_ptr();
00226 
00227   // Cannot calculate line strength in borders
00228   vil_fill_line(d_data,ni,d_istep,vxl_byte(0));
00229   vil_fill_line(d_data+d_jstep,ni,d_istep,vxl_byte(0));
00230   vil_fill_line(d_data+(nj-1)*d_jstep,ni,d_istep,vxl_byte(0));
00231   vil_fill_line(d_data+(nj-2)*d_jstep,ni,d_istep,vxl_byte(0));
00232   vil_fill_line(s_data,ni,s_istep,0.0f);
00233   vil_fill_line(s_data+s_jstep,ni,s_istep,0.0f);
00234   vil_fill_line(s_data+(nj-1)*s_jstep,ni,s_istep,0.0f);
00235   vil_fill_line(s_data+(nj-2)*s_jstep,ni,s_istep,0.0f);
00236 
00237   d_data += 2*d_jstep;
00238   s_data += 2*s_jstep;
00239   const Type* im_data = image.top_left_ptr()+2*(jstep+istep);
00240 
00241   int ni2 = ni-2;
00242   int nj2 = nj-2;
00243 
00244   // Relative positions of points to be sampled
00245   vcl_ptrdiff_t i1a = -2*istep;
00246   vcl_ptrdiff_t i1b = -istep;
00247   vcl_ptrdiff_t i1c = istep;
00248   vcl_ptrdiff_t i1d = 2*istep;
00249 
00250   vcl_ptrdiff_t i2c = istep+jstep;
00251   vcl_ptrdiff_t i2a = -2*i2c;
00252   vcl_ptrdiff_t i2b = -1*i2c;
00253   vcl_ptrdiff_t i2d = 2*i2c;
00254 
00255   vcl_ptrdiff_t i3a = -2*jstep;
00256   vcl_ptrdiff_t i3b = -1*jstep;
00257   vcl_ptrdiff_t i3c = jstep;
00258   vcl_ptrdiff_t i3d = 2*jstep;
00259 
00260   vcl_ptrdiff_t i4c = istep-jstep;
00261   vcl_ptrdiff_t i4a = -2*i4c;
00262   vcl_ptrdiff_t i4b = -1*i4c;
00263   vcl_ptrdiff_t i4d = 2*i4c;
00264 
00265   for (int y=2;y<nj2;++y)
00266   {
00267     vxl_byte* d_row = d_data; d_row[0]=0; d_row+=d_istep;d_row[0]=0; d_row+=d_istep;
00268     float*    s_row = s_data; s_row[0]=0; s_row+=s_istep;s_row[0]=0; s_row+=s_istep;
00269     const Type* i_row = im_data;
00270     for (int x=2;x<ni2;++x)
00271     {
00272       // Evaluate the line strength at each orientation
00273 
00274       float f1 = float(i_row[i1a])+float(i_row[i1b])+float(i_row[i1c])+float(i_row[i1d]);
00275       float f2 = float(i_row[i2a])+float(i_row[i2b])+float(i_row[i2c])+float(i_row[i2d]);
00276       float f3 = float(i_row[i3a])+float(i_row[i3b])+float(i_row[i3c])+float(i_row[i3d]);
00277       float f4 = float(i_row[i4a])+float(i_row[i4b])+float(i_row[i4c])+float(i_row[i4d]);
00278 
00279       // Look for highest value (ie bright line on dark background)
00280       vxl_byte best_d = 1;
00281       float max_f = f1;
00282       if (f2>max_f) { best_d=2; max_f=f2;}
00283       if (f3>max_f) { best_d=3; max_f=f3;}
00284       if (f4>max_f) { best_d=4; max_f=f4;}
00285 
00286         // Average on line - average off line
00287       float edge_s = (17.0f/60) * max_f + 0.2f*(*i_row) -(f1+f2+f3+f4)/12;
00288       if (edge_s>edge_thresh)
00289       {
00290         *d_row = best_d;
00291         *s_row = edge_s;
00292       }
00293       else
00294       {
00295         *d_row=0; *s_row=0;
00296       }
00297 
00298       d_row+=d_istep;
00299       s_row+=s_istep;
00300       i_row+=istep;
00301     }
00302     // Zero the last elements in the rows
00303     d_row[0]=0; d_row[d_istep]=0;
00304     s_row[0]=0; s_row[s_istep]=0;
00305 
00306     d_data += d_jstep;
00307     s_data += s_jstep;
00308     im_data += jstep;
00309   }
00310 }
00311 
00312 //: Find line like structures in image (dark lines on light backgrounds)
00313 template <class Type>
00314 void vil_line_filter<Type>::dark_lines_5x5(vil_image_view<vxl_byte>& line_dir,
00315                                            vil_image_view<float>& line_str,
00316                                            vil_image_view<Type>const& image,
00317                                            float edge_thresh)
00318 {
00319   assert(image.nplanes()==1);
00320   unsigned ni = image.ni();
00321   unsigned nj = image.nj();
00322   vcl_ptrdiff_t istep = image.istep();
00323   vcl_ptrdiff_t jstep = image.jstep();
00324 
00325   line_dir.set_size(ni,nj,1);
00326   line_str.set_size(ni,nj,1);
00327 
00328   vcl_ptrdiff_t d_istep = line_dir.istep();
00329   vcl_ptrdiff_t d_jstep = line_dir.jstep();
00330   vxl_byte* d_data  = line_dir.top_left_ptr();
00331   vcl_ptrdiff_t s_istep = line_str.istep();
00332   vcl_ptrdiff_t s_jstep = line_str.jstep();
00333   float* s_data = line_str.top_left_ptr();
00334 
00335   // Cannot calculate line strength in borders
00336   vil_fill_line(d_data,ni,d_istep,vxl_byte(0));
00337   vil_fill_line(d_data+d_jstep,ni,d_istep,vxl_byte(0));
00338   vil_fill_line(d_data+(nj-1)*d_jstep,ni,d_istep,vxl_byte(0));
00339   vil_fill_line(d_data+(nj-2)*d_jstep,ni,d_istep,vxl_byte(0));
00340   vil_fill_line(s_data,ni,s_istep,0.0f);
00341   vil_fill_line(s_data+s_jstep,ni,s_istep,0.0f);
00342   vil_fill_line(s_data+(nj-1)*s_jstep,ni,s_istep,0.0f);
00343   vil_fill_line(s_data+(nj-2)*s_jstep,ni,s_istep,0.0f);
00344 
00345   d_data += 2*d_jstep;
00346   s_data += 2*s_jstep;
00347   const Type* im_data = image.top_left_ptr()+2*(jstep+istep);
00348 
00349   int ni2 = ni-2;
00350   int nj2 = nj-2;
00351 
00352   // Relative positions of points to be sampled
00353   vcl_ptrdiff_t i1a = -2*istep;
00354   vcl_ptrdiff_t i1b = -istep;
00355   vcl_ptrdiff_t i1c = istep;
00356   vcl_ptrdiff_t i1d = 2*istep;
00357 
00358   vcl_ptrdiff_t i2c = istep+jstep;
00359   vcl_ptrdiff_t i2a = -2*i2c;
00360   vcl_ptrdiff_t i2b = -1*i2c;
00361   vcl_ptrdiff_t i2d = 2*i2c;
00362 
00363   vcl_ptrdiff_t i3a = -2*jstep;
00364   vcl_ptrdiff_t i3b = -1*jstep;
00365   vcl_ptrdiff_t i3c = jstep;
00366   vcl_ptrdiff_t i3d = 2*jstep;
00367 
00368   vcl_ptrdiff_t i4c = istep-jstep;
00369   vcl_ptrdiff_t i4a = -2*i4c;
00370   vcl_ptrdiff_t i4b = -1*i4c;
00371   vcl_ptrdiff_t i4d = 2*i4c;
00372 
00373   for (int y=2;y<nj2;++y)
00374   {
00375     vxl_byte* d_row = d_data; d_row[0]=0; d_row+=d_istep;d_row[0]=0; d_row+=d_istep;
00376     float*    s_row = s_data; s_row[0]=0; s_row+=s_istep;s_row[0]=0; s_row+=s_istep;
00377     const Type* i_row = im_data;
00378     for (int x=2;x<ni2;++x)
00379     {
00380       // Evaluate the line strength at each orientation
00381 
00382       float f1 = float(i_row[i1a])+float(i_row[i1b])+float(i_row[i1c])+float(i_row[i1d]);
00383       float f2 = float(i_row[i2a])+float(i_row[i2b])+float(i_row[i2c])+float(i_row[i2d]);
00384       float f3 = float(i_row[i3a])+float(i_row[i3b])+float(i_row[i3c])+float(i_row[i3d]);
00385       float f4 = float(i_row[i4a])+float(i_row[i4b])+float(i_row[i4c])+float(i_row[i4d]);
00386 
00387       // Look for highest value (ie bright line on dark background)
00388       vxl_byte best_d = 1;
00389       float min_f = f1;
00390       if (f2<min_f) { best_d=2; min_f=f2;}
00391       if (f3<min_f) { best_d=3; min_f=f3;}
00392       if (f4<min_f) { best_d=4; min_f=f4;}
00393 
00394         // Average on line - average off line
00395       float edge_s = (f1+f2+f3+f4)/12 - (17.0f/60) * min_f - 0.2f*(*i_row);
00396       if (edge_s>edge_thresh)
00397       {
00398         *d_row = best_d;
00399         *s_row = edge_s;
00400       }
00401       else
00402       {
00403         *d_row=0; *s_row=0;
00404       }
00405 
00406       d_row+=d_istep;
00407       s_row+=s_istep;
00408       i_row+=istep;
00409     }
00410     // Zero the last elements in the rows
00411     d_row[0]=0; d_row[d_istep]=0;
00412     s_row[0]=0; s_row[s_istep]=0;
00413 
00414     d_data += d_jstep;
00415     s_data += s_jstep;
00416     im_data += jstep;
00417   }
00418 }
00419 
00420 
00421 #undef VIL_LINE_FILTER_INSTANTIATE
00422 #define VIL_LINE_FILTER_INSTANTIATE(T) \
00423  template class vil_line_filter<T >
00424 
00425 #endif