libcvd
distance_transform.h
1 #ifndef CVD_INC_DISTANCE_TRANSFORM_HPP
2 #define CVD_INC_DISTANCE_TRANSFORM_HPP
3 
4 #include <cmath>
5 #include <cvd/vision_exceptions.h>
6 
7 #include <algorithm>
8 #include <cmath>
9 #include <cvd/image.h>
10 #include <limits>
11 #include <vector>
12 
13 namespace CVD
14 {
15 
16 template <class Precision = double>
18 {
19  // Implements
20  // Distance Transforms of Sampled Functions
21  // Pedro F. Felzenszwalb Daniel P. Huttenlocher
22 
23  public:
25  : sz(ImageRef(-1, -1))
26  , big_number(1'000'000'000) //Hmm, why doesn't HUGE_VAL work?
27  //Anyway, hilariously small number here so it works with int, too.
28  {
29  }
30 
31  private:
32  inline void transform_row(const int n)
33  {
34  v[0] = 0; //std::numeric_limits<Precision>::infinity();
35  z[0] = -big_number; //std::numeric_limits<Precision>::infinity();
36  z[1] = +big_number; // std::numeric_limits<Precision>::infinity();
37  int k = 0;
38  for(int q = 1; q < n; q++)
39  {
40  Precision s = ((f[q] + (q * q)) - (f[v[k]] + (v[k] * v[k]))) / (2 * q - 2 * v[k]);
41  while(s <= z[k])
42  {
43  k--;
44  s = ((f[q] + (q * q)) - (f[v[k]] + (v[k] * v[k]))) / (2 * q - 2 * v[k]);
45  }
46  k++;
47  v[k] = q;
48  z[k] = s;
49  z[k + 1] = +big_number; //std::numeric_limits<Precision>::infinity();
50  }
51  k = 0;
52  for(int q = 0; q < n; q++)
53  {
54  while(z[k + 1] < q)
55  {
56  k++;
57  }
58  d[q] = ((q - v[k]) * (q - v[k])) + f[v[k]];
59  pos[q] = q > v[k] ? (q - v[k]) : (v[k] - q);
60  //cout << "n=" << n << " q=" << q << " d[q]=" << d[q] << " v[k]=" << v[k] << " f[v[k]]=" << f[v[k]] << endl;
61  }
62  }
63 
64  void transform_image(BasicImage<Precision>& DT)
65  {
66  const ImageRef img_sz(DT.size());
67  for(int x = 0; x < img_sz.x; x++)
68  {
69  for(int y = 0; y < img_sz.y; y++)
70  {
71  f[y] = DT[y][x];
72  }
73  transform_row(img_sz.y);
74  for(int y = 0; y < img_sz.y; y++)
75  {
76  DT[y][x] = d[y];
77  }
78  }
79  //#if 0
80  for(int y = 0; y < img_sz.y; y++)
81  {
82  for(int x = 0; x < img_sz.x; x++)
83  {
84  f[x] = DT[y][x];
85  }
86  transform_row(img_sz.x);
87  for(int x = 0; x < img_sz.x; x++)
88  {
89  DT[y][x] = d[x];
90  }
91  }
92  //#endif
93  }
94 
95  template <class Functor>
98  void transform_image_with_ADT(BasicImage<Precision>& DT, BasicImage<ImageRef>& ADT, const Functor& func)
99  {
100  const ImageRef img_sz(DT.size());
101  const double maxdist = img_sz.x * img_sz.y;
102  for(int x = 0; x < img_sz.x; x++)
103  {
104  for(int y = 0; y < img_sz.y; y++)
105  {
106  f[y] = DT[y][x];
107  }
108  transform_row(img_sz.y);
109  for(int y = 0; y < img_sz.y; y++)
110  {
111  DT[y][x] = d[y];
112  }
113  }
114  for(int y = 0; y < img_sz.y; y++)
115  {
116  for(int x = 0; x < img_sz.x; x++)
117  {
118  f[x] = DT[y][x];
119  }
120  transform_row(img_sz.x);
121  for(int x = 0; x < img_sz.x; x++)
122  {
123  DT[y][x] = d[x];
124  const double hyp = d[x];
125  if(hyp >= maxdist)
126  {
127  ADT[y][x] = ImageRef(-1, -1);
128  continue;
129  }
130  const double dx = pos[x];
131  const double dy = sqrt(hyp - dx * dx);
132  const int ddy = static_cast<int>(dy);
133  const ImageRef candA(static_cast<int>(x - dx), static_cast<int>(y - ddy));
134  const ImageRef candB(static_cast<int>(x - dx), static_cast<int>(y + ddy));
135  const ImageRef candC(static_cast<int>(x + dx), static_cast<int>(y - ddy));
136  const ImageRef candD(static_cast<int>(x + dx), static_cast<int>(y + ddy));
139  if(DT.in_image(candA) && func(candA))
140  {
141  ADT[y][x] = candA;
142  }
143  else if(DT.in_image(candB) && func(candB))
144  {
145  ADT[y][x] = candB;
146  }
147  else if(DT.in_image(candC) && func(candC))
148  {
149  ADT[y][x] = candC;
150  }
151  else if(DT.in_image(candD) && func(candD))
152  {
153  ADT[y][x] = candD;
154  }
155  else
156  {
157  //ADT[y][x] = ImageRef(-1,-1);
159  throw Exceptions::Vision::BadInput("DistanceTransformEuclidean: no points set");
160  }
161  }
162  }
163  }
164 
165  void resize(const ImageRef& new_size)
166  {
167  if(new_size != sz)
168  {
169  sz = new_size;
170  int m(std::max(new_size.x, new_size.y));
171  d.resize(m);
172  v.resize(m);
173  f.resize(m);
174  pos.resize(m);
175  z.resize(m + 1);
176  }
177  }
178 
179  public:
180  template <class T>
181  void transform_ADT(const BasicImage<T>& feature, BasicImage<Precision>& DT, BasicImage<ImageRef>& ADT)
182  {
183  if(feature.size() != DT.size())
184  throw Exceptions::Vision::IncompatibleImageSizes(__FUNCTION__);
185 
186  if(feature.size() != ADT.size())
187  throw Exceptions::Vision::IncompatibleImageSizes(__FUNCTION__);
188 
189  resize(feature.size());
190 
191  apply_functor(DT, NotZero<T>(feature));
192 
193  transform_image_with_ADT(DT, ADT, NotZero<T>(feature));
194  }
195 
196  void transform(BasicImage<Precision>& out)
197  {
198  resize(out.size());
199  transform_image(out);
200  }
201 
202  template <class C>
203  struct NotZero
204  {
205  NotZero(const BasicImage<C>& im_)
206  : im(im_)
207  {
208  }
209 
210  const BasicImage<C>& im;
211  bool operator()(const ImageRef& i) const
212  {
213  return im[i] != 0;
214  }
215  };
216 
217  template <class Out, class Functor>
218  void apply_functor(BasicImage<Out>& out, const Functor& f)
219  {
220  for(int y = 0; y < out.size().y; y++)
221  for(int x = 0; x < out.size().x; x++)
222  if(f(ImageRef(x, y)))
223  out[y][x] = 0;
224  else
225  out[y][x] = big_number;
226  }
227 
228  private:
229  ImageRef sz;
230  int big_number;
231  std::vector<Precision> d;
232  std::vector<int> v;
233  std::vector<Precision> z;
234  std::vector<Precision> f;
235  std::vector<Precision> pos;
236 };
237 
244 template <class T, class Q>
246 {
247  if(in.size() != out.size())
248  throw Exceptions::Vision::IncompatibleImageSizes(__FUNCTION__);
250  dt.apply_functor(out, typename DistanceTransformEuclidean<Q>::template NotZero<T>(in));
251  dt.transform(out);
252 }
253 
261 template <class T, class Q>
263 {
264  if(in.size() != out.size())
265  throw Exceptions::Vision::IncompatibleImageSizes(__FUNCTION__);
267  dt.transform_ADT(in, out, lookup_DT);
268 }
269 
276 template <class T, class Q>
278 {
280  for(int y = 0; y < out.size().y; y++)
281  for(int x = 0; x < out.size().x; x++)
282  out[y][x] = sqrt(out[y][x]);
283 }
284 
292 template <class T, class Q>
294 {
295  euclidean_distance_transform_sq(in, out, lookup_DT);
296  for(int y = 0; y < out.size().y; y++)
297  for(int x = 0; x < out.size().x; x++)
298  out[y][x] = sqrt(out[y][x]);
299 }
300 
301 #ifndef DOXYGEN_IGNORE_INTERNAL
302 namespace Internal
303 {
304  template <class C>
306  {
307  };
308 
309  template <class T>
311  {
312  ImagePromise(const BasicImage<T>& in_)
313  : in(in_)
314  {
315  }
316 
317  const BasicImage<T>& in;
318 
319  template <class C>
320  void execute(Image<C>& im)
321  {
322  im.resize(in.size());
324  }
325  };
326 };
327 
328 template <class T>
330 {
331  using namespace Internal;
333 }
334 #else
335 
341 template <class T>
343 #endif
344 
347 };
348 #endif
Input images have incompatible dimensions.
Definition: vision_exceptions.h:26
Definition: distance_transform.h:17
void euclidean_distance_transform_sq(const BasicImage< T > &in, BasicImage< Q > &out)
Compute squared Euclidean distance transform using the Felzenszwalb & Huttenlocher algorithm...
Definition: distance_transform.h:245
Definition: vision_exceptions.h:40
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
Definition: distance_transform.h:305
void euclidean_distance_transform(const BasicImage< T > &in, BasicImage< Q > &out)
Compute Euclidean distance transform using the Felzenszwalb & Huttenlocher algorithm.
Definition: distance_transform.h:277
void resize(const ImageRef &size)
Resize the image (destroying the data).
Definition: image.h:731
int x
The x co-ordinate.
Definition: image_ref.h:172
Definition: image_ref.h:29
Definition: distance_transform.h:203
Definition: image.h:62
A generic image class to manage a block of arbitrarily padded data as an image.
Definition: image.h:273
int y
The y co-ordinate.
Definition: image_ref.h:173
A full image which manages its own data.
Definition: image.h:623