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

symmetry.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 1998-2002 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_SYMMETRY_HXX
37 #define VIGRA_SYMMETRY_HXX
38 
39 #include "utilities.hxx"
40 #include "numerictraits.hxx"
41 #include "stdimage.hxx"
42 #include "convolution.hxx"
43 #include "multi_shape.hxx"
44 
45 namespace vigra {
46 
47 /** \addtogroup SymmetryDetection Symmetry Detection
48  Measure the local symmetry at each pixel.
49 */
50 //@{
51 
52 /********************************************************/
53 /* */
54 /* radialSymmetryTransform */
55 /* */
56 /********************************************************/
57 
58 /** \brief Find centers of radial symmetry in an image.
59 
60  This algorithm implements the Fast Radial Symmetry Transform according to
61  [G. Loy, A. Zelinsky: <em> "A Fast Radial Symmetry Transform for Detecting
62  Points of Interest"</em>, in: A. Heyden et al. (Eds.): Proc. of 7th European
63  Conf. on Computer Vision, Part 1, pp. 358-368, Springer LNCS 2350, 2002].
64  Minima of the algorithm response mark dark blobs, maxima correspond to light blobs.
65  The "radial strictness parameter" is fixed at <TT>alpha</tt> = 2.0, the
66  spatial spreading of the raw response is done by a Gaussian convolution
67  at <tt>0.25*scale</TT> (these values are recommendations from the paper).
68  Loy and Zelinsky additionally propose to add the operator response from several
69  scales (see usage example below).
70 
71  <b> Declarations:</b>
72 
73  pass 2D array views:
74  \code
75  namespace vigra {
76  template <class T1, class S1,
77  class T2, class S2>
78  void
79  radialSymmetryTransform(MultiArrayView<2, T1, S1> const & src,
80  MultiArrayView<2, T2, S2> dest,
81  double scale);
82  }
83  \endcode
84 
85  \deprecatedAPI{radialSymmetryTransform}
86  pass \ref ImageIterators and \ref DataAccessors :
87  \code
88  namespace vigra {
89  template <class SrcIterator, class SrcAccessor,
90  class DestIterator, class DestAccessor>
91  void
92  radialSymmetryTransform(SrcIterator sul, SrcIterator slr, SrcAccessor as,
93  DestIterator dul, DestAccessor ad,
94  double scale)
95  }
96  \endcode
97  use argument objects in conjunction with \ref ArgumentObjectFactories :
98  \code
99  namespace vigra {
100  template <class SrcIterator, class SrcAccessor,
101  class DestIterator, class DestAccessor>
102  inline
103  void radialSymmetryTransform(
104  triple<SrcIterator, SrcIterator, SrcAccessor> src,
105  pair<DestIterator, DestAccessor> dest,
106  double scale)
107  }
108  \endcode
109  \deprecatedEnd
110 
111  <b> Usage:</b>
112 
113  <b>\#include</b> <vigra/symmetry.hxx><br>
114  Namespace: vigra
115 
116  \code
117  MultiArray<2, unsigned char> src(w,h), centers(w,h);
118  MultiArray<2, float> symmetry(w,h);
119 
120  // use edge detection filters at various scales
121  for(double scale = 2.0; scale <= 8.0; scale *= 2.0)
122  {
123  MultiArray<2, float> tmp(w,h);
124 
125  // find centers of symmetry
126  radialSymmetryTransform(src, tmp, scale);
127 
128  symmetry += tmp;
129  }
130 
131  // mark centers of symmetry
132  centers.init(128);
133  localMinima(symmetry, centers, 0);
134  localMaxima(symmetry, centers, 255);
135  \endcode
136 
137  \deprecatedUsage{radialSymmetryTransform}
138  \code
139  vigra::BImage src(w,h), centers(w,h);
140  vigra::FImage symmetry(w,h);
141 
142  // empty result image
143  centers.init(128);
144  symmetry.init(0.0);
145 
146  // input width of edge detection filter
147  for(double scale = 2.0; scale <= 8.0; scale *= 2.0)
148  {
149  vigra::FImage tmp(w,h);
150 
151  // find centers of symmetry
152  radialSymmetryTransform(srcImageRange(src), destImage(tmp), scale);
153 
154  combineTwoImages(srcImageRange(symmetry), srcImage(tmp), destImage(symmetry),
155  std::plus<float>());
156  }
157 
158  localMinima(srcImageRange(symmetry), destImage(centers), 0);
159  localMaxima(srcImageRange(symmetry), destImage(centers), 255);
160  \endcode
161  <b> Required Interface:</b>
162  \code
163  SrcImageIterator src_upperleft, src_lowerright;
164  DestImageIterator dest_upperleft;
165 
166  SrcAccessor src_accessor;
167  DestAccessor dest_accessor;
168 
169  // SrcAccessor::value_type must be a built-in type
170  SrcAccessor::value_type u = src_accessor(src_upperleft);
171 
172  dest_accessor.set(u, dest_upperleft);
173  \endcode
174  \deprecatedEnd
175 */
177 
178 template <class SrcIterator, class SrcAccessor,
179  class DestIterator, class DestAccessor>
180 void
181 radialSymmetryTransform(SrcIterator sul, SrcIterator slr, SrcAccessor as,
182  DestIterator dul, DestAccessor ad,
183  double scale)
184 {
185  vigra_precondition(scale > 0.0,
186  "radialSymmetryTransform(): Scale must be > 0");
187 
188  int w = slr.x - sul.x;
189  int h = slr.y - sul.y;
190 
191  if(w <= 0 || h <= 0) return;
192 
193  typedef typename
194  NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
195 
196  typedef BasicImage<TmpType> TmpImage;
197  typedef typename TmpImage::Iterator TmpIterator;
198 
199  TmpImage gx(w,h);
200  TmpImage gy(w,h);
201  IImage orientationCounter(w,h);
202  TmpImage magnitudeAccumulator(w,h);
203 
204  gaussianGradient(srcIterRange(sul, slr, as),
205  destImage(gx), destImage(gy),
206  scale);
207 
208  orientationCounter.init(0);
209  magnitudeAccumulator.init(NumericTraits<TmpType>::zero());
210 
211  TmpIterator gxi = gx.upperLeft();
212  TmpIterator gyi = gy.upperLeft();
213  int y;
214  for(y=0; y<h; ++y, ++gxi.y, ++gyi.y)
215  {
216  typename TmpIterator::row_iterator gxr = gxi.rowIterator();
217  typename TmpIterator::row_iterator gyr = gyi.rowIterator();
218 
219  for(int x = 0; x<w; ++x, ++gxr, ++gyr)
220  {
221  double angle = VIGRA_CSTD::atan2(-*gyr, *gxr);
222  double magnitude = VIGRA_CSTD::sqrt(*gxr * *gxr + *gyr * *gyr);
223 
224  if(magnitude < NumericTraits<TmpType>::epsilon()*10.0)
225  continue;
226 
227  int dx = NumericTraits<int>::fromRealPromote(scale * VIGRA_CSTD::cos(angle));
228  int dy = NumericTraits<int>::fromRealPromote(scale * VIGRA_CSTD::sin(angle));
229 
230  int xx = x + dx;
231  int yy = y - dy;
232 
233  if(xx >= 0 && xx < w && yy >= 0 && yy < h)
234  {
235  orientationCounter(xx, yy) += 1;
236  magnitudeAccumulator(xx, yy) += detail::RequiresExplicitCast<TmpType>::cast(magnitude);
237  }
238 
239  xx = x - dx;
240  yy = y + dy;
241 
242  if(xx >= 0 && xx < w && yy >= 0 && yy < h)
243  {
244  orientationCounter(xx, yy) -= 1;
245  magnitudeAccumulator(xx, yy) -= detail::RequiresExplicitCast<TmpType>::cast(magnitude);
246  }
247  }
248  }
249 
250  int maxOrientation = 0;
251  TmpType maxMagnitude = NumericTraits<TmpType>::zero();
252 
253  for(y=0; y<h; ++y)
254  {
255  for(int x = 0; x<w; ++x)
256  {
257  int o = VIGRA_CSTD::abs(orientationCounter(x,y));
258 
259  if(o > maxOrientation)
260  maxOrientation = o;
261 
262  TmpType m = VIGRA_CSTD::abs(magnitudeAccumulator(x,y));
263 
264  if(m > maxMagnitude)
265  maxMagnitude = m;
266  }
267  }
268 
269  for(y=0; y<h; ++y)
270  {
271  for(int x = 0; x<w; ++x)
272  {
273  double o = (double)orientationCounter(x, y) / maxOrientation;
274  magnitudeAccumulator(x, y) = detail::RequiresExplicitCast<TmpType>::cast(o * o * magnitudeAccumulator(x, y) / maxMagnitude);
275  }
276  }
277 
278  gaussianSmoothing(srcImageRange(magnitudeAccumulator), destIter(dul, ad), 0.25*scale);
279 }
280 
281 template <class SrcIterator, class SrcAccessor,
282  class DestIterator, class DestAccessor>
283 inline void
284 radialSymmetryTransform(triple<SrcIterator, SrcIterator, SrcAccessor> src,
285  pair<DestIterator, DestAccessor> dest,
286  double scale)
287 {
288  radialSymmetryTransform(src.first, src.second, src.third,
289  dest.first, dest.second,
290  scale);
291 }
292 
293 template <class T1, class S1,
294  class T2, class S2>
295 inline void
296 radialSymmetryTransform(MultiArrayView<2, T1, S1> const & src,
297  MultiArrayView<2, T2, S2> dest,
298  double scale)
299 {
300  vigra_precondition(src.shape() == dest.shape(),
301  "radialSymmetryTransform(): shape mismatch between input and output.");
302  radialSymmetryTransform(srcImageRange(src),
303  destImage(dest),
304  scale);
305 }
306 
307 //@}
308 
309 } // namespace vigra
310 
311 
312 #endif /* VIGRA_SYMMETRY_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
linalg::TemporaryMatrix< T > sin(MultiArrayView< 2, T, C > const &v)
void radialSymmetryTransform(...)
Find centers of radial symmetry in an image.
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
void gaussianGradient(...)
Calculate the gradient vector by means of a 1st derivatives of Gaussian filter.
FFTWComplex< R >::NormType abs(const FFTWComplex< R > &a)
absolute value (= magnitude)
Definition: fftw3.hxx:1002
void gaussianSmoothing(...)
Perform isotropic Gaussian convolution.
linalg::TemporaryMatrix< T > cos(MultiArrayView< 2, T, C > const &v)
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616
BasicImage< Int32 > IImage
Definition: stdimage.hxx:116

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