vigra - vigra/symmetry.hxx Source File

[ 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 #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 */
176 doxygen_overloaded_function(template <...> void radialSymmetryTransform)
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 */

© 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.10.0 (Mon Nov 18 2013)