A Survey of Gaussian Convolution Algorithms
strategy_gaussian_conv.c
Go to the documentation of this file.
1 
20 #include "strategy_gaussian_conv.h"
21 #include <stdlib.h>
22 #include <string.h>
23 #include "gaussian_conv_fir.h"
24 #include "gaussian_conv_dct.h"
25 #include "gaussian_conv_box.h"
26 #include "gaussian_conv_ebox.h"
27 #include "gaussian_conv_sii.h"
28 #include "gaussian_conv_am.h"
29 #include "gaussian_conv_deriche.h"
30 #include "gaussian_conv_vyv.h"
31 
32 struct gconv_
33 {
34  num *dest;
35  const num *src;
37  long N;
38  long stride;
39  const char *algo;
40  double sigma;
41  int K;
42  num tol;
43  void *coeffs;
44  void (*execute)(gconv*);
45  void (*free)(gconv*);
46 };
47 
48 #ifndef DOXYGEN_SHOULD_SKIP_THIS
49 static int gconv_fir_plan(gconv *g);
50 static int gconv_dct_plan(gconv *g);
51 static int gconv_box_plan(gconv *g);
52 static int gconv_ebox_plan(gconv *g);
53 static int gconv_sii_plan(gconv *g);
54 static int gconv_am_orig_plan(gconv *g);
55 static int gconv_am_plan(gconv *g);
56 static int gconv_deriche_plan(gconv *g);
57 static int gconv_vyv_plan(gconv *g);
58 #endif
59 
72 gconv* gconv_plan(num *dest, const num *src, long N, long stride,
73  const char *algo, double sigma, int K, num tol)
74 {
75  struct gconv_algo_entry
76  {
77  const char *name;
78  int (*plan)(gconv*);
79  } algos[] = {
80  {"fir", gconv_fir_plan},
81  {"dct", gconv_dct_plan},
82  {"box", gconv_box_plan},
83  {"ebox", gconv_ebox_plan},
84  {"sii", gconv_sii_plan},
85  {"am_orig", gconv_am_orig_plan},
86  {"am", gconv_am_plan},
87  {"deriche", gconv_deriche_plan},
88  {"vyv", gconv_vyv_plan}
89  };
90  gconv *g;
91  size_t i;
92 
93  if (!dest || !src || N <= 0 || sigma <= 0 || tol < 0 || tol > 1
94  || !(g = (gconv *)malloc(sizeof(gconv))))
95  return NULL;
96 
97  g->dest = dest;
98  g->src = src;
99  g->buffer = NULL;
100  g->N = N;
101  g->stride = stride;
102  g->algo = algo;
103  g->K = K;
104  g->sigma = sigma;
105  g->tol = tol;
106  g->coeffs = NULL;
107 
108  for (i = 0; i < sizeof(algos)/sizeof(*algos); ++i)
109  if (!strcmp(algo, algos[i].name))
110  {
111  if (algos[i].plan(g))
112  return g;
113  else
114  break;
115  }
116 
117  gconv_free(g);
118  return NULL;
119 }
120 
126 {
127  g->execute(g);
128 }
129 
135 {
136  if (g)
137  {
138  if (g->free)
139  g->free(g);
140 
141  free(g);
142  }
143 }
144 
145 #ifndef DOXYGEN_SHOULD_SKIP_THIS
146 /* FIR filtering. */
147 static void gconv_fir_execute(gconv *g);
148 static void gconv_fir_free(gconv *g);
149 
150 static int gconv_fir_plan(gconv *g)
151 {
152  g->execute = gconv_fir_execute;
153  g->free = gconv_fir_free;
154  return (g->coeffs = malloc(sizeof(fir_coeffs)))
155  && fir_precomp((fir_coeffs *)g->coeffs, g->sigma, g->tol);
156 }
157 
158 static void gconv_fir_execute(gconv *g)
159 {
161  g->dest, g->src, g->N, g->stride);
162 }
163 
164 static void gconv_fir_free(gconv *g)
165 {
166  if (g->coeffs)
167  {
168  fir_free((fir_coeffs *)g->coeffs);
169  free(g->coeffs);
170  }
171 }
172 
173 /* DCT (discrete cosine transform) based convolution. */
174 static void gconv_dct_execute(gconv *g);
175 static void gconv_dct_free(gconv *g);
176 
177 static int gconv_dct_plan(gconv *g)
178 {
179  g->execute = gconv_dct_execute;
180  g->free = gconv_dct_free;
181  return (g->coeffs = malloc(sizeof(dct_coeffs)))
182  && dct_precomp((dct_coeffs *)g->coeffs, g->dest, g->src,
183  g->N, g->stride, g->sigma);
184 }
185 
186 static void gconv_dct_execute(gconv *g)
187 {
189 }
190 
191 static void gconv_dct_free(gconv *g)
192 {
193  if (g->coeffs)
194  {
195  dct_free((dct_coeffs *)g->coeffs);
196  free(g->coeffs);
197  }
198 }
199 
200 /* Box filtering. */
201 static void gconv_box_execute(gconv *g);
202 static void gconv_box_free(gconv *g);
203 
204 static int gconv_box_plan(gconv *g)
205 {
206  g->execute = gconv_box_execute;
207  g->free = gconv_box_free;
208  return ((g->K > 0) && (g->buffer = malloc(sizeof(num)*g->N))) ? 1 : 0;
209 }
210 
211 static void gconv_box_execute(gconv *g)
212 {
213  box_gaussian_conv(g->dest, g->buffer, g->src, g->N, g->stride,
214  g->sigma, g->K);
215 }
216 
217 static void gconv_box_free(gconv *g)
218 {
219  if (g->buffer)
220  free(g->buffer);
221 }
222 
223 /* Extended box filter. */
224 static void gconv_ebox_execute(gconv *g);
225 static void gconv_ebox_free(gconv *g);
226 
227 static int gconv_ebox_plan(gconv *g)
228 {
229  g->execute = gconv_ebox_execute;
230  g->free = gconv_ebox_free;
231 
232  if ((g->K <= 0) || !(g->buffer = malloc(sizeof(num) * g->N))
233  || !(g->coeffs = malloc(sizeof(ebox_coeffs))))
234  return 0;
235 
236  ebox_precomp((ebox_coeffs *)g->coeffs, g->sigma, g->K);
237  return 1;
238 }
239 
240 static void gconv_ebox_execute(gconv *g)
241 {
243  g->dest, g->buffer, g->src, g->N, g->stride);
244 }
245 
246 static void gconv_ebox_free(gconv *g)
247 {
248  if (g->buffer)
249  free(g->buffer);
250  if (g->coeffs)
251  free(g->coeffs);
252 }
253 
254 /* SII Stacked integral images. */
255 static void gconv_sii_execute(gconv *g);
256 static void gconv_sii_free(gconv *g);
257 
258 static int gconv_sii_plan(gconv *g)
259 {
260  g->execute = gconv_sii_execute;
261  g->free = gconv_sii_free;
262 
263  if (!SII_VALID_K(g->K) || !(g->coeffs = malloc(sizeof(sii_coeffs))))
264  return 0;
265 
266  sii_precomp((sii_coeffs *)g->coeffs, g->sigma, g->K);
267 
268  return (g->buffer = malloc(sizeof(num) * sii_buffer_size(
269  *((sii_coeffs *)g->coeffs), g->N))) ? 1 : 0;
270 }
271 
272 static void gconv_sii_execute(gconv *g)
273 {
275  g->dest, g->buffer, g->src, g->N, g->stride);
276 }
277 
278 static void gconv_sii_free(gconv *g)
279 {
280  if (g->buffer)
281  free(g->buffer);
282  if (g->coeffs)
283  free(g->coeffs);
284 }
285 
286 /* Alvarez-Mazorra, original algorithm. */
287 static void gconv_am_orig_execute(gconv *g);
288 
289 static int gconv_am_orig_plan(gconv *g)
290 {
291  g->execute = gconv_am_orig_execute;
292  g->free = NULL;
293  return 1;
294 }
295 
296 static void gconv_am_orig_execute(gconv *g)
297 {
298  am_gaussian_conv(g->dest, g->src, g->N, 1,
299  g->sigma, g->K, g->tol, 0);
300 }
301 
302 /* Alvarez-Mazorra with proposed regression on parameter q. */
303 static void gconv_am_execute(gconv *g);
304 
305 static int gconv_am_plan(gconv *g)
306 {
307  g->execute = gconv_am_execute;
308  g->free = NULL;
309  return (g->K > 0);
310 }
311 
312 static void gconv_am_execute(gconv *g)
313 {
314  am_gaussian_conv(g->dest, g->src, g->N, 1,
315  g->sigma, g->K, g->tol, 1);
316 }
317 
318 /* Deriche recursive filtering. */
319 static void gconv_deriche_execute(gconv *g);
320 static void gconv_deriche_free(gconv *g);
321 
322 static int gconv_deriche_plan(gconv *g)
323 {
324  g->execute = gconv_deriche_execute;
325  g->free = gconv_deriche_free;
326 
327  if (!DERICHE_VALID_K(g->K)
328  || !(g->buffer = malloc(sizeof(num) * 2 * g->N))
329  || !(g->coeffs = malloc(sizeof(deriche_coeffs))))
330  return 0;
331 
332  deriche_precomp((deriche_coeffs *)g->coeffs, g->sigma, g->K, g->tol);
333  return 1;
334 }
335 
336 static void gconv_deriche_execute(gconv *g)
337 {
339  g->dest, g->buffer, g->src, g->N, g->stride);
340 }
341 
342 static void gconv_deriche_free(gconv *g)
343 {
344  if (g->buffer)
345  free(g->buffer);
346  if (g->coeffs)
347  free(g->coeffs);
348 }
349 
350 /* Vliet-Young-Verbeek recursive filtering. */
351 static void gconv_vyv_execute(gconv *g);
352 static void gconv_vyv_free(gconv *g);
353 
354 static int gconv_vyv_plan(gconv *g)
355 {
356  g->execute = gconv_vyv_execute;
357  g->free = gconv_vyv_free;
358 
359  if (!VYV_VALID_K(g->K) || !(g->coeffs = malloc(sizeof(vyv_coeffs))))
360  return 0;
361 
362  vyv_precomp((vyv_coeffs *)g->coeffs, g->sigma, g->K, g->tol);
363  return 1;
364 }
365 
366 static void gconv_vyv_execute(gconv *g)
367 {
369  g->dest, g->src, g->N, g->stride);
370 }
371 
372 static void gconv_vyv_free(gconv *g)
373 {
374  if (g->coeffs)
375  free(g->coeffs);
376 }
377 #endif