vil_quad_distance_function.h
Go to the documentation of this file.
1 #ifndef vil_quad_distance_function_h_
2 #define vil_quad_distance_function_h_
3 //:
4 // \file
5 // \brief Functions to compute quadratic distance functions
6 // \author Tim Cootes
7 
8 #include <vector>
9 #include <vil/vil_image_view.h>
10 #ifdef _MSC_VER
11 # include <vcl_msvc_warnings.h>
12 #endif
13 #include <cassert>
14 
15 //: Add parabola y=y0+(x-x0)^2 to lower envelope defined by (x,y,z)
16 // Parabolas are y' = y[i]+a(x'-x[i])^2
17 // Parabola i defines the envelope in the range (z[i],z[i+1]).
18 inline void vil_update_parabola_set(std::vector<double>& x,
19  std::vector<double>& y,
20  std::vector<double>& z, double a,
21  double x0, double y0, double n)
22 {
23  size_t k=x.size()-1;
24  while (true)
25  {
26  // Compute intercept of parabola centred at x0 with that at v[k]
27  // New parabola is below old for all x'>s
28  double new_z = 0.5*((y0-y[k])/a + (x0*x0-x[k]*x[k]))/(x0-x[k]);
29  if (new_z>n) return; // Only useful outsize (0,n) so discard
30  if (new_z>z[k])
31  {
32  x.push_back(x0);
33  y.push_back(y0);
34  z.push_back(new_z);
35  return;
36  }
37  if (k==0) // new_z<=0.0 since z[0]=0.0
38  {
39  // This parabola dominates in valid region so far
40  x[0]=x0; y[0]=y0; z[0]=0.0;
41  return;
42  }
43 
44  // Remove parabola k and repeat
45  x.erase(x.begin()+k);
46  y.erase(y.begin()+k);
47  z.erase(z.begin()+k);
48  --k;
49  }
50 }
51 
52 //: Compute parabolas forming lower envelope from set over range [0,n)
53 // Set of parabolas y=src[i*s_step]+a(x-i)^2 i=0..n-1
54 // Select those defining lower envelope in range [0,n)
55 // On exit, selected parabolas are y' = y[i]+(x'-x[i])^2
56 // Parabola i defines the envelope in the range (z[i],z[i+1]).
57 // Thus z.size()==x.size()+1
58 template<class srcT>
59 inline void vil_quad_envelope(const srcT* src,std::ptrdiff_t s_step,
60  size_t n,
61  std::vector<double>& x,
62  std::vector<double>& y,
63  std::vector<double>& z, double a)
64 {
65  x.resize(1); x[0]=0.0;
66  y.resize(1); y[0]=double(*src);
67  z.resize(1); z[0]=0.0;
68  src+=s_step;
69  for (unsigned int x0=1;x0<n;++x0,src+=s_step)
70  {
71  vil_update_parabola_set(x,y,z,a,x0,double(*src),double(n));
72  }
73  z.push_back(static_cast<double>(n));
74 }
75 
76 //: Sample from lower envelope of a set of parabolas
77 // Parabolas are y' = y[i]+a(x'-x[i])^2
78 // Parabola i defines the envelope in the range (z[i],z[i+1]).
79 // Thus z.size()==x.size()+1
80 template<class destT>
81 inline void vil_sample_quad_envelope(const std::vector<double>& x,
82  const std::vector<double>& y,
83  const std::vector<double>& z, double a,
84  destT* dest, std::ptrdiff_t d_step,
85  size_t n)
86 {
87  unsigned int k=0;
88  for (unsigned int i=0;i<n;++i,dest+=d_step)
89  {
90  while (z[k+1]<i) ++k; // Select relevant parabola
91  *dest = destT(y[k] + a*(i-x[k])*(i-x[k]));
92  }
93 }
94 
95 //: Sample from lower envelope of a set of parabolas
96 // Parabolas are y' = y[i]+a(x'-x[i])^2
97 // Parabola i defines the envelope in the range (z[i],z[i+1]).
98 // Thus z.size()==x.size()+1
99 //
100 // iT assumed to be an integer type (vxl_byte,short, int etc)
101 // On exit, pos[i*p_step] gives the x position of the parabola
102 // used to compute the envelope at position i.
103 template<class destT, class iT>
104 inline void vil_sample_quad_envelope_with_pos(const std::vector<double>& x,
105  const std::vector<double>& y,
106  const std::vector<double>& z,
107  double a,
108  destT* dest, std::ptrdiff_t d_step,
109  size_t n,
110  iT* pos, std::ptrdiff_t p_step)
111 {
112  unsigned int k=0;
113  for (unsigned int i=0;i<n;++i,dest+=d_step,pos+=p_step)
114  {
115  while (z[k+1]<i) ++k; // Select relevant parabola
116  *dest = destT(y[k] + a*(i-x[k])*(i-x[k]));
117  *pos = iT(x[k]+0.5); // x[k] assumed positive, round to nearest integer
118  }
119 }
120 
121 //: Compute quadratic distance function for a 1D function
122 // On exit dest(x) = min_i src(x+i)+a(i^2)
123 // Implementation of Felzenszwalb and Huttenlocher's algorithm,
124 // as described in "Distance Transforms of Sampled Functions".
125 //
126 // dest(x) = dest[x*d_step], src(x)=src[x*s_step]
127 template<class srcT, class destT>
128 inline void vil_quad_distance_function_1D(const srcT* src,std::ptrdiff_t s_step,
129  size_t n,
130  double a,
131  destT* dest, std::ptrdiff_t d_step)
132 {
133  std::vector<double> x,y,z;
134  vil_quad_envelope(src,s_step,n,x,y,z,a);
135  vil_sample_quad_envelope(x,y,z,a,dest,d_step,n);
136 }
137 
138 //: Compute quadratic distance function for a 1D function
139 // On exit dest(x) = min_i src(x+i)+a(i^2),
140 // pos(x) gives position (x+i) which leads to the minima
141 // Implementation of Felzenszwalb and Huttenlocher's algorithm,
142 // as described in "Distance Transforms of Sampled Functions".
143 //
144 // dest(x) = dest[x*d_step], src(x)=src[x*s_step], pos(x)=pos[x*p_step]
145 template<class srcT, class destT, class posT>
146 inline void vil_quad_distance_function_1D(const srcT* src,std::ptrdiff_t s_step,
147  unsigned int n,
148  double a,
149  destT* dest, std::ptrdiff_t d_step,
150  posT* pos, std::ptrdiff_t p_step)
151 {
152  std::vector<double> x,y,z;
153  vil_quad_envelope(src,s_step,n,x,y,z,a);
154  vil_sample_quad_envelope_with_pos(x,y,z,a,dest,d_step,n, pos,p_step);
155 }
156 
157 //: Apply quadratic distance transform along each row of src
158 //
159 // $ dest(x,y)=min_i,j (src(x+i,y+j)+ai(i^2)+aj(j^2)) $
160 // \relatesalso vil_image_view
161 template<class srcT, class destT>
163  double ai, double aj,
164  vil_image_view<destT>& dest)
165 {
166  assert(src.nplanes()==1);
167  unsigned int ni=src.ni(),nj=src.nj();
168  dest.set_size(ni,nj);
169  vil_image_view<destT> tmp(ni,nj); // Intermediate result
170  std::ptrdiff_t s_istep = src.istep(), s_jstep = src.jstep();
171  std::ptrdiff_t t_istep = tmp.istep(), t_jstep = tmp.jstep();
172  std::ptrdiff_t d_istep = dest.istep(), d_jstep = dest.jstep();
173 
174  const srcT* s_row = src.top_left_ptr();
175  destT* t_row = tmp.top_left_ptr();
176 
177  std::vector<double> x,y,z;
178 
179  // Apply transform along i direction to get tmp
180  for (unsigned int j=0;j<nj;++j, s_row+=s_jstep, t_row+=t_jstep)
181  {
182  vil_quad_envelope(s_row,s_istep,ni,x,y,z,ai);
183  vil_sample_quad_envelope(x,y,z,ai,t_row,t_istep,ni);
184  }
185  // Apply transform along j direction to get dest
186  destT* t_col = tmp.top_left_ptr();
187  destT* d_col = dest.top_left_ptr();
188  for (unsigned int i=0;i<ni;++i, d_col+=d_istep, t_col+=t_istep)
189  {
190  vil_quad_envelope(t_col,t_jstep,nj,x,y,z,aj);
191  vil_sample_quad_envelope(x,y,z,aj,d_col,d_jstep,nj);
192  }
193 }
194 
195 //: Apply quadratic distance transform along each row of src
196 //
197 // $ dest(x,y)=min_i,j (src(x+i,y+j)+ai(i^2)+aj(j^2)) $
198 // (pos(x,y,0),pos(x,y,1)) gives the position (x+i,y+j) leading to minima
199 // \relatesalso vil_image_view
200 template<class srcT, class destT, class posT>
202  double ai, double aj,
203  vil_image_view<destT>& dest,
205 {
206  assert(src.nplanes()==1);
207  unsigned int ni=src.ni(), nj=src.nj();
208  dest.set_size(ni,nj);
209  pos.set_size(ni,nj,2);
210  vil_image_view<destT> tmp(ni,nj); // Intermediate result
211  vil_image_view<posT> tmp_pos(ni,nj); // Intermediate result
212  std::ptrdiff_t s_istep = src.istep(), s_jstep = src.jstep();
213  std::ptrdiff_t t_istep = tmp.istep(), t_jstep = tmp.jstep();
214  std::ptrdiff_t d_istep = dest.istep(), d_jstep = dest.jstep();
215  std::ptrdiff_t tp_istep = tmp_pos.istep(), tp_jstep = tmp_pos.jstep();
216  std::ptrdiff_t p_istep = pos.istep(), p_jstep = pos.jstep();
217 
218  const srcT* s_row = src.top_left_ptr();
219  destT* t_row = tmp.top_left_ptr();
220  posT* tp_row = tmp_pos.top_left_ptr();
221 
222  std::vector<double> x,y,z;
223 
224  // Apply transform along i direction to get tmp
225  for (unsigned int j=0;j<nj;++j,s_row+=s_jstep,t_row+=t_jstep,tp_row+=tp_jstep)
226  {
227  vil_quad_envelope(s_row,s_istep,ni,x,y,z,ai);
228  vil_sample_quad_envelope_with_pos(x,y,z,ai,t_row,t_istep,ni,tp_row,tp_istep);
229  }
230  // Apply transform along j direction to get dest
231  destT* t_col = tmp.top_left_ptr();
232  destT* d_col = dest.top_left_ptr();
233  posT* pi_col = pos.top_left_ptr();
234  posT* pj_col = pi_col + pos.planestep();
235  posT* tp_col = tmp_pos.top_left_ptr();
236 
237  for (unsigned int i=0;i<ni;++i, d_col+=d_istep, t_col+=t_istep,
238  pi_col+=p_istep, pj_col+=p_istep,
239  tp_col+=tp_istep)
240  {
241  vil_quad_envelope(t_col,t_jstep,nj,x,y,z,aj);
242  vil_sample_quad_envelope_with_pos(x,y,z,aj,d_col,d_jstep,nj,pj_col,p_jstep);
243  // Now deduce the i position using the current offset
244  for (unsigned int j=0;j<nj;++j)
245  {
246  pi_col[j*p_jstep] = tp_col[pj_col[j*p_jstep]*tp_jstep];
247  }
248  }
249 }
250 
251 #endif
void vil_update_parabola_set(std::vector< double > &x, std::vector< double > &y, std::vector< double > &z, double a, double x0, double y0, double n)
Add parabola y=y0+(x-x0)^2 to lower envelope defined by (x,y,z).
void vil_quad_distance_function(const vil_image_view< srcT > &src, double ai, double aj, vil_image_view< destT > &dest)
Apply quadratic distance transform along each row of src.
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.
void vil_sample_quad_envelope(const std::vector< double > &x, const std::vector< double > &y, const std::vector< double > &z, double a, destT *dest, std::ptrdiff_t d_step, size_t n)
Sample from lower envelope of a set of parabolas.
std::ptrdiff_t jstep() const
Add this to your pixel pointer to get next j pixel.
unsigned ni() const
Width.
void vil_sample_quad_envelope_with_pos(const std::vector< double > &x, const std::vector< double > &y, const std::vector< double > &z, double a, destT *dest, std::ptrdiff_t d_step, size_t n, iT *pos, std::ptrdiff_t p_step)
Sample from lower envelope of a set of parabolas.
unsigned nj() const
Height.
std::ptrdiff_t planestep() const
Add this to your pixel pointer to get pixel on next plane.
void vil_quad_distance_function_1D(const srcT *src, std::ptrdiff_t s_step, size_t n, double a, destT *dest, std::ptrdiff_t d_step)
Compute quadratic distance function for a 1D function.
A base class reference-counting view of some image data.
T * top_left_ptr()
Pointer to the first (top left in plane 0) pixel.
unsigned nplanes() const
Number of planes.
void vil_quad_envelope(const srcT *src, std::ptrdiff_t s_step, size_t n, std::vector< double > &x, std::vector< double > &y, std::vector< double > &z, double a)
Compute parabolas forming lower envelope from set over range [0,n).
std::ptrdiff_t istep() const
Add this to your pixel pointer to get next i pixel.