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

# vigra/tensorutilities.hxx

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