[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

gaborfilter.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 2002-2004 by Ullrich Koethe and Hans Meine */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 
37 #ifndef VIGRA_GABORFILTER_HXX
38 #define VIGRA_GABORFILTER_HXX
39 
40 #include "imagecontainer.hxx"
41 #include "config.hxx"
42 #include "stdimage.hxx"
43 #include "copyimage.hxx"
44 #include "transformimage.hxx"
45 #include "combineimages.hxx"
46 #include "utilities.hxx"
47 #include "multi_shape.hxx"
48 
49 #include <functional>
50 #include <vector>
51 #include <cmath>
52 
53 namespace vigra {
54 
55 /** \addtogroup GaborFilter Gabor Filter
56  Functions to create or apply gabor filter (latter based on FFTW).
57 */
58 //@{
59 
60 /********************************************************/
61 /* */
62 /* createGaborFilter */
63 /* */
64 /********************************************************/
65 
66 /** \brief Create a gabor filter in frequency space.
67 
68  The orientation is given in radians, the other parameters are the
69  center frequency (for example 0.375 or smaller) and the two
70  angular and radial sigmas of the gabor filter. (See \ref
71  angularGaborSigma() for an explanation of possible values.)
72 
73  The energy of the filter is explicitly normalized to 1.0.
74 
75  <b> Declarations:</b>
76 
77  pass 2D array views:
78  \code
79  namespace vigra {
80  template <class T, class S>
81  void
82  createGaborFilter(MultiArrayView<2, T, S> dest,
83  double orientation, double centerFrequency,
84  double angularSigma, double radialSigma);
85  }
86  \endcode
87 
88  \deprecatedAPI{createGaborFilter}
89  pass \ref ImageIterators and \ref DataAccessors :
90  \code
91  namespace vigra {
92  template <class DestImageIterator, class DestAccessor>
93  void createGaborFilter(DestImageIterator destUpperLeft,
94  DestImageIterator destLowerRight,
95  DestAccessor da,
96  double orientation, double centerFrequency,
97  double angularSigma, double radialSigma)
98  }
99  \endcode
100  use argument objects in conjunction with \ref ArgumentObjectFactories :
101  \code
102  namespace vigra {
103  template <class DestImageIterator, class DestAccessor>
104  void createGaborFilter(triple<DestImageIterator,
105  DestImageIterator,
106  DestAccessor> dest,
107  double orientation, double centerFrequency,
108  double angularSigma, double radialSigma)
109  }
110  \endcode
111  \deprecatedEnd
112 
113  <b> Usage:</b>
114 
115  <b>\#include</b> <vigra/gaborfilter.hxx><br/>
116  Namespace: vigra
117 
118  \code
119  MultiArray<2, float> gabor(w,h);
120 
121  createGaborFilter(gabor, orient, freq,
122  angularGaborSigma(directionCount, freq),
123  radialGaborSigma(freq));
124  \endcode
125 
126  \deprecatedUsage{createGaborFilter}
127  \code
128  vigra::FImage gabor(w,h);
129 
130  vigra::createGaborFilter(destImageRange(gabor), orient, freq,
131  angularGaborSigma(directionCount, freq),
132  radialGaborSigma(freq));
133  \endcode
134  \deprecatedEnd
135 */
137 
138 template <class DestImageIterator, class DestAccessor>
139 void createGaborFilter(DestImageIterator destUpperLeft,
140  DestImageIterator destLowerRight, DestAccessor da,
141  double orientation, double centerFrequency,
142  double angularSigma, double radialSigma)
143 {
144  int w = int(destLowerRight.x - destUpperLeft.x);
145  int h = int(destLowerRight.y - destUpperLeft.y);
146 
147  double squaredSum = 0.0;
148  double cosTheta= VIGRA_CSTD::cos(orientation);
149  double sinTheta= VIGRA_CSTD::sin(orientation);
150 
151  double radialSigma2 = radialSigma*radialSigma;
152  double angularSigma2 = angularSigma*angularSigma;
153 
154  double wscale = w % 1 ?
155  1.0f / (w-1) :
156  1.0f / w;
157  double hscale = h % 1 ?
158  1.0f / (h-1) :
159  1.0f / h;
160 
161  int dcX= (w+1)/2, dcY= (h+1)/2;
162 
163  double u, v;
164  for ( int y=0; y<h; y++, destUpperLeft.y++ )
165  {
166  typename DestImageIterator::row_iterator dix = destUpperLeft.rowIterator();
167 
168  v = hscale * ((h - (y - dcY))%h - dcY);
169  for ( int x=0; x<w; x++, dix++ )
170  {
171  u= wscale*((x - dcX + w)%w - dcX);
172 
173  double uu = cosTheta*u + sinTheta*v - centerFrequency;
174  double vv = -sinTheta*u + cosTheta*v;
175  double gabor;
176 
177  gabor = VIGRA_CSTD::exp(-0.5*(uu*uu / radialSigma2 + vv*vv / angularSigma2));
178  squaredSum += gabor * gabor;
179  da.set( gabor, dix );
180  }
181  }
182  destUpperLeft.y -= h;
183 
184  // clear out DC value and remove it from the squared sum
185  double dcValue = da(destUpperLeft);
186  squaredSum -= dcValue * dcValue;
187  da.set( 0.0, destUpperLeft );
188 
189  // normalize energy to one
190  double factor = VIGRA_CSTD::sqrt(squaredSum);
191  for ( int y=0; y<h; y++, destUpperLeft.y++ )
192  {
193  typename DestImageIterator::row_iterator dix = destUpperLeft.rowIterator();
194 
195  for ( int x=0; x<w; x++, dix++ )
196  {
197  da.set( da(dix) / factor, dix );
198  }
199  }
200 }
201 
202 template <class DestImageIterator, class DestAccessor>
203 inline void
204 createGaborFilter(triple<DestImageIterator, DestImageIterator, DestAccessor> dest,
205  double orientation, double centerFrequency,
206  double angularSigma, double radialSigma)
207 {
208  createGaborFilter(dest.first, dest.second, dest.third,
209  orientation, centerFrequency,
210  angularSigma, radialSigma);
211 }
212 
213 template <class T, class S>
214 inline void
215 createGaborFilter(MultiArrayView<2, T, S> dest,
216  double orientation, double centerFrequency,
217  double angularSigma, double radialSigma)
218 {
219  createGaborFilter(destImageRange(dest),
220  orientation, centerFrequency,
221  angularSigma, radialSigma);
222 }
223 
224 /********************************************************/
225 /* */
226 /* radialGaborSigma */
227 /* */
228 /********************************************************/
229 
230 /** \brief Calculate sensible radial sigma for given parameters.
231 
232  For a brief introduction what is meant with "sensible" sigmas, see
233  \ref angularGaborSigma().
234 
235  <b> Declaration:</b>
236 
237  \code
238  namespace vigra {
239  double radialGaborSigma(double centerFrequency)
240  }
241  \endcode
242  */
243 
244 inline double radialGaborSigma(double centerFrequency)
245 {
246  double sfactor = 3.0 * VIGRA_CSTD::sqrt(VIGRA_CSTD::log(4.0));
247  return centerFrequency / sfactor;
248 }
249 
250 /********************************************************/
251 /* */
252 /* angularGaborSigma */
253 /* */
254 /********************************************************/
255 
256 /** \brief Calculate sensible angular sigma for given parameters.
257 
258  "Sensible" means: If you use a range of gabor filters for feature
259  detection, you are interested in minimal redundancy. This is hard
260  to define but one possible try is to arrange the filters in
261  frequency space, so that the half-peak-magnitude ellipses touch
262  each other.
263 
264  To do so, you must know the number of directions (first parameter
265  for the angular sigma function) and the center frequency of the
266  filter you want to calculate the sigmas for.
267 
268  The exact formulas are:
269  \code
270  sigma_radial= 1/sqrt(ln(4)) * centerFrequency/3
271  \endcode
272 
273  \code
274  sigma_angular= 1/sqrt(ln(4)) * tan(pi/(directions*2))
275  * sqrt(8/9) * centerFrequency
276  \endcode
277 
278  <b> Declaration:</b>
279 
280  \code
281  namespace vigra {
282  double angularGaborSigma(int directionCount, double centerFrequency)
283  }
284  \endcode
285  */
286 
287 inline double angularGaborSigma(int directionCount, double centerFrequency)
288 {
289  return VIGRA_CSTD::tan(M_PI/directionCount/2.0) * centerFrequency
290  * VIGRA_CSTD::sqrt(8.0 / (9 * VIGRA_CSTD::log(4.0)));
291 }
292 
293 /********************************************************/
294 /* */
295 /* GaborFilterFamily */
296 /* */
297 /********************************************************/
298 
299 /** \brief Family of gabor filters of different scale and direction.
300 
301  A GaborFilterFamily can be used to quickly create a whole family
302  of gabor filters in frequency space. Especially useful in
303  conjunction with \ref applyFourierFilterFamily, since it's derived
304  from \ref ImageArray.
305 
306  The filter parameters are chosen to make the center frequencies
307  decrease in octaves with increasing scale indices, and to make the
308  half-peak-magnitude ellipses touch each other to somewhat reduce
309  redundancy in the filter answers. This is done by using \ref
310  angularGaborSigma() and \ref radialGaborSigma(), you'll find more
311  information there.
312 
313  The template parameter ImageType should be a scalar image type suitable for filling in
314 
315  <b>\#include</b> <vigra/gaborfilter.hxx><br/>
316  Namespace: vigra
317 */
318 template <class ImageType,
319  class Alloc = typename ImageType::allocator_type::template rebind<ImageType>::other >
321 : public ImageArray<ImageType, Alloc>
322 {
324  int scaleCount_, directionCount_;
325  double maxCenterFrequency_;
326 
327 protected:
328  void initFilters()
329  {
330  for(int direction= 0; direction<directionCount_; direction++)
331  for(int scale= 0; scale<scaleCount_; scale++)
332  {
333  double angle = direction * M_PI / directionCount();
334  double centerFrequency =
335  maxCenterFrequency_ / VIGRA_CSTD::pow(2.0, (double)scale);
336  createGaborFilter(destImageRange(this->images_[filterIndex(direction, scale)]),
337  angle, centerFrequency,
338  angularGaborSigma(directionCount(), centerFrequency),
339  radialGaborSigma(centerFrequency));
340  }
341  }
342 
343 public:
344  enum { stdFilterSize= 128, stdDirectionCount= 6, stdScaleCount= 4 };
345 
346  /** Constructs a family of gabor filters in frequency
347  space. The filters will be calculated on construction, so
348  it makes sense to provide good parameters right now
349  although they can be changed later, too. If you leave them
350  out, the defaults are a \ref directionCount of 6, a \ref
351  scaleCount of 4 and a \ref maxCenterFrequency of
352  3/8(=0.375).
353  */
355  int directionCount = stdDirectionCount, int scaleCount = stdScaleCount,
356  double maxCenterFrequency = 3.0/8.0,
357  Alloc const & alloc = Alloc())
358  : ParentClass(directionCount*scaleCount, size, alloc),
359  scaleCount_(scaleCount),
360  directionCount_(directionCount),
361  maxCenterFrequency_(maxCenterFrequency)
362  {
363  initFilters();
364  }
365 
366  /** Convenience variant of the above constructor taking width
367  and height separately. Also, this one serves as default
368  constructor constructing 128x128 pixel filters.
369  */
370  GaborFilterFamily(int width= stdFilterSize, int height= -1,
371  int directionCount = stdDirectionCount, int scaleCount = stdScaleCount,
372  double maxCenterFrequency = 3.0/8.0,
373  Alloc const & alloc = Alloc())
375  Size2D(width, height > 0 ? height : width), alloc),
376  scaleCount_(scaleCount),
377  directionCount_(directionCount),
378  maxCenterFrequency_(maxCenterFrequency)
379  {
380  initFilters();
381  }
382 
383  /** Return the index of the filter with the given direction and
384  scale in this ImageArray. direction must in the range
385  0..directionCount()-1 and scale in the range
386  0..rangeCount()-1. This is useful for example if you used
387  \ref applyFourierFilterFamily() and got a resulting
388  ImageArray which still has the same order of images, but no
389  \ref getFilter() method anymore.
390  */
391  int filterIndex(int direction, int scale) const
392  {
393  return scale*directionCount()+direction;
394  }
395 
396  /** Return the filter with the given direction and
397  scale. direction must in the range 0..directionCount()-1
398  and scale in the range 0..rangeCount()-1.
399  <tt>filters.getFilter(direction, scale)</tt> is the same as
400  <tt>filters[filterIndex(direction, scale)]</tt>.
401  */
402  ImageType const & getFilter(int direction, int scale) const
403  {
404  return this->images_[filterIndex(direction, scale)];
405  }
406 
407  /** Resize all filters (causing their recalculation).
408  */
409  virtual void resizeImages(const Diff2D &newSize)
410  {
411  ParentClass::resizeImages(newSize);
412  initFilters();
413  }
414 
415  /** Query the number of filter scales available.
416  */
417  int scaleCount() const
418  { return scaleCount_; }
419 
420  /** Query the number of filter directions available.
421  */
422  int directionCount() const
423  { return directionCount_; }
424 
425  /** Change the number of directions / scales. This causes the
426  recalculation of all filters.
427  */
429  {
430  this->resize(directionCount * scaleCount);
431  scaleCount_ = scaleCount;
432  directionCount_ = directionCount;
433  initFilters();
434  }
435 
436  /** Return the center frequency of the filter(s) with
437  scale==0. Filters with scale>0 will have a center frequency
438  reduced in octaves:
439  <tt>centerFrequency= maxCenterFrequency / 2.0^scale</tt>
440  */
442  { return maxCenterFrequency_; }
443 
444  /** Change the center frequency of the filter(s) with
445  scale==0. See \ref maxCenterFrequency().
446  */
448  {
449  maxCenterFrequency_ = maxCenterFrequency;
450  initFilters();
451  }
452 };
453 
454 //@}
455 
456 } // namespace vigra
457 
458 #endif // VIGRA_GABORFILTER_HXX
Fundamental class template for arrays of equal-sized images.
Definition: imagecontainer.hxx:72
linalg::TemporaryMatrix< T > sin(MultiArrayView< 2, T, C > const &v)
virtual void resizeImages(const Diff2D &newSize)
Definition: gaborfilter.hxx:409
linalg::TemporaryMatrix< T > exp(MultiArrayView< 2, T, C > const &v)
double radialGaborSigma(double centerFrequency)
Calculate sensible radial sigma for given parameters.
Definition: gaborfilter.hxx:244
Two dimensional difference vector.
Definition: diff2d.hxx:185
int scaleCount() const
Definition: gaborfilter.hxx:417
double maxCenterFrequency()
Definition: gaborfilter.hxx:441
double angularGaborSigma(int directionCount, double centerFrequency)
Calculate sensible angular sigma for given parameters.
Definition: gaborfilter.hxx:287
void setMaxCenterFrequency(double maxCenterFrequency)
Definition: gaborfilter.hxx:447
Two dimensional size object.
Definition: diff2d.hxx:482
void setDirectionScaleCounts(int directionCount, int scaleCount)
Definition: gaborfilter.hxx:428
int directionCount() const
Definition: gaborfilter.hxx:422
int filterIndex(int direction, int scale) const
Definition: gaborfilter.hxx:391
size_type size() const
Definition: imagecontainer.hxx:228
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
GaborFilterFamily(int width=stdFilterSize, int height=-1, int directionCount=stdDirectionCount, int scaleCount=stdScaleCount, double maxCenterFrequency=3.0/8.0, Alloc const &alloc=Alloc())
Definition: gaborfilter.hxx:370
linalg::TemporaryMatrix< T > log(MultiArrayView< 2, T, C > const &v)
ImageType const & getFilter(int direction, int scale) const
Definition: gaborfilter.hxx:402
Family of gabor filters of different scale and direction.
Definition: gaborfilter.hxx:320
void resize(size_type newSize)
Definition: imagecontainer.hxx:310
linalg::TemporaryMatrix< T > tan(MultiArrayView< 2, T, C > const &v)
void createGaborFilter(...)
Create a gabor filter in frequency space.
linalg::TemporaryMatrix< T > cos(MultiArrayView< 2, T, C > const &v)
virtual void resizeImages(const Diff2D &newSize)
Definition: imagecontainer.hxx:418
GaborFilterFamily(const Diff2D &size, int directionCount=stdDirectionCount, int scaleCount=stdScaleCount, double maxCenterFrequency=3.0/8.0, Alloc const &alloc=Alloc())
Definition: gaborfilter.hxx:354
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.11.1 (Fri May 19 2017)