SMIL  1.0.4
filterGabor.hpp
1 /* __HEAD__
2  * Copyright (c) 2011-2016, Matthieu FAESSEL and ARMINES
3  * Copyright (c) 2017-2023, Centre de Morphologie Mathematique
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * * Neither the name of Matthieu FAESSEL, or ARMINES nor the
15  * names of its contributors may be used to endorse or promote products
16  * derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * Description :
31  * 2D Gabor filter implementation by Vincent Morard
32  *
33  * History :
34  * - XX/XX/XXXX - by Vincent Morard
35  * Just created it
36  * - 21/02/2019 - by Jose-Marcio Martins da Cruz
37  * Formatting and removing some warnings and minor differences
38  *
39  * __HEAD__ - Stop here !
40  */
41 
42 #ifndef __GABOR_FILTER_HPP__
43 #define __GABOR_FILTER_HPP__
44 
45 #include <math.h>
46 
47 namespace smil
48 {
49 #define VM_MAX(x, y) (((x) > (y)) ? (x) : (y))
50 
51  template <class T1, class T2>
52  static RES_T _computeGaborFilterConvolution(T1 *bufferIn, int W, int H,
53  double sigma, double theta,
54  double lambda, double psi,
55  double gamma, T2 *bufferOut)
56  {
57  int i, j, k, l;
58  int Xmax, Ymax;
59  int nstds = 3;
60  int dx, dy;
61 
62  double dXmax, dYmax;
63 
64  //**********************
65  // Generation of the kernel
66  //**********************
67  double sigma_x = sigma;
68  double sigma_y = sigma * gamma;
69 
70  // Bounding box
71  dXmax = VM_MAX(std::abs(nstds * sigma_x * cos(theta)),
72  std::abs(nstds * sigma_y * sin(theta)));
73  dYmax = VM_MAX(std::abs(nstds * sigma_x * sin(theta)),
74  std::abs(nstds * sigma_y * cos(theta)));
75  Xmax = (int) VM_MAX(1, std::ceil(dXmax));
76  Ymax = (int) VM_MAX(1, std::ceil(dYmax));
77  dx = 2 * Xmax + 1;
78  dy = 2 * Ymax + 1;
79 
80  double *x_theta = new double[dx * dy];
81  double *y_theta = new double[dx * dy];
82 
83  // 2D Rotation
84  for (i = 0; i < dx; i++)
85  for (j = 0; j < dy; j++) {
86  x_theta[i + j * dx] =
87  (i - dx / 2) * cos(theta) + (j - dy / 2) * sin(theta);
88  y_theta[i + j * dx] =
89  -(i - dx / 2) * sin(theta) + (j - dy / 2) * cos(theta);
90  }
91 
92  double *gabor = new double[dx * dy];
93  for (i = 0; i < dx; i++) {
94  for (j = 0; j < dy; j++) {
95  int pos = i + j * dx;
96 
97  gabor[pos] =
98  std::exp(-0.5 * ((x_theta[pos] * x_theta[pos]) / (sigma_x * sigma_x) +
99  (y_theta[pos] * y_theta[pos]) / (sigma_y * sigma_y))) *
100  cos(2 * 3.14159 / lambda * x_theta[pos] + psi);
101  }
102  }
103  delete[] x_theta;
104  delete[] y_theta;
105 
106  int I, J;
107  double D;
108 
109  //****************************
110  // Start of the convolution
111  //****************************
112  for (j = 0; j < H; j++)
113  for (i = 0; i < W; i++) {
114  D = 0;
115  for (k = -dx / 2; k <= dx / 2; k++)
116  for (l = -dy / 2; l <= dy / 2; l++) {
117  I = (i + k) % W;
118  J = (j + l) % H;
119  if (I < 0)
120  I += W; // Mirror
121  if (J < 0)
122  J += H;
123 
124  D += gabor[k + dx / 2 + (l + dx / 2) * dx] * bufferIn[I + J * W];
125  }
126  bufferOut[i + j * W] = (T2) D;
127  }
128 
129  delete[] gabor;
130 
131  return RES_OK;
132  }
133 
134  /*
135  *
136  */
137  template <class T1>
138  static void t_createGaborKernel(T1 *gabor, double sigma, double theta,
139  double lambda, double psi, double gamma)
140  {
141  int i, j, Xmax, Ymax, nstds = 3, dx, dy;
142  double dXmax, dYmax;
143 
144  //**********************
145  // Generation of the kernel
146  //**********************
147  double sigma_x = sigma;
148  double sigma_y = sigma * gamma;
149 
150  // Bounding box
151  dXmax = VM_MAX(std::fabs(nstds * sigma_x * cos(theta)),
152  std::fabs(nstds * sigma_y * sin(theta)));
153  dYmax = VM_MAX(std::fabs(nstds * sigma_x * sin(theta)),
154  std::fabs(nstds * sigma_y * cos(theta)));
155  Xmax = (int) VM_MAX(1, std::ceil(dXmax));
156  Ymax = (int) VM_MAX(1, std::ceil(dYmax));
157  dx = 2 * Xmax + 1;
158  dy = 2 * Ymax + 1;
159 
160  double *x_theta = new double[dx * dy];
161  double *y_theta = new double[dx * dy];
162 
163  // 2D Rotation
164  for (i = 0; i < dx; i++)
165  for (j = 0; j < dy; j++) {
166  x_theta[i + j * dx] =
167  (i - dx / 2) * cos(theta) + (j - dy / 2) * sin(theta);
168  y_theta[i + j * dx] =
169  -(i - dx / 2) * sin(theta) + (j - dy / 2) * cos(theta);
170  }
171 
172  for (j = 0; j < dy; j++)
173  for (i = 0; i < dx; i++)
174  gabor[i + j * dx] =
175  (T1) std::exp(-0.5 * ((x_theta[i + j * dx] * x_theta[i + j * dx]) /
176  (sigma_x * sigma_x) +
177  (y_theta[i + j * dx] * y_theta[i + j * dx]) /
178  (sigma_y * sigma_y))) *
179  cos(2 * 3.14159 / lambda * x_theta[i + j * dx] + psi);
180  delete[] x_theta;
181  delete[] y_theta;
182  }
183 
184  /*
185  *
186  */
187  template <class T>
188  RES_T gaborFilterConvolution(const Image<T> &imIn, double sigma,
189  double theta, double lambda, double psi,
190  double gamma, Image<T> &imOut)
191  {
192  ASSERT_ALLOCATED(&imIn, &imOut);
193  ASSERT_SAME_SIZE(&imIn, &imOut);
194 
195  ImageFreezer freeze(imOut);
196 
197  size_t S[3];
198  imIn.getSize(S);
199 
200  if (S[2] > 1) {
201  // This is a 3D Image...
202  return RES_ERR;
203  }
204 
205  typename ImDtTypes<T>::lineType bufferIn = imIn.getPixels();
206  typename ImDtTypes<T>::lineType bufferOut = imOut.getPixels();
207 
208  _computeGaborFilterConvolution(bufferIn, S[0], S[1], sigma, theta, lambda,
209  psi, gamma, bufferOut);
210 
211  return RES_OK;
212  }
213 
214  /*
215  *
216  */
217  template <class T>
218  RES_T gaborFilterConvolutionNorm(const Image<T> &imIn, double sigma,
219  double theta, double lambda, double psi,
220  double gamma, double Min, double Max,
221  Image<T> &imOut, Image<T> &imGabor)
222  {
223  ASSERT_ALLOCATED(&imIn, &imOut, &imGabor);
224  ASSERT_SAME_SIZE(&imIn, &imOut, &imGabor);
225 
226  RES_T res = gaborFilterConvolution(imIn, sigma, theta, lambda, psi, gamma,
227  imGabor);
228  if (res != RES_OK) {
229  // tell something
230  return res;
231  }
232 
233  size_t S[3];
234  imIn.getSize(S);
235 
236  if (S[2] > 1) {
237  // This is a 3D Image...
238  return RES_ERR;
239  }
240 
241  typename ImDtTypes<T>::lineType bufferGabor = imGabor.getPixels();
242  typename ImDtTypes<T>::lineType bufferOut = imOut.getPixels();
243 
244  int W, H;
245  W = S[0];
246  H = S[1];
247 
248  T dtMax = imOut.getDataTypeMax();
249  for (int i = W * H - 1; i >= 0; i--) {
250  bufferOut[i] = (T)((bufferGabor[i] - Min) / (Max - Min) * dtMax);
251  }
252  return RES_OK;
253  }
254 
255  /*
256  *
257  */
258  template <class T>
259  RES_T gaborFilterConvolutionNormAuto(const Image<T> &imIn, double sigma,
260  double theta, double lambda,
261  double psi, double gamma, double *Min,
262  double *Max, Image<T> &imOut,
263  Image<T> &imGabor)
264  {
265  ASSERT_ALLOCATED(&imIn, &imOut, &imGabor);
266  ASSERT_SAME_SIZE(&imIn, &imOut, &imGabor);
267 
268  RES_T res = gaborFilterConvolution(imIn, sigma, theta, lambda, psi, gamma,
269  imGabor);
270  if (res != RES_OK) {
271  // tell something
272  return res;
273  }
274 
275  size_t S[3];
276  imIn.getSize(S);
277 
278  if (S[2] > 1) {
279  // This is a 3D Image...
280  return RES_ERR;
281  }
282 
283  typename ImDtTypes<T>::lineType bufferGabor = imGabor.getPixels();
284  typename ImDtTypes<T>::lineType bufferOut = imOut.getPixels();
285 
286  int W, H;
287  W = S[0];
288  H = S[1];
289 
290  *Min = bufferGabor[0];
291  *Max = bufferGabor[0];
292  for (int i = W * H - 1; i > 0; i--) {
293  if (*Min > bufferGabor[i])
294  *Min = bufferGabor[i];
295  if (*Max < bufferGabor[i])
296  *Max = bufferGabor[i];
297  }
298 
299  T dtMax = imOut.getDataTypeMax();
300  for (int i = W * H - 1; i >= 0; i--) {
301  bufferOut[i] = (T)((bufferGabor[i] - *Min) / (*Max - *Min) * dtMax);
302  }
303  return RES_OK;
304  }
305 } // namespace smil
306 
307 #endif
void getSize(size_t *w, size_t *h, size_t *d) const
Get image size.
Definition: DBaseImage.h:118
Definition: DBaseImage.h:386
Main Image class.
Definition: DImage.hpp:57
lineType getPixels() const
Get the pixels as a 1D array.
Definition: DImage.hpp:105
RES_T gaborFilterConvolution(const Image< T > &imIn, double sigma, double theta, double lambda, double psi, double gamma, Image< T > &imOut)
gaborFilterConvolution Gabor Filter
Definition: filterGabor.hpp:188
RES_T gaborFilterConvolutionNorm(const Image< T > &imIn, double sigma, double theta, double lambda, double psi, double gamma, double Min, double Max, Image< T > &imOut, Image< T > &imGabor)
gaborFilterConvolutionNorm Gabor Filter (normalized between Min and Max)
Definition: filterGabor.hpp:218
RES_T gaborFilterConvolutionNormAuto(const Image< T > &imIn, double sigma, double theta, double lambda, double psi, double gamma, double *Min, double *Max, Image< T > &imOut, Image< T > &imGabor)
gaborFilterConvolutionNormAuto Gabor Filter (automatically normalized)
Definition: filterGabor.hpp:259
RES_T exp(const Image< T1 > &imIn, Image< T2 > &imOut, int base=0)
exp() - exponential of an image
Definition: DImageArith.hpp:881