[ 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)