vil_find_peaks.h
Go to the documentation of this file.
1 // This is core/vil/algo/vil_find_peaks.h
2 #ifndef vil_find_peaks_h_
3 #define vil_find_peaks_h_
4 //:
5 // \file
6 // \brief Find peaks in image
7 // \author Tim Cootes
8 
9 #include <vector>
10 #include <vil/vil_image_view.h>
11 #ifdef _MSC_VER
12 # include <vcl_msvc_warnings.h>
13 #endif
14 
15 //: True if pixel at *im is strictly above 8 neighbours.
16 // \sa vil_is_plateau_3x3()
17 template <class T>
18 inline bool vil_is_peak_3x3(const T* im, std::ptrdiff_t i_step, std::ptrdiff_t j_step)
19 {
20  T v = *im;
21  return v > im[i_step]
22  && v > im[-i_step]
23  && v > im[j_step]
24  && v > im[-j_step]
25  && v > im[i_step+j_step]
26  && v > im[i_step-j_step]
27  && v > im[j_step-i_step]
28  && v > im[-i_step-j_step];
29 }
30 
31 //: Return (pi,pj) for all points in image strictly above their 8 neighbours
32 // Compute position of all local peaks (pi[k],pj[k]) above given threshold value.
33 // \param clear_list If true (the default) then empty lists before adding new examples
34 // \sa vil_find_plateaus_3x3()
35 // \relatesalso vil_image_view
36 template <class T>
37 inline void vil_find_peaks_3x3(std::vector<unsigned>& pi,
38  std::vector<unsigned>& pj,
39  const vil_image_view<T>& image,
40  const T& min_thresh,
41  bool clear_list=true)
42 {
43  if (clear_list) {
44  pi.resize(0);
45  pj.resize(0);
46  }
47  const unsigned ni1=image.ni()-1,nj1=image.nj()-1;
48  const std::ptrdiff_t istep = image.istep(),jstep=image.jstep();
49  const T* row = image.top_left_ptr()+istep+jstep;
50  for (unsigned j=1;j<nj1;++j,row+=jstep)
51  {
52  const T* pixel = row;
53  for (unsigned i=1;i<ni1;++i,pixel+=istep)
54  if (*pixel>=min_thresh && vil_is_peak_3x3(pixel,istep,jstep))
55  { pi.push_back(i); pj.push_back(j); }
56  }
57 }
58 
59 
60 //: Fit a paraboloid to a pixel and its 8 neighbors to interpolate the peak.
61 // \return true if the neighborhood produces a proper peak (not a saddle)
62 // return by reference the sub-pixel offsets from the pixel center
63 // \a dx and \a dy as well as the interpolated peak value \a val.
64 template<class T>
65 bool vil_interpolate_peak(const T* pixel,
66  std::ptrdiff_t istep, std::ptrdiff_t jstep,
67  double& dx, double& dy, double& val)
68 {
69  dx=dy=0;
70  //extract the neighborhood
71  // +-----+-----+-----+
72  // | p00 | p10 | p20 |
73  // +-----+-----+-----+
74  // | p01 | p11 | p21 |
75  // +-----+-----+-----+
76  // | p02 | p12 | p22 |
77  // +-----+-----+-----+
78  const T& p11 = *pixel;
79  const T& p01 = *(pixel-istep);
80  const T& p21 = *(pixel+istep);
81  const T& p10 = *(pixel-jstep);
82  const T& p12 = *(pixel+jstep);
83  const T& p00 = *(&p10-istep);
84  const T& p20 = *(&p10+istep);
85  const T& p02 = *(&p12-istep);
86  const T& p22 = *(&p12+istep);
87 
88  //Compute the 2nd order quadratic coefficients
89  // 1/6 * [ -1 0 +1 ]
90  // Ix = [ -1 0 +1 ]
91  // [ -1 0 +1 ]
92  double Ix =(-p00-p01-p02 +p20+p21+p22)/6.0;
93  // 1/6 * [ -1 -1 -1 ]
94  // Iy = [ 0 0 0 ]
95  // [ +1 +1 +1 ]
96  double Iy =(-p00-p10-p20 +p02+p12+p22)/6.0;
97  // 1/3 * [ +1 -2 +1 ]
98  // Ixx = [ +1 -2 +1 ]
99  // [ +1 -2 +1 ]
100  double Ixx = ((p00+p01+p02 +p20+p21+p22)-2.0*(p10+p11+p12))/3.0;
101  // 1/4 * [ +1 0 -1 ]
102  // Ixy = [ 0 0 0 ]
103  // [ -1 0 +1 ]
104  double Ixy = (p00+p22 -p02-p20)/4.0;
105  // 1/3 * [ +1 +1 +1 ]
106  // Iyy = [ -2 -2 -2 ]
107  // [ +1 +1 +1 ]
108  double Iyy = ((p00+p10+p20 +p02+p12+p22)-2.0*(p01+p11+p21))/3.0;
109 
110  //
111  // The next bit is to find the extremum of the fitted surface by setting its
112  // partial derivatives to zero. We need to solve the following linear system :
113  // Given the fitted surface is
114  // I(x,y) = Io + Ix x + Iy y + 1/2 Ixx x^2 + Ixy x y + 1/2 Iyy y^2
115  // we solve for the maximum (x,y),
116  //
117  // [ Ixx Ixy ] [ dx ] + [ Ix ] = [ 0 ] (dI/dx = 0)
118  // [ Ixy Iyy ] [ dy ] [ Iy ] [ 0 ] (dI/dy = 0)
119  //
120  double det = Ixx*Iyy - Ixy*Ixy;
121  // det>0 corresponds to a true local extremum otherwise a saddle point
122  if (det<=0)
123  return false;
124 
125  dx = (Iy*Ixy - Ix*Iyy) / det;
126  dy = (Ix*Ixy - Iy*Ixx) / det;
127  // more than one pixel away
128  if (dx > 1.0 || dx < -1.0 || dy > 1.0 || dy < -1.0)
129  return false;
130 
131  double Io =(p00+p01+p02 +p10+p11+p12 +p20+p21+p22)/9.0;
132 
133  val = Io + (Ix + 0.5*Ixx*dx + Ixy*dy)*dx + (Iy + 0.5*Iyy*dy)*dy;
134 
135  return true;
136 }
137 
138 
139 //: Return sub-pixel (px,py,val) for all points in image strictly above their 8 neighbours
140 // Interpolation sub-pixel position of all local peaks (px[k],py[k])
141 // above given threshold value by fitting a paraboloid.
142 // Interpolated peak values are returned in \a val.
143 // \param clear_list If true (the default) then empty lists before adding new examples.
144 // \relatesalso vil_image_view
145 template <class T>
146 inline void vil_find_peaks_3x3_subpixel(std::vector<double>& px,
147  std::vector<double>& py,
148  std::vector<double>& val,
149  const vil_image_view<T>& image,
150  const T& min_thresh,
151  bool clear_list=true)
152 {
153  if (clear_list) {
154  px.resize(0);
155  py.resize(0);
156  val.resize(0);
157  }
158  const unsigned ni1=image.ni()-1,nj1=image.nj()-1;
159  const std::ptrdiff_t istep = image.istep(),jstep=image.jstep();
160  const T* row = image.top_left_ptr()+istep+jstep;
161  double dx,dy,v;
162  for (unsigned j=1;j<nj1;++j,row+=jstep)
163  {
164  const T* pixel = row;
165  for (unsigned i=1;i<ni1;++i,pixel+=istep)
166  if (*pixel>=min_thresh && vil_is_peak_3x3(pixel,istep,jstep) &&
167  vil_interpolate_peak(pixel,istep,jstep,dx,dy,v))
168  {
169  px.push_back(i+dx);
170  py.push_back(j+dy);
171  val.push_back(v);
172  }
173  }
174 }
175 
176 #endif // vil_find_peaks_h_
Concrete view of image data of type T held in memory.
Definition: vil_fwd.h:13
bool vil_interpolate_peak(const T *pixel, std::ptrdiff_t istep, std::ptrdiff_t jstep, double &dx, double &dy, double &val)
Fit a paraboloid to a pixel and its 8 neighbors to interpolate the peak.
std::ptrdiff_t jstep() const
Add this to your pixel pointer to get next j pixel.
unsigned ni() const
Width.
unsigned nj() const
Height.
#define v
void vil_find_peaks_3x3_subpixel(std::vector< double > &px, std::vector< double > &py, std::vector< double > &val, const vil_image_view< T > &image, const T &min_thresh, bool clear_list=true)
Return sub-pixel (px,py,val) for all points in image strictly above their 8 neighbours.
void vil_find_peaks_3x3(std::vector< unsigned > &pi, std::vector< unsigned > &pj, const vil_image_view< T > &image, const T &min_thresh, bool clear_list=true)
Return (pi,pj) for all points in image strictly above their 8 neighbours.
A base class reference-counting view of some image data.
bool vil_is_peak_3x3(const T *im, std::ptrdiff_t i_step, std::ptrdiff_t j_step)
True if pixel at *im is strictly above 8 neighbours.
T * top_left_ptr()
Pointer to the first (top left in plane 0) pixel.
std::ptrdiff_t istep() const
Add this to your pixel pointer to get next i pixel.