vil_line_filter.hxx
Go to the documentation of this file.
1 // This is core/vil/algo/vil_line_filter.hxx
2 #ifndef vil_line_filter_hxx_
3 #define vil_line_filter_hxx_
4 //:
5 // \file
6 // \brief Find line-like structures in a 2D image
7 // \author Tim Cootes
8 
9 #include "vil_line_filter.h"
10 #include <vil/vil_fill.h>
11 #include <cassert>
12 #ifdef _MSC_VER
13 # include <vcl_msvc_warnings.h>
14 #endif
15 
16 //: Find line like structures in image (light lines on dark backgrounds)
17 // On exit line_str contains line strength at each pixel,
18 // line_dir contains value indicating direction [0,4]
19 // 0 = Undefined, 1 = horizontal, 2 = 45 degrees etc
20 // This version looks for light lines on a dark background only.
21 template <class Type>
23  vil_image_view<float>& line_str,
24  vil_image_view<Type>const& image,
25  float edge_thresh)
26 {
27  assert(image.nplanes()==1);
28  unsigned ni = image.ni();
29  unsigned nj = image.nj();
30  std::ptrdiff_t istep = image.istep();
31  std::ptrdiff_t jstep = image.jstep();
32 
33  line_dir.set_size(ni,nj,1);
34  line_str.set_size(ni,nj,1);
35 
36  std::ptrdiff_t d_istep = line_dir.istep();
37  std::ptrdiff_t d_jstep = line_dir.jstep();
38  vxl_byte* d_data = line_dir.top_left_ptr();
39  std::ptrdiff_t s_istep = line_str.istep();
40  std::ptrdiff_t s_jstep = line_str.jstep();
41  float* s_data = line_str.top_left_ptr();
42 
43  // Cannot calculate line strength in borders
44  vil_fill_line(d_data,ni,d_istep,vxl_byte(0));
45  vil_fill_line(d_data+(nj-1)*d_jstep,ni,d_istep,vxl_byte(0));
46  vil_fill_line(s_data,ni,s_istep,0.0f);
47  vil_fill_line(s_data+(nj-1)*s_jstep,ni,s_istep,0.0f);
48 
49  d_data += d_jstep;
50  s_data += s_jstep;
51  const Type* im_data = image.top_left_ptr()+jstep+istep;
52 
53  int ni1 = ni-1;
54  int nj1 = nj-1;
55 
56  // Relative positions of points to be sampled
57  std::ptrdiff_t nistep = -istep;
58  std::ptrdiff_t njstep = -jstep;
59  std::ptrdiff_t xjstep = istep+jstep;
60  std::ptrdiff_t ynistep = jstep-istep;
61  std::ptrdiff_t xnjstep = istep-jstep;
62  std::ptrdiff_t ninjstep = -istep-jstep;
63 
64  for (int y=1;y<nj1;++y)
65  {
66  vxl_byte* d_row = d_data; d_row[0]=0; d_row+=d_istep;
67  float* s_row = s_data; s_row[0]=0; s_row+=s_istep;
68  const Type* i_row = im_data;
69  for (int x=1;x<ni1;++x)
70  {
71  // Evaluate the line strength at each orientation
72 
73  float f1 = float(i_row[nistep]) +float(i_row[istep]);
74  float f2 = float(i_row[ninjstep])+float(i_row[xjstep]);
75  float f3 = float(i_row[njstep]) +float(i_row[jstep]);
76  float f4 = float(i_row[ynistep]) +float(i_row[xnjstep]);
77 
78  // Look for highest value (ie bright line on dark background)
79  vxl_byte best_d = 1;
80  float max_f = f1;
81  if (f2>max_f) { best_d=2; max_f=f2;}
82  if (f3>max_f) { best_d=3; max_f=f3;}
83  if (f4>max_f) { best_d=4; max_f=f4;}
84 
85  float edge_s = 0.5f*max_f + (*i_row)/3.0f -(f1+f2+f3+f4)/6.0f;
86  if (edge_s>edge_thresh)
87  {
88  *d_row = best_d;
89  *s_row = edge_s;
90  }
91  else
92  {
93  *d_row=0; *s_row=0;
94  }
95 
96  d_row+=d_istep;
97  s_row+=s_istep;
98  i_row+=istep;
99  }
100  // Zero the last elements in the rows
101  d_row[0]=0;
102  s_row[0]=0;
103 
104  d_data += d_jstep;
105  s_data += s_jstep;
106  im_data += jstep;
107  }
108 }
109 
110 //: Find line like structures in image (dark lines on bright backgrounds)
111 // On exit line_str contains line strength at each pixel,
112 // line_dir contains value indicating direction [0,4]
113 // 0 = Undefined, 1 = horizontal, 2 = 45 degrees etc
114 template <class Type>
116  vil_image_view<float>& line_str,
117  vil_image_view<Type>const& image,
118  float edge_thresh)
119 {
120  assert(image.nplanes()==1);
121  unsigned ni = image.ni();
122  unsigned nj = image.nj();
123  std::ptrdiff_t istep = image.istep();
124  std::ptrdiff_t jstep = image.jstep();
125 
126  line_dir.set_size(ni,nj,1);
127  line_str.set_size(ni,nj,1);
128 
129  std::ptrdiff_t d_istep = line_dir.istep();
130  std::ptrdiff_t d_jstep = line_dir.jstep();
131  vxl_byte* d_data = line_dir.top_left_ptr();
132  std::ptrdiff_t s_istep = line_str.istep();
133  std::ptrdiff_t s_jstep = line_str.jstep();
134  float* s_data = line_str.top_left_ptr();
135 
136  // Cannot calculate line strength in borders
137  vil_fill_line(d_data,ni,d_istep,vxl_byte(0));
138  vil_fill_line(d_data+(nj-1)*d_jstep,ni,d_istep,vxl_byte(0));
139  vil_fill_line(s_data,ni,s_istep,0.0f);
140  vil_fill_line(s_data+(nj-1)*s_jstep,ni,s_istep,0.0f);
141 
142  d_data += d_jstep;
143  s_data += s_jstep;
144  const Type* im_data = image.top_left_ptr()+jstep+istep;
145 
146  int ni1 = ni-1;
147  int nj1 = nj-1;
148 
149  // Relative positions of points to be sampled
150  std::ptrdiff_t nistep = -istep;
151  std::ptrdiff_t njstep = -jstep;
152  std::ptrdiff_t xjstep = istep+jstep;
153  std::ptrdiff_t ynistep = jstep-istep;
154  std::ptrdiff_t xnjstep = istep-jstep;
155  std::ptrdiff_t ninjstep = -istep-jstep;
156 
157  for (int y=1;y<nj1;++y)
158  {
159  vxl_byte* d_row = d_data; d_row[0]=0; d_row+=d_istep;
160  float* s_row = s_data; s_row[0]=0; s_row+=s_istep;
161  const Type* i_row = im_data;
162  for (int x=1;x<ni1;++x)
163  {
164  // Evaluate the line strength at each orientation
165 
166  float f1 = float(i_row[nistep]) +float(i_row[istep]);
167  float f2 = float(i_row[ninjstep])+float(i_row[xjstep]);
168  float f3 = float(i_row[njstep]) +float(i_row[jstep]);
169  float f4 = float(i_row[xnjstep]) +float(i_row[ynistep]);
170 
171  // Look for lowest value (ie dark line on light background)
172  vxl_byte best_d = 1;
173  float min_f = f1;
174  if (f2<min_f) { best_d=2; min_f=f2;}
175  if (f3<min_f) { best_d=3; min_f=f3;}
176  if (f4<min_f) { best_d=4; min_f=f4;}
177 
178  float edge_s = (f1+f2+f3+f4)/6.0f - 0.5f*min_f - (*i_row)/3.0f;
179  if (edge_s>edge_thresh)
180  {
181  *d_row = best_d;
182  *s_row = edge_s;
183  }
184  else
185  {
186  *d_row=0; *s_row=0;
187  }
188 
189  d_row+=d_istep;
190  s_row+=s_istep;
191  i_row+=istep;
192  }
193  // Zero the last elements in the rows
194  d_row[0]=0;
195  s_row[0]=0;
196 
197  d_data += d_jstep;
198  s_data += s_jstep;
199  im_data += jstep;
200  }
201 }
202 
203 //: Find line like structures in image (light lines on dark backgrounds)
204 // On exit line_str contains line strength at each pixel,
205 // line_dir contains value indicating direction [0,4]
206 // 0 = Undefined, 1 = horizontal, 2 = 45 degrees etc
207 // This version looks for light lines on a dark background only.
208 template <class Type>
210  vil_image_view<float>& line_str,
211  vil_image_view<Type>const& image,
212  float edge_thresh)
213 {
214  assert(image.nplanes()==1);
215  unsigned ni = image.ni();
216  unsigned nj = image.nj();
217  std::ptrdiff_t istep = image.istep();
218  std::ptrdiff_t jstep = image.jstep();
219 
220  line_dir.set_size(ni,nj,1);
221  line_str.set_size(ni,nj,1);
222 
223  std::ptrdiff_t d_istep = line_dir.istep();
224  std::ptrdiff_t d_jstep = line_dir.jstep();
225  vxl_byte* d_data = line_dir.top_left_ptr();
226  std::ptrdiff_t s_istep = line_str.istep();
227  std::ptrdiff_t s_jstep = line_str.jstep();
228  float* s_data = line_str.top_left_ptr();
229 
230  // Cannot calculate line strength in borders
231  vil_fill_line(d_data,ni,d_istep,vxl_byte(0));
232  vil_fill_line(d_data+d_jstep,ni,d_istep,vxl_byte(0));
233  vil_fill_line(d_data+(nj-1)*d_jstep,ni,d_istep,vxl_byte(0));
234  vil_fill_line(d_data+(nj-2)*d_jstep,ni,d_istep,vxl_byte(0));
235  vil_fill_line(s_data,ni,s_istep,0.0f);
236  vil_fill_line(s_data+s_jstep,ni,s_istep,0.0f);
237  vil_fill_line(s_data+(nj-1)*s_jstep,ni,s_istep,0.0f);
238  vil_fill_line(s_data+(nj-2)*s_jstep,ni,s_istep,0.0f);
239 
240  d_data += 2*d_jstep;
241  s_data += 2*s_jstep;
242  const Type* im_data = image.top_left_ptr()+2*(jstep+istep);
243 
244  int ni2 = ni-2;
245  int nj2 = nj-2;
246 
247  // Relative positions of points to be sampled
248  std::ptrdiff_t i1a = -2*istep;
249  std::ptrdiff_t i1b = -istep;
250  std::ptrdiff_t i1c = istep;
251  std::ptrdiff_t i1d = 2*istep;
252 
253  std::ptrdiff_t i2c = istep+jstep;
254  std::ptrdiff_t i2a = -2*i2c;
255  std::ptrdiff_t i2b = -1*i2c;
256  std::ptrdiff_t i2d = 2*i2c;
257 
258  std::ptrdiff_t i3a = -2*jstep;
259  std::ptrdiff_t i3b = -1*jstep;
260  std::ptrdiff_t i3c = jstep;
261  std::ptrdiff_t i3d = 2*jstep;
262 
263  std::ptrdiff_t i4c = istep-jstep;
264  std::ptrdiff_t i4a = -2*i4c;
265  std::ptrdiff_t i4b = -1*i4c;
266  std::ptrdiff_t i4d = 2*i4c;
267 
268  for (int y=2;y<nj2;++y)
269  {
270  vxl_byte* d_row = d_data; d_row[0]=0; d_row+=d_istep;d_row[0]=0; d_row+=d_istep;
271  float* s_row = s_data; s_row[0]=0; s_row+=s_istep;s_row[0]=0; s_row+=s_istep;
272  const Type* i_row = im_data;
273  for (int x=2;x<ni2;++x)
274  {
275  // Evaluate the line strength at each orientation
276 
277  float f1 = float(i_row[i1a])+float(i_row[i1b])+float(i_row[i1c])+float(i_row[i1d]);
278  float f2 = float(i_row[i2a])+float(i_row[i2b])+float(i_row[i2c])+float(i_row[i2d]);
279  float f3 = float(i_row[i3a])+float(i_row[i3b])+float(i_row[i3c])+float(i_row[i3d]);
280  float f4 = float(i_row[i4a])+float(i_row[i4b])+float(i_row[i4c])+float(i_row[i4d]);
281 
282  // Look for highest value (ie bright line on dark background)
283  vxl_byte best_d = 1;
284  float max_f = f1;
285  if (f2>max_f) { best_d=2; max_f=f2;}
286  if (f3>max_f) { best_d=3; max_f=f3;}
287  if (f4>max_f) { best_d=4; max_f=f4;}
288 
289  // Average on line - average off line
290  float edge_s = (17.0f/60) * max_f + 0.2f*(*i_row) -(f1+f2+f3+f4)/12;
291  if (edge_s>edge_thresh)
292  {
293  *d_row = best_d;
294  *s_row = edge_s;
295  }
296  else
297  {
298  *d_row=0; *s_row=0;
299  }
300 
301  d_row+=d_istep;
302  s_row+=s_istep;
303  i_row+=istep;
304  }
305  // Zero the last elements in the rows
306  d_row[0]=0; d_row[d_istep]=0;
307  s_row[0]=0; s_row[s_istep]=0;
308 
309  d_data += d_jstep;
310  s_data += s_jstep;
311  im_data += jstep;
312  }
313 }
314 
315 //: Find line like structures in image (dark lines on light backgrounds)
316 template <class Type>
318  vil_image_view<float>& line_str,
319  vil_image_view<Type>const& image,
320  float edge_thresh)
321 {
322  assert(image.nplanes()==1);
323  unsigned ni = image.ni();
324  unsigned nj = image.nj();
325  std::ptrdiff_t istep = image.istep();
326  std::ptrdiff_t jstep = image.jstep();
327 
328  line_dir.set_size(ni,nj,1);
329  line_str.set_size(ni,nj,1);
330 
331  std::ptrdiff_t d_istep = line_dir.istep();
332  std::ptrdiff_t d_jstep = line_dir.jstep();
333  vxl_byte* d_data = line_dir.top_left_ptr();
334  std::ptrdiff_t s_istep = line_str.istep();
335  std::ptrdiff_t s_jstep = line_str.jstep();
336  float* s_data = line_str.top_left_ptr();
337 
338  // Cannot calculate line strength in borders
339  vil_fill_line(d_data,ni,d_istep,vxl_byte(0));
340  vil_fill_line(d_data+d_jstep,ni,d_istep,vxl_byte(0));
341  vil_fill_line(d_data+(nj-1)*d_jstep,ni,d_istep,vxl_byte(0));
342  vil_fill_line(d_data+(nj-2)*d_jstep,ni,d_istep,vxl_byte(0));
343  vil_fill_line(s_data,ni,s_istep,0.0f);
344  vil_fill_line(s_data+s_jstep,ni,s_istep,0.0f);
345  vil_fill_line(s_data+(nj-1)*s_jstep,ni,s_istep,0.0f);
346  vil_fill_line(s_data+(nj-2)*s_jstep,ni,s_istep,0.0f);
347 
348  d_data += 2*d_jstep;
349  s_data += 2*s_jstep;
350  const Type* im_data = image.top_left_ptr()+2*(jstep+istep);
351 
352  int ni2 = ni-2;
353  int nj2 = nj-2;
354 
355  // Relative positions of points to be sampled
356  std::ptrdiff_t i1a = -2*istep;
357  std::ptrdiff_t i1b = -istep;
358  std::ptrdiff_t i1c = istep;
359  std::ptrdiff_t i1d = 2*istep;
360 
361  std::ptrdiff_t i2c = istep+jstep;
362  std::ptrdiff_t i2a = -2*i2c;
363  std::ptrdiff_t i2b = -1*i2c;
364  std::ptrdiff_t i2d = 2*i2c;
365 
366  std::ptrdiff_t i3a = -2*jstep;
367  std::ptrdiff_t i3b = -1*jstep;
368  std::ptrdiff_t i3c = jstep;
369  std::ptrdiff_t i3d = 2*jstep;
370 
371  std::ptrdiff_t i4c = istep-jstep;
372  std::ptrdiff_t i4a = -2*i4c;
373  std::ptrdiff_t i4b = -1*i4c;
374  std::ptrdiff_t i4d = 2*i4c;
375 
376  for (int y=2;y<nj2;++y)
377  {
378  vxl_byte* d_row = d_data; d_row[0]=0; d_row+=d_istep;d_row[0]=0; d_row+=d_istep;
379  float* s_row = s_data; s_row[0]=0; s_row+=s_istep;s_row[0]=0; s_row+=s_istep;
380  const Type* i_row = im_data;
381  for (int x=2;x<ni2;++x)
382  {
383  // Evaluate the line strength at each orientation
384 
385  float f1 = float(i_row[i1a])+float(i_row[i1b])+float(i_row[i1c])+float(i_row[i1d]);
386  float f2 = float(i_row[i2a])+float(i_row[i2b])+float(i_row[i2c])+float(i_row[i2d]);
387  float f3 = float(i_row[i3a])+float(i_row[i3b])+float(i_row[i3c])+float(i_row[i3d]);
388  float f4 = float(i_row[i4a])+float(i_row[i4b])+float(i_row[i4c])+float(i_row[i4d]);
389 
390  // Look for highest value (ie bright line on dark background)
391  vxl_byte best_d = 1;
392  float min_f = f1;
393  if (f2<min_f) { best_d=2; min_f=f2;}
394  if (f3<min_f) { best_d=3; min_f=f3;}
395  if (f4<min_f) { best_d=4; min_f=f4;}
396 
397  // Average on line - average off line
398  float edge_s = (f1+f2+f3+f4)/12 - (17.0f/60) * min_f - 0.2f*(*i_row);
399  if (edge_s>edge_thresh)
400  {
401  *d_row = best_d;
402  *s_row = edge_s;
403  }
404  else
405  {
406  *d_row=0; *s_row=0;
407  }
408 
409  d_row+=d_istep;
410  s_row+=s_istep;
411  i_row+=istep;
412  }
413  // Zero the last elements in the rows
414  d_row[0]=0; d_row[d_istep]=0;
415  s_row[0]=0; s_row[s_istep]=0;
416 
417  d_data += d_jstep;
418  s_data += s_jstep;
419  im_data += jstep;
420  }
421 }
422 
423 
424 #undef VIL_LINE_FILTER_INSTANTIATE
425 #define VIL_LINE_FILTER_INSTANTIATE(T) \
426  template class vil_line_filter<T >
427 
428 #endif
Various functions for manipulating image views.
Concrete view of image data of type T held in memory.
Definition: vil_fwd.h:13
void set_size(unsigned ni, unsigned nj) override
resize current planes to ni x nj.
std::ptrdiff_t jstep() const
Add this to your pixel pointer to get next j pixel.
Find line-like structures in a 2D image.
unsigned ni() const
Width.
unsigned nj() const
Height.
void vil_fill_line(vil_image_view< T > &im, int ai, int aj, int bi, int bj, T value)
Fill line from (ai,aj) to (bi,bj) using Bresenham's algorithm.
Definition: vil_fill.h:58
void dark_lines_3x3(vil_image_view< vxl_byte > &line_dir, vil_image_view< float > &line_str, const vil_image_view< Type > &image, float edge_thresh=0.1f)
Find line like structures in image (dark lines on light backgrounds).
void light_lines_5x5(vil_image_view< vxl_byte > &line_dir, vil_image_view< float > &line_str, const vil_image_view< Type > &image, float edge_thresh=0.1f)
Find line like structures in image (light lines on dark backgrounds).
T * top_left_ptr()
Pointer to the first (top left in plane 0) pixel.
unsigned nplanes() const
Number of planes.
std::ptrdiff_t istep() const
Add this to your pixel pointer to get next i pixel.
void light_lines_3x3(vil_image_view< vxl_byte > &line_dir, vil_image_view< float > &line_str, const vil_image_view< Type > &image, float edge_thresh=0.1f)
Find line like structures in image (light lines on dark backgrounds).
void dark_lines_5x5(vil_image_view< vxl_byte > &line_dir, vil_image_view< float > &line_str, const vil_image_view< Type > &image, float edge_thresh=0.1f)
Find line like structures in image (dark lines on light backgrounds).