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

vigra/symmetry.hxx VIGRA

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> <vigra/symmetry.hxx><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)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.8.0 (20 Sep 2011)