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

orientedtensorfilters.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 2002-2004 by Ullrich Koethe */
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 #ifndef VIGRA_ORIENTEDTENSORFILTERS_HXX
37 #define VIGRA_ORIENTEDTENSORFILTERS_HXX
38 
39 #include <cmath>
40 #include "utilities.hxx"
41 #include "initimage.hxx"
42 #include "stdconvolution.hxx"
43 #include "multi_shape.hxx"
44 
45 namespace vigra {
46 
47 /** \addtogroup TensorImaging Tensor Image Processing
48 */
49 //@{
50 
51 /********************************************************/
52 /* */
53 /* hourGlassFilter */
54 /* */
55 /********************************************************/
56 
57 /** \brief Anisotropic tensor smoothing with the hourglass filter.
58 
59  This function implements anisotropic tensor smoothing by an
60  hourglass-shaped filters as described in
61 
62  U. K&ouml;the: <a href="http://hci.iwr.uni-heidelberg.de/people/ukoethe/papers/index.php#cite_structureTensor">
63  <i>"Edge and Junction Detection with an Improved Structure Tensor"</i></a>,
64  in: Proc. of 25th DAGM Symposium, Magdeburg 2003, Lecture Notes in Computer Science 2781,
65  pp. 25-32, Heidelberg: Springer, 2003
66 
67  It is closely related to the structure tensor (see \ref structureTensor()), but
68  replaces the linear tensor smoothing with a smoothing along edges only.
69  Smoothing across edges is largely suppressed. This means that the
70  image structure is preserved much better because nearby features
71  such as parallel edges are not blended into each other.
72 
73  The hourglass filter is typically applied to a gradient tensor, i.e. the
74  Euclidean product of the gradient with itself, which can be obtained by a
75  gradient operator followed with \ref vectorToTensor(), see example below.
76  The hourglass shape of the filter can be interpreted as indicating the likely
77  continuations of a local edge element. The parameter <tt>sigma</tt> determines
78  the radius of the hourglass (i.e. how far the influence of the edge element
79  reaches), and <tt>rho</tt> controls its opening angle (i.e. how narrow the
80  edge orientation os followed). Recommended values are <tt>sigma = 1.4</tt>
81  (or, more generally, two to three times the scale of the gradient operator
82  used in the first step), and <tt>rho = 0.4</tt> which corresponds to an
83  opening angle of 22.5 degrees to either side of the edge.
84 
85  <b> Declarations:</b>
86 
87  pass 2D array views:
88  \code
89  namespace vigra {
90  template <class T1, class S1,
91  class T2, class S2>
92  void
93  hourGlassFilter(MultiArrayView<2, T1, S1> const & src,
94  MultiArrayView<2, T2, S2> dest,
95  double sigma, double rho);
96  }
97  \endcode
98 
99  \deprecatedAPI{hourGlassFilter}
100  pass \ref ImageIterators and \ref DataAccessors :
101  \code
102  namespace vigra {
103  template <class SrcIterator, class SrcAccessor,
104  class DestIterator, class DestAccessor>
105  void hourGlassFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src,
106  DestIterator dul, DestAccessor dest,
107  double sigma, double rho);
108  }
109  \endcode
110  use argument objects in conjunction with \ref ArgumentObjectFactories :
111  \code
112  namespace vigra {
113  template <class SrcIterator, class SrcAccessor,
114  class DestIterator, class DestAccessor>
115  inline
116  void hourGlassFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
117  pair<DestIterator, DestAccessor> d,
118  double sigma, double rho);
119  }
120  \endcode
121  \deprecatedEnd
122 
123  <b> Usage:</b>
124 
125  <b>\#include</b> <vigra/orientedtensorfilters.hxx><br/>
126  Namespace: vigra
127 
128  \code
129  MultiArray<2, float> img(w,h);
130  MultiArray<2, TinyVector<float, 2> > gradient(w,h);
131  MultiArray<2, TinyVector<float, 3> > tensor(w,h), smoothedTensor(w,h);
132 
133  gaussianGradient(img, gradient, 1.0);
134  vectorToTensor(gradient, tensor);
135  hourGlassFilter(tensor, smoothedTensor, 2.0, 0.4);
136  \endcode
137 
138  \deprecatedUsage{hourGlassFilter}
139  \code
140  FImage img(w,h);
141  FVector2Image gradient(w,h);
142  FVector3Image tensor(w,h), smoothedTensor(w,h);
143 
144  gaussianGradient(srcImageRange(img), destImage(gradient), 1.0);
145  vectorToTensor(srcImageRange(gradient), destImage(tensor));
146  hourGlassFilter(srcImageRange(tensor), destImage(smoothedTensor), 2.0, 0.4);
147  \endcode
148  \deprecatedEnd
149 
150  \see vectorToTensor()
151 */
152 doxygen_overloaded_function(template <...> void hourGlassFilter)
153 
154 template <class SrcIterator, class SrcAccessor,
155  class DestIterator, class DestAccessor>
156 void hourGlassFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src,
157  DestIterator dul, DestAccessor dest,
158  double sigma, double rho)
159 {
160  vigra_precondition(sigma >= 0.0 && rho >= 0.0,
161  "hourGlassFilter(): sigma and rho must be >= 0.0");
162  vigra_precondition(src.size(sul) == 3,
163  "hourGlassFilter(): input image must have 3 bands.");
164  vigra_precondition(dest.size(dul) == 3,
165  "hourGlassFilter(): output image must have 3 bands.");
166 
167  // TODO: normalization
168 
169  int w = slr.x - sul.x;
170  int h = slr.y - sul.y;
171 
172  double radius = VIGRA_CSTD::floor(3.0*sigma + 0.5);
173  double sigma2 = -0.5 / sigma / sigma;
174  double rho2 = -0.5 / rho / rho;
175  double norm = 1.0 / (2.0 * M_PI * sigma * sigma);
176 
177  initImage(dul, dul+Diff2D(w,h), dest, NumericTraits<typename DestAccessor::value_type>::zero());
178 
179  for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
180  {
181  SrcIterator s = sul;
182  DestIterator d = dul;
183  for(int x=0; x<w; ++x, ++s.x, ++d.x)
184  {
185  double phi = 0.5 * VIGRA_CSTD::atan2(
186  2.0*src.getComponent(s,1),
187  (double)src.getComponent(s,0) - src.getComponent(s,2));
188  double u = VIGRA_CSTD::sin(phi);
189  double v = VIGRA_CSTD::cos(phi);
190 
191  double x0 = x - radius < 0 ? -x : -radius;
192  double y0 = y - radius < 0 ? -y : -radius;
193  double x1 = x + radius >= w ? w - x - 1 : radius;
194  double y1 = y + radius >= h ? h - y - 1 : radius;
195 
196  DestIterator dwul = d + Diff2D((int)x0, (int)y0);
197 
198  for(double yy=y0; yy <= y1; ++yy, ++dwul.y)
199  {
200  typename DestIterator::row_iterator dw = dwul.rowIterator();
201  for(double xx=x0; xx <= x1; ++xx, ++dw)
202  {
203  double r2 = xx*xx + yy*yy;
204  double p = u*xx - v*yy;
205  double q = v*xx + u*yy;
206  double kernel = (p == 0.0) ?
207  (q == 0.0) ?
208  norm :
209  0.0 :
210  norm * VIGRA_CSTD::exp(sigma2*r2 + rho2*q*q/p/p);
211  dest.set(dest(dw) + kernel*src(s), dw);
212  }
213  }
214  }
215  }
216 }
217 
218 template <class SrcIterator, class SrcAccessor,
219  class DestIterator, class DestAccessor>
220 inline void
221 hourGlassFilter(triple<SrcIterator, SrcIterator, SrcAccessor> s,
222  pair<DestIterator, DestAccessor> d,
223  double sigma, double rho)
224 {
225  hourGlassFilter(s.first, s.second, s.third, d.first, d.second, sigma, rho);
226 }
227 
228 template <class T1, class S1,
229  class T2, class S2>
230 inline void
231 hourGlassFilter(MultiArrayView<2, T1, S1> const & src,
232  MultiArrayView<2, T2, S2> dest,
233  double sigma, double rho)
234 {
235  vigra_precondition(src.shape() == dest.shape(),
236  "hourGlassFilter(): shape mismatch between input and output.");
237  hourGlassFilter(srcImageRange(src), destImage(dest), sigma, rho);
238 }
239 
240 /********************************************************/
241 /* */
242 /* ellipticGaussian */
243 /* */
244 /********************************************************/
245 
246 template <class SrcIterator, class SrcAccessor,
247  class DestIterator, class DestAccessor>
248 void ellipticGaussian(SrcIterator sul, SrcIterator slr, SrcAccessor src,
249  DestIterator dul, DestAccessor dest,
250  double sigmax, double sigmin)
251 {
252  vigra_precondition(sigmax >= sigmin && sigmin >= 0.0,
253  "ellipticGaussian(): "
254  "sigmax >= sigmin and sigmin >= 0.0 required");
255 
256  int w = slr.x - sul.x;
257  int h = slr.y - sul.y;
258 
259  double radius = VIGRA_CSTD::floor(3.0*sigmax + 0.5);
260  double sigmin2 = -0.5 / sigmin / sigmin;
261  double norm = 1.0 / (2.0 * M_PI * sigmin * sigmax);
262 
263  initImage(dul, dul+Diff2D(w,h), dest, NumericTraits<typename DestAccessor::value_type>::zero());
264 
265  for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
266  {
267  SrcIterator s = sul;
268  DestIterator d = dul;
269  for(int x=0; x<w; ++x, ++s.x, ++d.x)
270  {
271  typedef typename
272  NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType;
273  TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2);
274  TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2);
275  TmpType d3 = 2.0 * src.getComponent(s,1);
276  TmpType d4 = VIGRA_CSTD::sqrt(sq(d2) + sq(d3));
277  TmpType excentricity = 1.0 - (d1 - d4) / (d1 + d4);
278  double sigmax2 = -0.5 / sq((sigmax - sigmin)*excentricity + sigmin);
279 
280  double phi = 0.5 * VIGRA_CSTD::atan2(d3, d2);
281  double u = VIGRA_CSTD::sin(phi);
282  double v = VIGRA_CSTD::cos(phi);
283 
284  double x0 = x - radius < 0 ? -x : -radius;
285  double y0 = y - radius < 0 ? -y : -radius;
286  double x1 = x + radius >= w ? w - x - 1 : radius;
287  double y1 = y + radius >= h ? h - y - 1 : radius;
288 
289  DestIterator dwul = d + Diff2D((int)x0, (int)y0);
290 
291  for(double yy=y0; yy <= y1; ++yy, ++dwul.y)
292  {
293  typename DestIterator::row_iterator dw = dwul.rowIterator();
294  for(double xx=x0; xx <= x1; ++xx, ++dw)
295  {
296  double p = u*xx - v*yy;
297  double q = v*xx + u*yy;
298  double kernel = norm * VIGRA_CSTD::exp(sigmax2*p*p + sigmin2*q*q);
299  dest.set(dest(dw) + kernel*src(s), dw);
300  }
301  }
302  }
303  }
304 }
305 
306 template <class SrcIterator, class SrcAccessor,
307  class DestIterator, class DestAccessor>
308 inline void
309 ellipticGaussian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
310  pair<DestIterator, DestAccessor> dest,
311  double sigmax, double sigmin)
312 {
313  ellipticGaussian(src.first, src.second, src.third, dest.first, dest.second, sigmax, sigmin);
314 }
315 
316 template <class T1, class S1,
317  class T2, class S2>
318 inline void
319 ellipticGaussian(MultiArrayView<2, T1, S1> const & src,
320  MultiArrayView<2, T2, S2> dest,
321  double sigmax, double sigmin)
322 {
323  vigra_precondition(src.shape() == dest.shape(),
324  "ellipticGaussian(): shape mismatch between input and output.");
325  ellipticGaussian(srcImageRange(src), destImage(dest), sigmax, sigmin);
326 }
327 
328 /********************************************************/
329 /* */
330 /* kernels for orientedTrigonometricFilter */
331 /* */
332 /********************************************************/
333 
334 class FoerstnerKernelBase
335 {
336  public:
337  typedef double ResultType;
338  typedef double WeightType;
339  typedef DVector2Image::value_type VectorType;
340  typedef VectorType::value_type ValueType;
341 
342  FoerstnerKernelBase(double scale, bool ringShaped = false)
343  : radius_((int)(3.0*scale+0.5)),
344  weights_(2*radius_+1, 2*radius_+1),
345  vectors_(2*radius_+1, 2*radius_+1)
346  {
347  double norm = 1.0 / (2.0 * M_PI * scale * scale);
348  double s2 = -0.5 / scale / scale;
349 
350  for(int y = -radius_; y <= radius_; ++y)
351  {
352  for(int x = -radius_; x <= radius_; ++x)
353  {
354  double d2 = x*x + y*y;
355  double d = VIGRA_CSTD::sqrt(d2);
356  vectors_(x+radius_,y+radius_) = d != 0.0 ?
357  VectorType(x/d, -y/d) :
358  VectorType(ValueType(0), ValueType(0));
359  weights_(x+radius_,y+radius_) = ringShaped ?
360  norm * d2 * VIGRA_CSTD::exp(d2 * s2) :
361  norm * VIGRA_CSTD::exp(d2 * s2);
362  }
363  }
364  }
365 
366  ResultType operator()(int /*x*/, int /*y*/, VectorType const &) const
367  {
368  // isotropic filtering
369  return weights_(radius_, radius_);
370  }
371 
372  int radius_;
373  DImage weights_;
374  DVector2Image vectors_;
375 };
376 
377 class FoerstnerRingKernelBase
378 : public FoerstnerKernelBase
379 {
380  public:
381  FoerstnerRingKernelBase(double scale)
382  : FoerstnerKernelBase(scale, true)
383  {}
384 };
385 
386 class Cos2RingKernel
387 : public FoerstnerKernelBase
388 {
389  public:
390  typedef double ResultType;
391  typedef double WeightType;
392  typedef DVector2Image::value_type VectorType;
393 
394  Cos2RingKernel(double scale)
395  : FoerstnerKernelBase(scale, true)
396  {}
397 
398  ResultType operator()(int x, int y, VectorType const & v) const
399  {
400  if(x == 0 && y == 0)
401  return weights_(radius_, radius_);
402  double d = dot(vectors_(x+radius_, y+radius_), v);
403  return d * d * weights_(x+radius_, y+radius_);
404  }
405 };
406 
407 class Cos2Kernel
408 : public FoerstnerKernelBase
409 {
410  public:
411  typedef double ResultType;
412  typedef double WeightType;
413  typedef DVector2Image::value_type VectorType;
414 
415  Cos2Kernel(double scale)
416  : FoerstnerKernelBase(scale, false)
417  {}
418 
419  ResultType operator()(int x, int y, VectorType const & v) const
420  {
421  if(x == 0 && y == 0)
422  return weights_(radius_, radius_);
423  double d = dot(vectors_(x+radius_, y+radius_), v);
424  return d * d * weights_(x+radius_, y+radius_);
425  }
426 };
427 
428 class Sin2RingKernel
429 : public FoerstnerKernelBase
430 {
431  public:
432  typedef double ResultType;
433  typedef double WeightType;
434  typedef DVector2Image::value_type VectorType;
435 
436  Sin2RingKernel(double scale)
437  : FoerstnerKernelBase(scale, true)
438  {}
439 
440  ResultType operator()(int x, int y, VectorType const & v) const
441  {
442  if(x == 0 && y == 0)
443  return weights_(radius_, radius_);
444  double d = dot(vectors_(x+radius_, y+radius_), v);
445  return (1.0 - d * d) * weights_(x+radius_, y+radius_);
446  }
447 };
448 
449 class Sin2Kernel
450 : public FoerstnerKernelBase
451 {
452  public:
453  typedef double ResultType;
454  typedef double WeightType;
455  typedef DVector2Image::value_type VectorType;
456 
457  Sin2Kernel(double scale)
458  : FoerstnerKernelBase(scale, false)
459  {}
460 
461  ResultType operator()(int x, int y, VectorType const & v) const
462  {
463  if(x == 0 && y == 0)
464  return weights_(radius_, radius_);
465  double d = dot(vectors_(x+radius_, y+radius_), v);
466  return (1.0 - d * d) * weights_(x+radius_, y+radius_);
467  }
468 };
469 
470 class Sin6RingKernel
471 : public FoerstnerKernelBase
472 {
473  public:
474  typedef double ResultType;
475  typedef double WeightType;
476  typedef DVector2Image::value_type VectorType;
477 
478  Sin6RingKernel(double scale)
479  : FoerstnerKernelBase(scale, true)
480  {}
481 
482  ResultType operator()(int x, int y, VectorType const & v) const
483  {
484  if(x == 0 && y == 0)
485  return weights_(radius_, radius_);
486  double d = dot(vectors_(x+radius_, y+radius_), v);
487  return VIGRA_CSTD::pow(1.0 - d * d, 3) * weights_(x+radius_, y+radius_);
488  }
489 };
490 
491 class Sin6Kernel
492 : public FoerstnerKernelBase
493 {
494  public:
495  typedef double ResultType;
496  typedef double WeightType;
497  typedef DVector2Image::value_type VectorType;
498 
499  Sin6Kernel(double scale)
500  : FoerstnerKernelBase(scale, false)
501  {}
502 
503  ResultType operator()(int x, int y, VectorType const & v) const
504  {
505  if(x == 0 && y == 0)
506  return weights_(radius_, radius_);
507  double d = dot(vectors_(x+radius_, y+radius_), v);
508  return VIGRA_CSTD::pow(1.0 - d * d, 3) * weights_(x+radius_, y+radius_);
509  }
510 };
511 
512 class Cos6RingKernel
513 : public FoerstnerKernelBase
514 {
515  public:
516  typedef double ResultType;
517  typedef double WeightType;
518  typedef DVector2Image::value_type VectorType;
519 
520  Cos6RingKernel(double scale)
521  : FoerstnerKernelBase(scale, true)
522  {}
523 
524  ResultType operator()(int x, int y, VectorType const & v) const
525  {
526  if(x == 0 && y == 0)
527  return weights_(radius_, radius_);
528  double d = dot(vectors_(x+radius_, y+radius_), v);
529  return (1.0 - VIGRA_CSTD::pow(1.0 - d * d, 3)) * weights_(x+radius_, y+radius_);
530  }
531 };
532 
533 class Cos6Kernel
534 : public FoerstnerKernelBase
535 {
536  public:
537  typedef double ResultType;
538  typedef double WeightType;
539  typedef DVector2Image::value_type VectorType;
540 
541  Cos6Kernel(double scale)
542  : FoerstnerKernelBase(scale, false)
543  {}
544 
545  ResultType operator()(int x, int y, VectorType const & v) const
546  {
547  if(x == 0 && y == 0)
548  return weights_(radius_, radius_);
549  double d = dot(vectors_(x+radius_, y+radius_), v);
550  return (1.0 - VIGRA_CSTD::pow(1.0 - d * d, 3)) * weights_(x+radius_, y+radius_);
551  }
552 };
553 
554 /********************************************************/
555 /* */
556 /* orientedTrigonometricFilter */
557 /* */
558 /********************************************************/
559 
560 template <class SrcIterator, class SrcAccessor,
561  class DestIterator, class DestAccessor,
562  class Kernel>
563 void orientedTrigonometricFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src,
564  DestIterator dul, DestAccessor dest,
565  Kernel const & kernel)
566 {
567  vigra_precondition(src.size(sul) == 2,
568  "orientedTrigonometricFilter(): input image must have 2 bands.");
569  vigra_precondition(dest.size(dul) == 3,
570  "orientedTrigonometricFilter(): output image must have 3 bands.");
571 
572  int w = slr.x - sul.x;
573  int h = slr.y - sul.y;
574  int radius = kernel.radius_;
575 
576  typedef typename SrcAccessor::value_type VectorType;
577  typedef typename DestAccessor::value_type TensorType;
578 
579  initImage(dul, dul+Diff2D(w,h), dest, NumericTraits<TensorType>::zero());
580 
581  for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
582  {
583  SrcIterator s = sul;
584  DestIterator d = dul;
585  for(int x=0; x<w; ++x, ++s.x, ++d.x)
586  {
587  int x0 = x - radius < 0 ? -x : -radius;
588  int y0 = y - radius < 0 ? -y : -radius;
589  int x1 = x + radius >= w ? w - x - 1 : radius;
590  int y1 = y + radius >= h ? h - y - 1 : radius;
591 
592  VectorType v(src(s));
593  TensorType t(sq(v[0]), v[0]*v[1], sq(v[1]));
594  double sqMag = t[0] + t[2];
595  double mag = VIGRA_CSTD::sqrt(sqMag);
596  if(mag != 0.0)
597  v /= mag;
598  else
599  v *= 0.0;
600  Diff2D dd;
601  for(dd.y = y0; dd.y <= y1; ++dd.y)
602  {
603  for(dd.x = x0; dd.x <= x1; ++dd.x)
604  {
605  dest.set(dest(d, dd) + kernel(dd.x, dd.y, v) * t, d, dd);
606  }
607  }
608  }
609  }
610 }
611 
612 template <class SrcIterator, class SrcAccessor,
613  class DestIterator, class DestAccessor,
614  class Kernel>
615 inline void
616 orientedTrigonometricFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
617  pair<DestIterator, DestAccessor> dest,
618  Kernel const & kernel)
619 {
620  orientedTrigonometricFilter(src.first, src.second, src.third, dest.first, dest.second, kernel);
621 }
622 
623 template <class T1, class S1,
624  class T2, class S2,
625  class Kernel>
626 inline void
627 orientedTrigonometricFilter(MultiArrayView<2, T1, S1> const & src,
628  MultiArrayView<2, T2, S2> dest,
629  Kernel const & kernel)
630 {
631  vigra_precondition(src.shape() == dest.shape(),
632  "orientedTrigonometricFilter(): shape mismatch between input and output.");
633  orientedTrigonometricFilter(srcImageRange(src), destImage(dest), kernel);
634 }
635 
636 //@}
637 
638 } // namespace vigra
639 
640 #endif /* VIGRA_ORIENTEDTENSORFILTERS_HXX */
FixedPoint16< 2, OverflowHandling > atan2(FixedPoint16< IntBits, OverflowHandling > y, FixedPoint16< IntBits, OverflowHandling > x)
Arctangent. Accuracy better than 1/3 degree (9 significant bits).
Definition: fixedpoint.hxx:1654
PromoteTraits< V1, V2 >::Promote dot(RGBValue< V1, RIDX1, GIDX1, BIDX1 > const &r1, RGBValue< V2, RIDX2, GIDX2, BIDX2 > const &r2)
dot product
Definition: rgbvalue.hxx:906
void initImage(...)
Write a value to every pixel in an image or rectangular ROI.
linalg::TemporaryMatrix< T > sin(MultiArrayView< 2, T, C > const &v)
linalg::TemporaryMatrix< T > exp(MultiArrayView< 2, T, C > const &v)
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition: fftw3.hxx:1037
NumericTraits< T >::Promote sq(T t)
The square function.
Definition: mathutil.hxx:382
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
void hourGlassFilter(...)
Anisotropic tensor smoothing with the hourglass filter.
linalg::TemporaryMatrix< T > cos(MultiArrayView< 2, T, C > const &v)
BasicImage< double > DImage
Definition: stdimage.hxx:153
int floor(FixedPoint< IntBits, FracBits > v)
rounding down.
Definition: fixedpoint.hxx:667
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616
TinyVector< double, 2 > value_type
Definition: basicimage.hxx:481
BasicImage< TinyVector< double, 2 > > DVector2Image
Definition: stdimage.hxx:306

© 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)