libcvd
harris_corner.h
1 #ifndef CVD_HARRIS_CORNER_H
2 #define CVD_HARRIS_CORNER_H
3 
4 #include <algorithm>
5 #include <cmath>
6 #include <cstdlib>
7 #include <utility>
8 #include <vector>
9 
10 #include <cvd/convolution.h>
11 #include <cvd/image.h>
12 
13 namespace CVD
14 {
15 
16 namespace Harris
17 {
19  template <class C>
20  inline C sq(const C& c)
21  {
22  return c * c;
23  }
24 
27  struct HarrisScore
28  {
29  static float Compute(float xx, float xy, float yy)
30  {
31  return (xx * yy - xy * xy) - 0.04 * sq(xx + yy);
32  }
33  };
34 
38  {
39  static float Compute(float xx, float xy, float yy)
40  {
41  float l1 = xx + yy + std::sqrt(sq(xx - yy) + 4.0 * xy * xy);
42  float l2 = xx + yy - std::sqrt(sq(xx - yy) + 4.0 * xy * xy);
43  return std::min(abs(l1), std::abs(l2));
44  }
45  };
46 
49  struct PosInserter
50  {
51  static void insert(std::vector<ImageRef>& i, const std::pair<float, ImageRef>& p)
52  {
53  i.push_back(p.second);
54  }
55  };
56 
59  struct PairInserter
60  {
61  static void insert(std::vector<std::pair<float, ImageRef>>& i, const std::pair<float, ImageRef>& p)
62  {
63  i.push_back(p);
64  }
65  };
66 }
67 
81 template <class Score, class Inserter, class C, class B>
82 void harrislike_corner_detect(const BasicImage<B>& i, C& c, unsigned int N, float blur, float sigmas, BasicImage<float>& xx, BasicImage<float>& xy, BasicImage<float>& yy)
83 {
84  using std::greater;
85  using std::make_pair;
86  using std::pair;
87  using std::vector;
88 
89  if(!(i.size() == xx.size() && i.size() == xy.size() && i.size() == yy.size()))
90  throw Exceptions::Convolution::IncompatibleImageSizes("harrislike_corner_detect");
91 
92  zeroBorders(xx);
93  zeroBorders(xy);
94  zeroBorders(yy);
95 
96  typedef typename Pixel::traits<B>::wider_type gType;
97 
98  //Compute gradients
99  for(int y = 1; y < i.size().y - 1; y++)
100  for(int x = 1; x < i.size().x - 1; x++)
101  {
102 
103  //FIXME use fast-casting using an arrsy for byte to float conversion.
104  gType gx = (gType)i[y][x - 1] - i[y][x + 1];
105  gType gy = (gType)i[y - 1][x] - i[y + 1][x];
106 
107  //Compute the gradient moments
108  xx[y][x] = gx * gx;
109  xy[y][x] = gx * gy;
110  yy[y][x] = gy * gy;
111  }
112 
113  convolveGaussian(xx, xx, blur, sigmas);
114  convolveGaussian(xy, xy, blur, sigmas);
115  convolveGaussian(yy, yy, blur, sigmas);
116 
117  //Avoid computing the score along the image borders where the
118  //result of the convolution is not valid.
119  int kspread = (int)ceil(sigmas * blur);
120 
121  //Compute harris score
122  for(int y = kspread; y < i.size().y - kspread; y++)
123  for(int x = kspread; x < i.size().x - kspread; x++)
124  xx[y][x] = Score::Compute(xx[y][x], xy[y][x], yy[y][x]);
125 
126  vector<pair<float, ImageRef>> corner_heap;
127  corner_heap.reserve(N + 1);
128 
129  typedef greater<pair<float, ImageRef>> minheap_compare;
130 
131  //Keep the N best corner scores, using a min-heap. This allows us to always
132  //remove the smallest element, keeping the largest ones.
133 
134  //C++ heap functions use std::less to create a max-heap, growing from the
135  //beginning of the array. This allows for convenient sorting. pop_heap
136  //gets the largest element, and the heap is shrunk by 1. This element
137  //is then put on to the end of the array, ie the spot freed up by shrinking
138  //the heap by 1. Repeating this procedure will sort the heap, pulling out
139  //the largest elements and placing them at the end. The resulting array will
140  //then be sorted by std::less.
141 
142  //Therefore we need to use std::greater to create a min-heap
143 
144  //The first element in the array will be the smallest value
145 
146  //Find local maxima
147  for(int y = kspread; y < i.size().y - kspread; y++)
148  for(int x = kspread; x < i.size().x - kspread; x++)
149  {
150  float c = xx[y][x];
151 
152  if(c > xx[y - 1][x - 1] && c > xx[y - 1][x + 0] && c > xx[y - 1][x + 1] && c > xx[y - 0][x - 1] && c > xx[y - 0][x + 1] && c > xx[y + 1][x - 1] && c > xx[y + 1][x + 0] && c > xx[y + 1][x + 1])
153  {
154  if(corner_heap.size() <= N || c > corner_heap[0].first)
155  {
156  corner_heap.push_back(make_pair(c, ImageRef(x, y)));
157  push_heap(corner_heap.begin(), corner_heap.end(), minheap_compare());
158  }
159 
160  if(corner_heap.size() > N)
161  {
162  pop_heap(corner_heap.begin(), corner_heap.end(), minheap_compare());
163  corner_heap.pop_back();
164  }
165  }
166  }
167 
168  for(unsigned int i = 0; i < corner_heap.size(); i++)
169  Inserter::insert(c, corner_heap[i]);
170 }
171 
172 template <class C>
173 void harris_corner_detect(const BasicImage<C>& i, std::vector<ImageRef>& c, unsigned int N, float blur = 1.0, float sigmas = 3.0)
174 {
175  Image<float> xx(i.size()), xy(i.size()), yy(i.size());
176  harrislike_corner_detect<Harris::HarrisScore, Harris::PosInserter>(i, c, N, blur, sigmas, xx, xy, yy);
177 }
178 
179 template <class C>
180 void shitomasi_corner_detect(const BasicImage<C>& i, std::vector<ImageRef>& c, unsigned int N, float blur = 1.0, float sigmas = 3.0)
181 {
182  Image<float> xx(i.size()), xy(i.size()), yy(i.size());
183  harrislike_corner_detect<Harris::ShiTomasiScore, Harris::PosInserter>(i, c, N, blur, sigmas, xx, xy, yy);
184 }
185 }
186 #endif
All classes and functions are within the CVD namespace.
Definition: argb.h:6
ImageRef size() const
What is the size of this image?
Definition: image.h:557
Used to save corner positions from harrislike_corner_detect.
Definition: harris_corner.h:49
void harrislike_corner_detect(const BasicImage< B > &i, C &c, unsigned int N, float blur, float sigmas, BasicImage< float > &xx, BasicImage< float > &xy, BasicImage< float > &yy)
Generic Harris corner detection function.
Definition: harris_corner.h:82
Compute the score according to Shi-Tomasi.
Definition: harris_corner.h:37
Used to save corner positions and scores from harrislike_corner_detect.
Definition: harris_corner.h:59
Input images have incompatible dimensions.
Definition: convolution.h:117
Definition: image_ref.h:29
void zeroBorders(BasicImage< T > &I)
Set the one-pixel border (top, bottom, sides) of an image to zero values.
Definition: utility.h:109
A generic image class to manage a block of arbitrarily padded data as an image.
Definition: image.h:273
A full image which manages its own data.
Definition: image.h:623
Compute the corner score according to Harris.
Definition: harris_corner.h:27