A Survey of Gaussian Convolution Algorithms
gaussian_conv_fir.c
Go to the documentation of this file.
1 
20 #include "gaussian_conv_fir.h"
21 #include <assert.h>
22 #include <math.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include "filter_util.h"
26 #include "inverfc_acklam.h"
27 
43 static num *make_g_trunc(num sigma, long r)
44 {
45  num *g_trunc = NULL;
46 
47  if ((g_trunc = (num *)malloc(sizeof(num) * (r + 1))))
48  {
49  num accum = g_trunc[0] = 1.0;
50  long m;
51 
52  for (m = 1; m <= r; ++m)
53  {
54  num temp = m / sigma;
55  g_trunc[m] = exp(-0.5 * temp * temp);
56  accum += 2.0 * g_trunc[m];
57  }
58 
59  /* Normalize such that the filter has unit sum. */
60  for (m = 0; m <= r; ++m)
61  g_trunc[m] /= accum;
62  }
63 
64  return g_trunc;
65 }
66 
82 static void conv_sym(num *dest, const num *src, long N, long stride,
83  const num *h, long r)
84 {
85  long n;
86 
87  for (n = 0; n < N; ++n)
88  {
89  num accum = h[0] * src[stride * n];
90  long m;
91 
92  /* Compute \sum_m h_m ( src(n - m) + src(n + m) ). */
93  for (m = 1; m <= r; ++m)
94  accum += h[m] * (src[stride * extension(N, n - m)]
95  + src[stride * extension(N, n + m)]);
96 
97  dest[stride * n] = accum;
98  }
99 
100  return;
101 }
102 
117 int fir_precomp(fir_coeffs *c, double sigma, num tol)
118 {
119  assert(c && sigma > 0.0 && 0.0 < tol && tol < 1.0);
120  c->radius = (long)ceil(M_SQRT2 * sigma * inverfc(0.5 * tol));
121  return (c->g_trunc = make_g_trunc(sigma, c->radius)) ? 1 : 0;
122 }
123 
137 void fir_gaussian_conv(fir_coeffs c, num *dest, const num *src,
138  long N, long stride)
139 {
140  assert(c.g_trunc && dest && src && dest != src && N > 0 && stride != 0);
141  conv_sym(dest, src, N, stride, c.g_trunc, c.radius);
142  return;
143 }
144 
158 void fir_gaussian_conv_image(fir_coeffs c, num *dest, num *buffer,
159  const num *src, int width, int height, int num_channels)
160 {
161  const long num_pixels = ((long)width) * ((long)height);
162  int x, y, channel;
163 
164  assert(c.g_trunc && dest && buffer
165  && src && dest != src && num_pixels > 0);
166 
167  /* Loop over the image channels. */
168  for (channel = 0; channel < num_channels; ++channel)
169  {
170  num *dest_y = dest;
171  const num *src_y = src;
172 
173  /* Filter each column of the channel. */
174  for (x = 0; x < width; ++x)
175  conv_sym(dest + x, src + x, height, width, c.g_trunc, c.radius);
176 
177  /* Filter each row of the channel. */
178  for (y = 0; y < height; ++y)
179  {
180  conv_sym(buffer, dest_y, width, 1, c.g_trunc, c.radius);
181  memcpy(dest_y, buffer, sizeof(num) * width);
182  dest_y += width;
183  src_y += width;
184  }
185 
186  dest += num_pixels;
187  src += num_pixels;
188  }
189 
190  return;
191 }
192 
198 {
199  if (c && c->g_trunc)
200  {
201  free(c->g_trunc);
202  c->g_trunc = NULL;
203  }
204 
205  return;
206 }