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

symmetry.hxx
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 
44 namespace vigra {
45 
46 /** \addtogroup SymmetryDetection Symmetry Detection
47  Measure the local symmetry at each pixel.
48 */
49 //@{
50 
51 /********************************************************/
52 /* */
53 /* radialSymmetryTransform */
54 /* */
55 /********************************************************/
56 
57 /** \brief Find centers of radial symmetry in an image.
58 
59  This algorithm implements the Fast Radial Symmetry Transform according to
60  [G. Loy, A. Zelinsky: <em> "A Fast Radial Symmetry Transform for Detecting
61  Points of Interest"</em>, in: A. Heyden et al. (Eds.): Proc. of 7th European
62  Conf. on Computer Vision, Part 1, pp. 358-368, Springer LNCS 2350, 2002].
63  Minima of the algorithm response mark dark blobs, maxima correspond to light blobs.
64  The "radial strictness parameter" is fixed at <TT>alpha</tt> = 2.0, the
65  spatial spreading of the raw response is done by a Gaussian convolution
66  at <tt>0.25*scale</TT> (these values are recommendations from the paper).
67  Loy and Zelinsky additionally propose to add the operator response from several
68  scales (see usage example below).
69 
70  <b> Declarations:</b>
71 
72  pass arguments explicitly:
73  \code
74  namespace vigra {
75  template <class SrcIterator, class SrcAccessor,
76  class DestIterator, class DestAccessor>
77  void
78  radialSymmetryTransform(SrcIterator sul, SrcIterator slr, SrcAccessor as,
79  DestIterator dul, DestAccessor ad,
80  double scale)
81  }
82  \endcode
83 
84  use argument objects in conjunction with \ref ArgumentObjectFactories :
85  \code
86  namespace vigra {
87  template <class SrcIterator, class SrcAccessor,
88  class DestIterator, class DestAccessor>
89  inline
90  void radialSymmetryTransform(
91  triple<SrcIterator, SrcIterator, SrcAccessor> src,
92  pair<DestIterator, DestAccessor> dest,
93  double scale)
94  }
95  \endcode
96 
97  <b> Usage:</b>
98 
99  <b>\#include</b> <<a href="symmetry_8hxx-source.html">vigra/symmetry.hxx</a>><br>
100  Namespace: vigra
101 
102  \code
103  vigra::BImage src(w,h), centers(w,h);
104  vigra::FImage symmetry(w,h);
105 
106  // empty result image
107  centers.init(128);
108  symmetry.init(0.0);
109 
110  // input width of edge detection filter
111  for(double scale = 2.0; scale <= 8.0; scale *= 2.0)
112  {
113  vigra::FImage tmp(w,h);
114 
115  // find centers of symmetry
116  radialSymmetryTransform(srcImageRange(src), destImage(tmp), scale);
117 
118  combineTwoImages(srcImageRange(symmetry), srcImage(tmp), destImage(symmetry),
119  std::plus<float>());
120  }
121 
122  localMinima(srcImageRange(symmetry), destImage(centers), 0);
123  localMaxima(srcImageRange(symmetry), destImage(centers), 255);
124  \endcode
125 
126  <b> Required Interface:</b>
127 
128  \code
129  SrcImageIterator src_upperleft, src_lowerright;
130  DestImageIterator dest_upperleft;
131 
132  SrcAccessor src_accessor;
133  DestAccessor dest_accessor;
134 
135  // SrcAccessor::value_type must be a built-in type
136  SrcAccessor::value_type u = src_accessor(src_upperleft);
137 
138  dest_accessor.set(u, dest_upperleft);
139  \endcode
140 */
142 
143 template <class SrcIterator, class SrcAccessor,
144  class DestIterator, class DestAccessor>
145 void
146 radialSymmetryTransform(SrcIterator sul, SrcIterator slr, SrcAccessor as,
147  DestIterator dul, DestAccessor ad,
148  double scale)
149 {
150  vigra_precondition(scale > 0.0,
151  "radialSymmetryTransform(): Scale must be > 0");
152 
153  int w = slr.x - sul.x;
154  int h = slr.y - sul.y;
155 
156  if(w <= 0 || h <= 0) return;
157 
158  typedef typename
159  NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType;
160 
161  typedef BasicImage<TmpType> TmpImage;
162  typedef typename TmpImage::Iterator TmpIterator;
163 
164  TmpImage gx(w,h);
165  TmpImage gy(w,h);
166  IImage orientationCounter(w,h);
167  TmpImage magnitudeAccumulator(w,h);
168 
169  gaussianGradient(srcIterRange(sul, slr, as),
170  destImage(gx), destImage(gy),
171  scale);
172 
173  orientationCounter.init(0);
174  magnitudeAccumulator.init(NumericTraits<TmpType>::zero());
175 
176  TmpIterator gxi = gx.upperLeft();
177  TmpIterator gyi = gy.upperLeft();
178  int y;
179  for(y=0; y<h; ++y, ++gxi.y, ++gyi.y)
180  {
181  typename TmpIterator::row_iterator gxr = gxi.rowIterator();
182  typename TmpIterator::row_iterator gyr = gyi.rowIterator();
183 
184  for(int x = 0; x<w; ++x, ++gxr, ++gyr)
185  {
186  double angle = VIGRA_CSTD::atan2(-*gyr, *gxr);
187  double magnitude = VIGRA_CSTD::sqrt(*gxr * *gxr + *gyr * *gyr);
188 
189  if(magnitude < NumericTraits<TmpType>::epsilon()*10.0)
190  continue;
191 
192  int dx = NumericTraits<int>::fromRealPromote(scale * VIGRA_CSTD::cos(angle));
193  int dy = NumericTraits<int>::fromRealPromote(scale * VIGRA_CSTD::sin(angle));
194 
195  int xx = x + dx;
196  int yy = y - dy;
197 
198  if(xx >= 0 && xx < w && yy >= 0 && yy < h)
199  {
200  orientationCounter(xx, yy) += 1;
201  magnitudeAccumulator(xx, yy) += detail::RequiresExplicitCast<TmpType>::cast(magnitude);
202  }
203 
204  xx = x - dx;
205  yy = y + dy;
206 
207  if(xx >= 0 && xx < w && yy >= 0 && yy < h)
208  {
209  orientationCounter(xx, yy) -= 1;
210  magnitudeAccumulator(xx, yy) -= detail::RequiresExplicitCast<TmpType>::cast(magnitude);
211  }
212  }
213  }
214 
215  int maxOrientation = 0;
216  TmpType maxMagnitude = NumericTraits<TmpType>::zero();
217 
218  for(y=0; y<h; ++y)
219  {
220  for(int x = 0; x<w; ++x)
221  {
222  int o = VIGRA_CSTD::abs(orientationCounter(x,y));
223 
224  if(o > maxOrientation)
225  maxOrientation = o;
226 
227  TmpType m = VIGRA_CSTD::abs(magnitudeAccumulator(x,y));
228 
229  if(m > maxMagnitude)
230  maxMagnitude = m;
231  }
232  }
233 
234  for(y=0; y<h; ++y)
235  {
236  for(int x = 0; x<w; ++x)
237  {
238  double o = (double)orientationCounter(x, y) / maxOrientation;
239  magnitudeAccumulator(x, y) = detail::RequiresExplicitCast<TmpType>::cast(o * o * magnitudeAccumulator(x, y) / maxMagnitude);
240  }
241  }
242 
243  gaussianSmoothing(srcImageRange(magnitudeAccumulator), destIter(dul, ad), 0.25*scale);
244 }
245 
246 template <class SrcIterator, class SrcAccessor,
247  class DestIterator, class DestAccessor>
248 inline
250  triple<SrcIterator, SrcIterator, SrcAccessor> src,
251  pair<DestIterator, DestAccessor> dest,
252  double scale)
253 {
254  radialSymmetryTransform(src.first, src.second, src.third,
255  dest.first, dest.second,
256  scale);
257 }
258 
259 
260 //@}
261 
262 } // namespace vigra
263 
264 
265 #endif /* VIGRA_SYMMETRY_HXX */

© 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.7.1 (Wed Mar 12 2014)