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