[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
00001 /************************************************************************/ 00002 /* */ 00003 /* Copyright 1998-2002 by Ullrich Koethe */ 00004 /* */ 00005 /* This file is part of the VIGRA computer vision library. */ 00006 /* The VIGRA Website is */ 00007 /* http://hci.iwr.uni-heidelberg.de/vigra/ */ 00008 /* Please direct questions, bug reports, and contributions to */ 00009 /* ullrich.koethe@iwr.uni-heidelberg.de or */ 00010 /* vigra@informatik.uni-hamburg.de */ 00011 /* */ 00012 /* Permission is hereby granted, free of charge, to any person */ 00013 /* obtaining a copy of this software and associated documentation */ 00014 /* files (the "Software"), to deal in the Software without */ 00015 /* restriction, including without limitation the rights to use, */ 00016 /* copy, modify, merge, publish, distribute, sublicense, and/or */ 00017 /* sell copies of the Software, and to permit persons to whom the */ 00018 /* Software is furnished to do so, subject to the following */ 00019 /* conditions: */ 00020 /* */ 00021 /* The above copyright notice and this permission notice shall be */ 00022 /* included in all copies or substantial portions of the */ 00023 /* Software. */ 00024 /* */ 00025 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ 00026 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ 00027 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 00028 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ 00029 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ 00030 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ 00031 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ 00032 /* OTHER DEALINGS IN THE SOFTWARE. */ 00033 /* */ 00034 /************************************************************************/ 00035 00036 #ifndef VIGRA_SYMMETRY_HXX 00037 #define VIGRA_SYMMETRY_HXX 00038 00039 #include "utilities.hxx" 00040 #include "numerictraits.hxx" 00041 #include "stdimage.hxx" 00042 #include "convolution.hxx" 00043 00044 namespace vigra { 00045 00046 /** \addtogroup SymmetryDetection Symmetry Detection 00047 Measure the local symmetry at each pixel. 00048 */ 00049 //@{ 00050 00051 /********************************************************/ 00052 /* */ 00053 /* radialSymmetryTransform */ 00054 /* */ 00055 /********************************************************/ 00056 00057 /** \brief Find centers of radial symmetry in an image. 00058 00059 This algorithm implements the Fast Radial Symmetry Transform according to 00060 [G. Loy, A. Zelinsky: <em> "A Fast Radial Symmetry Transform for Detecting 00061 Points of Interest"</em>, in: A. Heyden et al. (Eds.): Proc. of 7th European 00062 Conf. on Computer Vision, Part 1, pp. 358-368, Springer LNCS 2350, 2002]. 00063 Minima of the algorithm response mark dark blobs, maxima correspond to light blobs. 00064 The "radial strictness parameter" is fixed at <TT>alpha</tt> = 2.0, the 00065 spatial spreading of the raw response is done by a Gaussian convolution 00066 at <tt>0.25*scale</TT> (these values are recommendations from the paper). 00067 Loy and Zelinsky additionally propose to add the operator response from several 00068 scales (see usage example below). 00069 00070 <b> Declarations:</b> 00071 00072 pass arguments explicitly: 00073 \code 00074 namespace vigra { 00075 template <class SrcIterator, class SrcAccessor, 00076 class DestIterator, class DestAccessor> 00077 void 00078 radialSymmetryTransform(SrcIterator sul, SrcIterator slr, SrcAccessor as, 00079 DestIterator dul, DestAccessor ad, 00080 double scale) 00081 } 00082 \endcode 00083 00084 use argument objects in conjunction with \ref ArgumentObjectFactories : 00085 \code 00086 namespace vigra { 00087 template <class SrcIterator, class SrcAccessor, 00088 class DestIterator, class DestAccessor> 00089 inline 00090 void radialSymmetryTransform( 00091 triple<SrcIterator, SrcIterator, SrcAccessor> src, 00092 pair<DestIterator, DestAccessor> dest, 00093 double scale) 00094 } 00095 \endcode 00096 00097 <b> Usage:</b> 00098 00099 <b>\#include</b> <<a href="symmetry_8hxx-source.html">vigra/symmetry.hxx</a>><br> 00100 Namespace: vigra 00101 00102 \code 00103 vigra::BImage src(w,h), centers(w,h); 00104 vigra::FImage symmetry(w,h); 00105 00106 // empty result image 00107 centers.init(128); 00108 symmetry.init(0.0); 00109 00110 // input width of edge detection filter 00111 for(double scale = 2.0; scale <= 8.0; scale *= 2.0) 00112 { 00113 vigra::FImage tmp(w,h); 00114 00115 // find centers of symmetry 00116 radialSymmetryTransform(srcImageRange(src), destImage(tmp), scale); 00117 00118 combineTwoImages(srcImageRange(symmetry), srcImage(tmp), destImage(symmetry), 00119 std::plus<float>()); 00120 } 00121 00122 localMinima(srcImageRange(symmetry), destImage(centers), 0); 00123 localMaxima(srcImageRange(symmetry), destImage(centers), 255); 00124 \endcode 00125 00126 <b> Required Interface:</b> 00127 00128 \code 00129 SrcImageIterator src_upperleft, src_lowerright; 00130 DestImageIterator dest_upperleft; 00131 00132 SrcAccessor src_accessor; 00133 DestAccessor dest_accessor; 00134 00135 // SrcAccessor::value_type must be a built-in type 00136 SrcAccessor::value_type u = src_accessor(src_upperleft); 00137 00138 dest_accessor.set(u, dest_upperleft); 00139 \endcode 00140 */ 00141 doxygen_overloaded_function(template <...> void radialSymmetryTransform) 00142 00143 template <class SrcIterator, class SrcAccessor, 00144 class DestIterator, class DestAccessor> 00145 void 00146 radialSymmetryTransform(SrcIterator sul, SrcIterator slr, SrcAccessor as, 00147 DestIterator dul, DestAccessor ad, 00148 double scale) 00149 { 00150 vigra_precondition(scale > 0.0, 00151 "radialSymmetryTransform(): Scale must be > 0"); 00152 00153 int w = slr.x - sul.x; 00154 int h = slr.y - sul.y; 00155 00156 if(w <= 0 || h <= 0) return; 00157 00158 typedef typename 00159 NumericTraits<typename SrcAccessor::value_type>::RealPromote TmpType; 00160 00161 typedef BasicImage<TmpType> TmpImage; 00162 typedef typename TmpImage::Iterator TmpIterator; 00163 00164 TmpImage gx(w,h); 00165 TmpImage gy(w,h); 00166 IImage orientationCounter(w,h); 00167 TmpImage magnitudeAccumulator(w,h); 00168 00169 gaussianGradient(srcIterRange(sul, slr, as), 00170 destImage(gx), destImage(gy), 00171 scale); 00172 00173 orientationCounter.init(0); 00174 magnitudeAccumulator.init(NumericTraits<TmpType>::zero()); 00175 00176 TmpIterator gxi = gx.upperLeft(); 00177 TmpIterator gyi = gy.upperLeft(); 00178 int y; 00179 for(y=0; y<h; ++y, ++gxi.y, ++gyi.y) 00180 { 00181 typename TmpIterator::row_iterator gxr = gxi.rowIterator(); 00182 typename TmpIterator::row_iterator gyr = gyi.rowIterator(); 00183 00184 for(int x = 0; x<w; ++x, ++gxr, ++gyr) 00185 { 00186 double angle = VIGRA_CSTD::atan2(-*gyr, *gxr); 00187 double magnitude = VIGRA_CSTD::sqrt(*gxr * *gxr + *gyr * *gyr); 00188 00189 if(magnitude < NumericTraits<TmpType>::epsilon()*10.0) 00190 continue; 00191 00192 int dx = NumericTraits<int>::fromRealPromote(scale * VIGRA_CSTD::cos(angle)); 00193 int dy = NumericTraits<int>::fromRealPromote(scale * VIGRA_CSTD::sin(angle)); 00194 00195 int xx = x + dx; 00196 int yy = y - dy; 00197 00198 if(xx >= 0 && xx < w && yy >= 0 && yy < h) 00199 { 00200 orientationCounter(xx, yy) += 1; 00201 magnitudeAccumulator(xx, yy) += detail::RequiresExplicitCast<TmpType>::cast(magnitude); 00202 } 00203 00204 xx = x - dx; 00205 yy = y + dy; 00206 00207 if(xx >= 0 && xx < w && yy >= 0 && yy < h) 00208 { 00209 orientationCounter(xx, yy) -= 1; 00210 magnitudeAccumulator(xx, yy) -= detail::RequiresExplicitCast<TmpType>::cast(magnitude); 00211 } 00212 } 00213 } 00214 00215 int maxOrientation = 0; 00216 TmpType maxMagnitude = NumericTraits<TmpType>::zero(); 00217 00218 for(y=0; y<h; ++y) 00219 { 00220 for(int x = 0; x<w; ++x) 00221 { 00222 int o = VIGRA_CSTD::abs(orientationCounter(x,y)); 00223 00224 if(o > maxOrientation) 00225 maxOrientation = o; 00226 00227 TmpType m = VIGRA_CSTD::abs(magnitudeAccumulator(x,y)); 00228 00229 if(m > maxMagnitude) 00230 maxMagnitude = m; 00231 } 00232 } 00233 00234 for(y=0; y<h; ++y) 00235 { 00236 for(int x = 0; x<w; ++x) 00237 { 00238 double o = (double)orientationCounter(x, y) / maxOrientation; 00239 magnitudeAccumulator(x, y) = detail::RequiresExplicitCast<TmpType>::cast(o * o * magnitudeAccumulator(x, y) / maxMagnitude); 00240 } 00241 } 00242 00243 gaussianSmoothing(srcImageRange(magnitudeAccumulator), destIter(dul, ad), 0.25*scale); 00244 } 00245 00246 template <class SrcIterator, class SrcAccessor, 00247 class DestIterator, class DestAccessor> 00248 inline 00249 void radialSymmetryTransform( 00250 triple<SrcIterator, SrcIterator, SrcAccessor> src, 00251 pair<DestIterator, DestAccessor> dest, 00252 double scale) 00253 { 00254 radialSymmetryTransform(src.first, src.second, src.third, 00255 dest.first, dest.second, 00256 scale); 00257 } 00258 00259 00260 //@} 00261 00262 } // namespace vigra 00263 00264 00265 #endif /* VIGRA_SYMMETRY_HXX */
© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) |
html generated using doxygen and Python
|