vil_corners.cxx
Go to the documentation of this file.
1 //:
2 // \file
3 // \brief Estimate corner positions using Forstner/Harris approach
4 // \author Tim Cootes
5 
6 #include "vil_corners.h"
7 #include <vil/vil_fill.h>
8 #include <cassert>
9 #ifdef _MSC_VER
10 # include <vcl_msvc_warnings.h>
11 #endif
13 #include <vil/vil_math.h>
14 
15 //: Compute Forstner/Harris corner strength function given gradient images.
16 // grad_i and grad_j are assumed to be the i and j gradient images (single
17 // plane), such as produced by vil_sobel_3x3(). At each pixel compute
18 // the Forstner/Harris corner function: det(H)-k*sqr(trace(H)), where
19 // H is the 2x2 matrix of second derivatives, generated by applying a Sobel
20 // operator to the gradient images.
21 //
22 // The local peaks of the output image correspond to corner candidates.
23 // \relatesalso vil_image_view
25  const vil_image_view<float>& grad_j,
26  vil_image_view<float>& dest, double k)
27 {
28  assert(grad_i.nplanes()==1);
29  assert(grad_j.nplanes()==1);
30  unsigned ni = grad_i.ni(), nj = grad_i.nj();
31  assert(grad_j.ni()==ni && grad_j.nj()==nj );
32 
33  dest.set_size(ni,nj);
34 
35  // Zero a two pixel border
36  for (unsigned i=0;i<2;++i)
37  {
38  vil_fill_row(dest,i,0.0f);
39  vil_fill_row(dest,nj-1-i,0.0f);
40  vil_fill_col(dest,i,0.0f);
41  vil_fill_col(dest,ni-1-i,0.0f);
42  }
43 
44  const unsigned ni2 = ni-2;
45  const unsigned nj2 = nj-2;
46 
47  // Compute relative grid positions
48  // o1 o2 o3
49  // o4 o5
50  // o6 o7 o8
51  const std::ptrdiff_t oi1 = grad_i.jstep() - grad_i.istep();
52  const std::ptrdiff_t oi2 = grad_i.jstep();
53  const std::ptrdiff_t oi3 = grad_i.istep() + grad_i.jstep();
54  const std::ptrdiff_t oi4 = -grad_i.istep();
55  const std::ptrdiff_t oi5 = grad_i.istep();
56  const std::ptrdiff_t oi6 = -grad_i.istep() - grad_i.jstep();
57  const std::ptrdiff_t oi7 = -grad_i.jstep();
58  const std::ptrdiff_t oi8 = grad_i.istep() - grad_i.jstep();
59 
60  const std::ptrdiff_t oj1 = grad_j.jstep() - grad_j.istep();
61  const std::ptrdiff_t oj2 = grad_j.jstep();
62  const std::ptrdiff_t oj3 = grad_j.istep() + grad_j.jstep();
63  const std::ptrdiff_t oj6 = -grad_j.istep() - grad_j.jstep();
64  const std::ptrdiff_t oj7 = -grad_j.jstep();
65  const std::ptrdiff_t oj8 = grad_j.istep() - grad_j.jstep();
66 
67  float * d_data = &dest(2,2);
68  const float * gi_data = &grad_i(2,2);
69  const float * gj_data = &grad_j(2,2);
70 
71  for (unsigned j=2;j<nj2;++j)
72  {
73  float* d = d_data;
74  const float* pgi = gi_data;
75  const float* pgj = gj_data;
76  for (unsigned i=2;i<ni2;++i)
77  {
78  // Compute gradient in i
79  float dxdx = 0.125f*(pgi[oi3]+pgi[oi8] - (pgi[oi1]+pgi[oi6])) + 0.25f*(pgi[oi5]-pgi[oi4]);
80  // Compute gradient in j
81  float dxdy = 0.125f*(pgi[oi1]+pgi[oi3] - (pgi[oi6]+pgi[oi8])) + 0.25f*(pgi[oi2]-pgi[oi7]);
82  // Compute gradient in j
83  float dydy = 0.125f*(pgj[oj1]+pgj[oj3] - (pgj[oj6]+pgj[oj8])) + 0.25f*(pgj[oj2]-pgj[oj7]);
84 
85  float detH = dxdx*dydy - dxdy*dxdy;
86  float traceH = dxdx+dydy;
87 
88  *d = detH - float(k) * traceH * traceH;
89 
90  pgi += grad_i.istep();
91  pgj += grad_j.istep();
92  d += dest.istep();
93  }
94 
95  gi_data += grad_i.jstep();
96  gj_data += grad_j.jstep();
97  d_data += dest.jstep();
98  }
99 }
100 
102  const vil_image_view<double>& grad_j,
103  vil_image_view<double>& dest, double k)
104 {
105  assert(grad_i.nplanes()==1);
106  assert(grad_j.nplanes()==1);
107  unsigned ni = grad_i.ni(), nj = grad_i.nj();
108  assert(grad_j.ni()==ni && grad_j.nj()==nj );
109 
110  dest.set_size(ni,nj);
111 
112  // Zero a two pixel border
113  for (unsigned i=0;i<2;++i)
114  {
115  vil_fill_row(dest,i,0.0);
116  vil_fill_row(dest,nj-1-i,0.0);
117  vil_fill_col(dest,i,0.0);
118  vil_fill_col(dest,ni-1-i,0.0);
119  }
120 
121  const unsigned ni2 = ni-2;
122  const unsigned nj2 = nj-2;
123 
124  // Compute relative grid positions
125  // o1 o2 o3
126  // o4 o5
127  // o6 o7 o8
128  const std::ptrdiff_t oi1 = grad_i.jstep() - grad_i.istep();
129  const std::ptrdiff_t oi2 = grad_i.jstep();
130  const std::ptrdiff_t oi3 = grad_i.istep() + grad_i.jstep();
131  const std::ptrdiff_t oi4 = -grad_i.istep();
132  const std::ptrdiff_t oi5 = grad_i.istep();
133  const std::ptrdiff_t oi6 = -grad_i.istep() - grad_i.jstep();
134  const std::ptrdiff_t oi7 = -grad_i.jstep();
135  const std::ptrdiff_t oi8 = grad_i.istep() - grad_i.jstep();
136 
137  const std::ptrdiff_t oj1 = grad_j.jstep() - grad_j.istep();
138  const std::ptrdiff_t oj2 = grad_j.jstep();
139  const std::ptrdiff_t oj3 = grad_j.istep() + grad_j.jstep();
140  const std::ptrdiff_t oj6 = -grad_j.istep() - grad_j.jstep();
141  const std::ptrdiff_t oj7 = -grad_j.jstep();
142  const std::ptrdiff_t oj8 = grad_j.istep() - grad_j.jstep();
143 
144  double * d_data = &dest(2,2);
145  const double * gi_data = &grad_i(2,2);
146  const double * gj_data = &grad_j(2,2);
147 
148  for (unsigned j=2;j<nj2;++j)
149  {
150  double* d = d_data;
151  const double* pgi = gi_data;
152  const double* pgj = gj_data;
153  for (unsigned i=2;i<ni2;++i)
154  {
155  // Compute gradient in i
156  double dxdx = 0.125f*(pgi[oi3]+pgi[oi8] - (pgi[oi1]+pgi[oi6])) + 0.25f*(pgi[oi5]-pgi[oi4]);
157  // Compute gradient in j
158  double dxdy = 0.125f*(pgi[oi1]+pgi[oi3] - (pgi[oi6]+pgi[oi8])) + 0.25f*(pgi[oi2]-pgi[oi7]);
159  // Compute gradient in j
160  double dydy = 0.125f*(pgj[oj1]+pgj[oj3] - (pgj[oj6]+pgj[oj8])) + 0.25f*(pgj[oj2]-pgj[oj7]);
161 
162  double detH = dxdx*dydy - dxdy*dxdy;
163  double traceH = dxdx+dydy;
164 
165  *d = detH - double(k) * traceH * traceH;
166 
167  pgi += grad_i.istep();
168  pgj += grad_j.istep();
169  d += dest.istep();
170  }
171 
172  gi_data += grad_i.jstep();
173  gj_data += grad_j.jstep();
174  d_data += dest.jstep();
175  }
176 }
177 
178 //: Compute corner strength using Rohr's recommended method
179 // This computes the determinant of the matrix C=g.g'
180 // after the elements of C have been smoothed.
181 // g is the vector of first derivatives (gx,gy)'
182 // It relies only on first derivatives.
183 //
184 // Currently uses somewhat inefficient multi-pass method.
185 // Could be improved.
187  const vil_image_view<float>& gy,
188  vil_image_view<float>& corner_im)
189 {
190  vil_image_view<float> tmp_im,work_im, gx2,gy2,gxy;
191  vil_gauss_filter_5tap_params smooth_params(1.0);
192 
193  // Compute smoothed products of gradients
194  vil_math_image_product(gx,gx,tmp_im);
195  vil_gauss_filter_5tap(tmp_im,gx2,smooth_params,work_im);
196 
197  vil_math_image_product(gy,gy,tmp_im);
198  vil_gauss_filter_5tap(tmp_im,gy2,smooth_params,work_im);
199 
200  vil_math_image_product(gx,gy,tmp_im);
201  vil_gauss_filter_5tap(tmp_im,gxy,smooth_params,work_im);
202 
203  // Compute gx2*gy2 - gxy*gxy at each pixel
204  vil_math_image_product(gx2,gy2,corner_im);
205  vil_math_image_product(gxy,gxy,tmp_im);
206  vil_math_add_image_fraction(corner_im,1.0f,tmp_im,-1.0f);
207 }
Smooths images.
Various functions for manipulating image views.
Various mathematical manipulations of 2D images.
Estimate corner positions using Forstner/Harris approach.
Concrete view of image data of type T held in memory.
Definition: vil_fwd.h:13
void vil_math_image_product(const vil_image_view< aT > &imA, const vil_image_view< bT > &imB, vil_image_view< sumT > &im_product)
Compute pixel-wise product of two images (im_prod(i,j) = imA(i,j)*imB(i,j).
Definition: vil_math.h:736
void vil_gauss_filter_5tap(const srcT *src_im, std::ptrdiff_t src_ystep, unsigned ni, unsigned nj, destT *dest_im, std::ptrdiff_t dest_ystep, const vil_gauss_filter_5tap_params &params, destT *work)
Smooth a single plane src_im to produce dest_im.
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.
void vil_fill_col(vil_image_view< T > &view, unsigned i, T value)
Fill column i in view with given value.
Definition: vil_fill.h:148
unsigned ni() const
Width.
unsigned nj() const
Height.
void vil_corners_rohr(const vil_image_view< float > &grad_i, const vil_image_view< float > &grad_j, vil_image_view< float > &dest)
Compute corner strength using Rohr's recommended method.
unsigned nplanes() const
Number of planes.
void vil_corners(const vil_image_view< float > &grad_i, const vil_image_view< float > &grad_j, vil_image_view< float > &dest, double k)
Compute Forstner/Harris corner strength function given gradient images.
Definition: vil_corners.cxx:24
void vil_math_add_image_fraction(vil_image_view< aT > &imA, scaleT fa, const vil_image_view< bT > &imB, scaleT fb)
imA = fa*imA + fb*imB (Useful for moving averages!).
Definition: vil_math.h:1060
std::ptrdiff_t istep() const
Add this to your pixel pointer to get next i pixel.
void vil_fill_row(vil_image_view< T > &view, unsigned j, T value)
Fill row j in view with given value.
Definition: vil_fill.h:133