A Survey of Gaussian Convolution Algorithms
gaussian_conv_dct.c
Go to the documentation of this file.
1 
20 #include "gaussian_conv_dct.h"
21 #include <assert.h>
22 #include <math.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 #ifndef M_PI
27 
28 #define M_PI 3.14159265358979323846264338327950288
29 #endif
30 
53 int dct_precomp(dct_coeffs *c, num *dest, const num *src,
54  long N, long stride, double sigma)
55 {
56  const fftw_r2r_kind dct_2 = FFTW_REDFT10, dct_3 = FFTW_REDFT01;
57  double temp;
58  int length = N;
59 
60  assert(c && dest && src && N > 0 && stride != 0 && sigma > 0);
61  c->forward_plan = c->inverse_plan = NULL;
62 
63  if (!(c->forward_plan = FFT(plan_many_r2r)(1, &length, 1, (num *)src,
64  NULL, stride, 0, dest, NULL, stride, 0, &dct_2,
65  FFTW_ESTIMATE | ((src != dest) ? FFTW_PRESERVE_INPUT : 0)))
66  || !(c->inverse_plan = FFT(plan_many_r2r)(1, &length, 1, dest,
67  NULL, stride, 0, dest, NULL, stride, 0, &dct_3, FFTW_ESTIMATE)))
68  {
69  dct_free(c);
70  return 0;
71  }
72 
73  c->dest = dest;
74  c->src = src;
75  c->conv_type = DCT_GAUSSIAN_1D;
76  temp = (sigma * M_PI) / N;
77  c->dims.one.alpha = (num)(temp * temp / 2);
78  c->dims.one.N = N;
79  c->dims.one.stride = stride;
80  return 1;
81 }
82 
100 int dct_precomp_image(dct_coeffs *c, num *dest, const num *src,
101  int width, int height, int num_channels, double sigma)
102 {
103  const fftw_r2r_kind dct_2[] = {FFTW_REDFT10, FFTW_REDFT10};
104  const fftw_r2r_kind dct_3[] = {FFTW_REDFT01, FFTW_REDFT01};
105  const int dist = width * height;
106  double temp;
107  int size[2];
108 
109  assert(c && dest && src && width > 0 && height > 0 && sigma > 0);
110  size[1] = width;
111  size[0] = height;
112  c->forward_plan = c->inverse_plan = NULL;
113 
114  if (!(c->forward_plan = FFT(plan_many_r2r)(2, size, num_channels,
115  (num *)src, NULL, 1, dist, dest, NULL, 1, dist, dct_2,
116  FFTW_ESTIMATE | ((src != dest) ? FFTW_PRESERVE_INPUT : 0)))
117  || !(c->inverse_plan = FFT(plan_many_r2r)(2, size, num_channels,
118  dest, NULL, 1, dist, dest, NULL, 1, dist, dct_3, FFTW_ESTIMATE)))
119  {
120  dct_free(c);
121  return 0;
122  }
123 
124  c->dest = dest;
125  c->src = src;
126  c->conv_type = DCT_GAUSSIAN_IMAGE;
127  temp = (sigma * M_PI) / width;
128  c->dims.image.alpha_x = (num)(temp * temp / 2);
129  temp = (sigma * M_PI) / height;
130  c->dims.image.alpha_y = (num)(temp * temp / 2);
131  c->dims.image.width = width;
132  c->dims.image.height = height;
133  c->dims.image.num_channels = num_channels;
134  return 1;
135 }
136 
157 {
158  assert(c.forward_plan && c.inverse_plan);
159 
160  /* Perform the forward DCT-II transform. */
161  FFT(execute)(c.forward_plan);
162 
163  /* Perform spectral domain multiplication with the DCT-I transform of the
164  Gaussian, which is exp(-alpha n^2) for the nth mode. */
165  if (c.conv_type == DCT_GAUSSIAN_1D)
166  { /* Multiplication in one dimension. */
167  num denom = 2 * c.dims.one.N;
168  long n;
169 
170  for (n = 0; n < c.dims.one.N; ++n)
171  {
172  *c.dest *= ((num)exp(-c.dims.one.alpha * n * n)) / denom;
173  c.dest += c.dims.one.stride;
174  }
175  }
176  else
177  { /* Multiplication in two dimensions. */
178  num denom = 4 * ((num)c.dims.image.width)
179  * ((num)c.dims.image.height);
180  int x, y, channel;
181 
182  for (channel = 0; channel < c.dims.image.num_channels; ++channel)
183  for (y = 0; y < c.dims.image.height; ++y)
184  {
185  for (x = 0; x < c.dims.image.width; ++x)
186  c.dest[x] *= ((num)exp(
187  -c.dims.image.alpha_x * x * x
188  -c.dims.image.alpha_y * y * y)) / denom;
189 
190  c.dest += c.dims.image.width;
191  }
192  }
193 
194  /* Perform the inverse DCT-II transform. */
195  FFT(execute)(c.inverse_plan);
196  return;
197 }
198 
204 {
205  assert(c);
206 
207  if (c->inverse_plan)
208  FFT(destroy_plan)(c->inverse_plan);
209  if (c->forward_plan)
210  FFT(destroy_plan)(c->forward_plan);
211 
212  FFT(cleanup)();
213  c->forward_plan = c->inverse_plan = NULL;
214  return;
215 }