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

details vigra/tensorutilities.hxx VIGRA

00001 /************************************************************************/
00002 /*                                                                      */
00003 /*               Copyright 2002-2004 by Ullrich Koethe                  */
00004 /*       Cognitive Systems Group, University of Hamburg, Germany        */
00005 /*                                                                      */
00006 /*    This file is part of the VIGRA computer vision library.           */
00007 /*    ( Version 1.3.2, Jan 27 2005 )                                    */
00008 /*    You may use, modify, and distribute this software according       */
00009 /*    to the terms stated in the LICENSE file included in               */
00010 /*    the VIGRA distribution.                                           */
00011 /*                                                                      */
00012 /*    The VIGRA Website is                                              */
00013 /*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
00014 /*    Please direct questions, bug reports, and contributions to        */
00015 /*        koethe@informatik.uni-hamburg.de                              */
00016 /*                                                                      */
00017 /*  THIS SOFTWARE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR          */
00018 /*  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED      */
00019 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
00020 /*                                                                      */
00021 /************************************************************************/
00022 
00023 #ifndef VIGRA_TENSORUTILITIES_HXX
00024 #define VIGRA_TENSORUTILITIES_HXX
00025 
00026 #include <cmath>
00027 #include "vigra/utilities.hxx"
00028 
00029 namespace vigra {
00030 
00031 /** \addtogroup TensorImaging Tensor Image Processing
00032 */
00033 //@{
00034 
00035 /********************************************************/
00036 /*                                                      */
00037 /*                      vectorToTensor                  */
00038 /*                                                      */
00039 /********************************************************/
00040 
00041 /** \brief Calculate the tensor (outer) product of a 2D vector with itself.
00042 
00043     This function is useful to transform vector images into a tensor representation 
00044     that can be used as input to tensor based processing and analysis functions
00045     (e.g. tensor smoothing). The imput pixel type must be vectors of length 2, whereas
00046     the output must contain vectors of length 3 which will represent the tensor components
00047     in the order t11, t12 (== t21 due to symmetry), t22.
00048     
00049     <b>Note:</b> By default, this function negates the second component of the vector
00050     in order to turn a left handed vector (the usual resul of convolution, 
00051     e.g. a gradient filter, because <tt>y</tt> runs from top to bottom)
00052     into a right handed tensor (as is required by all tensor function in VIGRA). This
00053     behavior can be switched off by setting <tt>negateComponent2 = false</tt>.
00054     
00055     <b> Declarations:</b>
00056 
00057     pass arguments explicitly:
00058     \code
00059     namespace vigra {
00060         template <class SrcIterator, class SrcAccessor,
00061                 class DestIterator, class DestAccessor>
00062         void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00063                             DestIterator dul, DestAccessor dest,
00064                             bool negateComponent2 = true);
00065     }
00066     \endcode
00067 
00068 
00069     use argument objects in conjunction with \ref ArgumentObjectFactories:
00070     \code
00071     namespace vigra {
00072         template <class SrcIterator, class SrcAccessor,
00073                 class DestIterator, class DestAccessor>
00074         void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00075                             pair<DestIterator, DestAccessor> d,
00076                             bool negateComponent2 = true);
00077     }
00078     \endcode
00079 
00080     <b> Usage:</b>
00081 
00082     <b>\#include</b> "<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>"
00083 
00084     \code
00085     FImage img(w,h);
00086     FVector2Image gradient(w,h);
00087     FVector3Image tensor(w,h);
00088     
00089     gaussianGradient(srcImageRange(img), destImage(gradient), 2.0);
00090     vectorToTensor(srcImageRange(gradient), destImage(tensor));
00091     \endcode
00092 
00093 */
00094 template <class SrcIterator, class SrcAccessor,
00095           class DestIterator, class DestAccessor>
00096 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00097                     DestIterator dul, DestAccessor dest,
00098                     bool negateComponent2)
00099 {
00100     vigra_precondition(src.size(sul) == 2,
00101                        "vectorToTensor(): input image must have 2 bands.");
00102     vigra_precondition(dest.size(dul) == 3,
00103                        "vectorToTensor(): output image must have 3 bands.");
00104 
00105     int w = slr.x - sul.x;
00106     int h = slr.y - sul.y;
00107 
00108     for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
00109     {
00110         typename SrcIterator::row_iterator s = sul.rowIterator();
00111         typename SrcIterator::row_iterator send = s + w;
00112         typename DestIterator::row_iterator d = dul.rowIterator();
00113         if(negateComponent2)
00114         {
00115             for(; s < send; ++s, ++d)
00116             {
00117                 dest.setComponent(sq(src.getComponent(s, 0)), d, 0);
00118                 dest.setComponent(-src.getComponent(s, 0)*src.getComponent(s, 1), d, 1);
00119                                // ^ negative sign to turn left-handed into right-handed coordinates
00120                 dest.setComponent(sq(src.getComponent(s, 1)), d, 2);
00121             }
00122         }
00123         else
00124         {
00125             for(; s < send; ++s, ++d)
00126             {
00127                 dest.setComponent(sq(src.getComponent(s, 0)), d, 0);
00128                 dest.setComponent(src.getComponent(s, 0)*src.getComponent(s, 1), d, 1);
00129                 dest.setComponent(sq(src.getComponent(s, 1)), d, 2);
00130             }
00131         }
00132     }
00133 }
00134 
00135 template <class SrcIterator, class SrcAccessor,
00136           class DestIterator, class DestAccessor>
00137 inline
00138 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00139                     DestIterator dul, DestAccessor dest)
00140 {
00141     vectorToTensor(sul, slr, src, dul, dest, true);
00142 }
00143 
00144 template <class SrcIterator, class SrcAccessor,
00145           class DestIterator, class DestAccessor>
00146 inline
00147 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00148                      pair<DestIterator, DestAccessor> d,
00149                      bool negateComponent2)
00150 {
00151     vectorToTensor(s.first, s.second, s.third, d.first, d.second, negateComponent2);
00152 }
00153 
00154 template <class SrcIterator, class SrcAccessor,
00155           class DestIterator, class DestAccessor>
00156 inline
00157 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00158                     pair<DestIterator, DestAccessor> d)
00159 {
00160     vectorToTensor(s.first, s.second, s.third, d.first, d.second, true);
00161 }
00162 
00163 /********************************************************/
00164 /*                                                      */
00165 /*               tensorEigenRepresentation              */
00166 /*                                                      */
00167 /********************************************************/
00168 
00169 /** \brief Calculate eigen representation of a symmetric 2x2 tensor.
00170 
00171     This function turns a 3-band image representing the tensor components
00172     t11, t12 (== t21 due to symmetry), t22 into the a 3-band image holding the eigen
00173     representation e1, e2, and angle, where e1 &gt; e2. The original tensor must be
00174     defined in a right-handed coordinate system, and the angle of the tensor will
00175     then be given in mathematical positive (counter-clockwise) orientation, starting
00176     at the x-axis.
00177     
00178     <b> Declarations:</b>
00179 
00180     pass arguments explicitly:
00181     \code
00182     namespace vigra {
00183         template <class SrcIterator, class SrcAccessor,
00184                 class DestIterator, class DestAccessor>
00185         void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00186                                        DestIterator dul, DestAccessor dest);
00187     }
00188     \endcode
00189 
00190 
00191     use argument objects in conjunction with \ref ArgumentObjectFactories:
00192     \code
00193     namespace vigra {
00194         template <class SrcIterator, class SrcAccessor,
00195                 class DestIterator, class DestAccessor>
00196         void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00197                                        pair<DestIterator, DestAccessor> d);
00198     }
00199     \endcode
00200 
00201     <b> Usage:</b>
00202 
00203     <b>\#include</b> "<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>"
00204 
00205     \code
00206     FVector3Image tensor(w,h);
00207     FVector3Image eigen(w,h);
00208     
00209     tensorEigenRepresentation(srcImageRange(tensor), destImage(eigen));
00210     \endcode
00211 
00212 */
00213 template <class SrcIterator, class SrcAccessor,
00214           class DestIterator, class DestAccessor>
00215 void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00216                                DestIterator dul, DestAccessor dest)
00217 {
00218     vigra_precondition(src.size(sul) == 3,
00219                        "tensorEigenRepresentation(): input image must have 3 bands.");
00220     vigra_precondition(dest.size(dul) == 3,
00221                        "tensorEigenRepresentation(): output image must have 3 bands.");
00222 
00223     int w = slr.x - sul.x;
00224     int h = slr.y - sul.y;
00225 
00226     for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
00227     {
00228         typename SrcIterator::row_iterator s = sul.rowIterator();
00229         typename SrcIterator::row_iterator send = s + w;
00230         typename DestIterator::row_iterator d = dul.rowIterator();
00231         for(; s < send; ++s, ++d)
00232         {
00233             typedef typename 
00234                NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType;
00235             TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2);
00236             TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2);
00237             TmpType d3 = 2.0 * src.getComponent(s,1);
00238             TmpType d4 = VIGRA_CSTD::sqrt(sq(d2) + sq(d3));
00239             
00240             dest.setComponent(0.5 * (d1 + d4), d, 0); // large EV
00241             dest.setComponent(0.5 * (d1 - d4), d, 1); // small EV
00242             dest.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), d, 2); // orientation
00243         }
00244     }
00245 }
00246 
00247 template <class SrcIterator, class SrcAccessor,
00248           class DestIterator, class DestAccessor>
00249 inline
00250 void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00251                                pair<DestIterator, DestAccessor> d)
00252 {
00253     tensorEigenRepresentation(s.first, s.second, s.third, d.first, d.second);
00254 }
00255 
00256 /********************************************************/
00257 /*                                                      */
00258 /*                      tensorTrace                     */
00259 /*                                                      */
00260 /********************************************************/
00261 
00262 /** \brief Calculate the trace of a 2x2 tensor.
00263 
00264     This function turns a 3-band image representing the tensor components
00265     t11, t12 (== t21 due to symmetry), t22 into the a 1-band image holding the 
00266     tensor trace t11 + t22.
00267     
00268     <b> Declarations:</b>
00269 
00270     pass arguments explicitly:
00271     \code
00272     namespace vigra {
00273         template <class SrcIterator, class SrcAccessor,
00274                 class DestIterator, class DestAccessor>
00275         void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00276                          DestIterator dul, DestAccessor dest);
00277     }
00278     \endcode
00279 
00280 
00281     use argument objects in conjunction with \ref ArgumentObjectFactories:
00282     \code
00283     namespace vigra {
00284         template <class SrcIterator, class SrcAccessor,
00285                 class DestIterator, class DestAccessor>
00286         void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00287                          pair<DestIterator, DestAccessor> d);
00288     }
00289     \endcode
00290 
00291     <b> Usage:</b>
00292 
00293     <b>\#include</b> "<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>"
00294 
00295     \code
00296     FVector3Image tensor(w,h);
00297     FImage trace(w,h);
00298     
00299     tensorTrace(srcImageRange(tensor), destImage(trace));
00300     \endcode
00301 
00302 */
00303 template <class SrcIterator, class SrcAccessor,
00304           class DestIterator, class DestAccessor>
00305 void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00306                  DestIterator dul, DestAccessor dest)
00307 {
00308     vigra_precondition(src.size(sul) == 3,
00309                        "tensorTrace(): input image must have 3 bands.");
00310 
00311     int w = slr.x - sul.x;
00312     int h = slr.y - sul.y;
00313 
00314     for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
00315     {
00316         typename SrcIterator::row_iterator s = sul.rowIterator();
00317         typename SrcIterator::row_iterator send = s + w;
00318         typename DestIterator::row_iterator d = dul.rowIterator();
00319         for(; s < send; ++s, ++d)
00320         {
00321             dest.set(src.getComponent(s,0) + src.getComponent(s,2), d);
00322         }
00323     }
00324 }
00325 
00326 template <class SrcIterator, class SrcAccessor,
00327           class DestIterator, class DestAccessor>
00328 inline
00329 void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00330                  pair<DestIterator, DestAccessor> d)
00331 {
00332     tensorTrace(s.first, s.second, s.third, d.first, d.second);
00333 }
00334 
00335 /********************************************************/
00336 /*                                                      */
00337 /*                  tensorToEdgeCorner                  */
00338 /*                                                      */
00339 /********************************************************/
00340 
00341 /** \brief Decompose a symmetric 2x2 tensor into its edge and corner parts.
00342 
00343     This function turns a 3-band image representing the tensor components
00344     t11, t12 (== t21 due to symmetry), t22 into the a 2-band image holding 
00345     the tensor's edgeness (difference of the tensor's 
00346     eigenvalues) and orientation, and a 1-band image representing its corner part 
00347     (equal to the twice the small eigen value). The original tensor must be 
00348     positive definite and defined in a right-handed coordinate system (e.g.
00349     the tensor resulting from \ref boundaryTensor()).
00350     
00351     <b> Declarations:</b>
00352 
00353     pass arguments explicitly:
00354     \code
00355     namespace vigra {
00356         template <class SrcIterator, class SrcAccessor,
00357                   class DestIterator1, class DestAccessor1,
00358                   class DestIterator2, class DestAccessor2>
00359         void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00360                                 DestIterator1 edgeul, DestAccessor1 edge,
00361                                 DestIterator2 cornerul, DestAccessor2 corner);
00362     }
00363     \endcode
00364 
00365 
00366     use argument objects in conjunction with \ref ArgumentObjectFactories:
00367     \code
00368     namespace vigra {
00369         template <class SrcIterator, class SrcAccessor,
00370                   class DestIterator1, class DestAccessor1,
00371                   class DestIterator2, class DestAccessor2>
00372         void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00373                                 pair<DestIterator1, DestAccessor1> edge,
00374                                 pair<DestIterator2, DestAccessor2> corner);
00375     }
00376     \endcode
00377 
00378     <b> Usage:</b>
00379 
00380     <b>\#include</b> "<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>"
00381 
00382     \code
00383     FVector3Image tensor(w,h);
00384     FVector2Image edgePart(w,h);
00385     FImage cornerPart(w,h);
00386     
00387     tensorTrace(srcImageRange(tensor), destImage(edgePart), destImage(cornerPart));
00388     \endcode
00389 
00390 */
00391 template <class SrcIterator, class SrcAccessor,
00392           class DestIterator1, class DestAccessor1,
00393           class DestIterator2, class DestAccessor2>
00394 void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00395                         DestIterator1 edgeul, DestAccessor1 edge,
00396                         DestIterator2 cornerul, DestAccessor2 corner)
00397 {
00398     vigra_precondition(src.size(sul) == 3,
00399                        "tensorToEdgeCorner(): input image must have 3 bands.");
00400     vigra_precondition(edge.size(edgeul) == 2,
00401                        "tensorToEdgeCorner(): edge image must have 2 bands.");
00402 
00403     int w = slr.x - sul.x;
00404     int h = slr.y - sul.y;
00405 
00406     for(int y=0; y<h; ++y, ++sul.y, ++edgeul.y, ++cornerul.y)
00407     {
00408         typename SrcIterator::row_iterator s = sul.rowIterator();
00409         typename SrcIterator::row_iterator send = s + w;
00410         typename DestIterator1::row_iterator e = edgeul.rowIterator();
00411         typename DestIterator2::row_iterator c = cornerul.rowIterator();
00412         for(; s < send; ++s, ++e, ++c)
00413         {
00414             typedef typename 
00415                NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType;
00416             TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2);
00417             TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2);
00418             TmpType d3 = 2.0 * src.getComponent(s,1);
00419             TmpType d4 = VIGRA_CSTD::sqrt(sq(d2) + sq(d3));
00420             
00421             edge.setComponent(d4, e, 0); // edgeness = difference of EVs
00422             edge.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), e, 1); // orientation
00423             corner.set(d1 - d4, c); // cornerness = 2 * small EV
00424         }
00425     }
00426 }
00427 
00428 template <class SrcIterator, class SrcAccessor,
00429           class DestIterator1, class DestAccessor1,
00430           class DestIterator2, class DestAccessor2>
00431 inline
00432 void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00433                         pair<DestIterator1, DestAccessor1> edge,
00434                         pair<DestIterator2, DestAccessor2> corner)
00435 {
00436     tensorToEdgeCorner(s.first, s.second, s.third, 
00437                        edge.first, edge.second, corner.first, corner.second);
00438 }
00439 
00440 //@}
00441 
00442 } // namespace vigra
00443 
00444 #endif /* VIGRA_TENSORUTILITIES_HXX */

© Ullrich Köthe (koethe@informatik.uni-hamburg.de)
Cognitive Systems Group, University of Hamburg, Germany

html generated using doxygen and Python
VIGRA 1.3.2 (27 Jan 2005)