[ 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.5.0, Dec 07 2006 )                                    */
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 /*        koethe@informatik.uni-hamburg.de          or                  */
00012 /*        vigra@kogs1.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 template <class SrcIterator, class SrcAccessor,
00110           class DestIterator, class DestAccessor>
00111 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00112                     DestIterator dul, DestAccessor dest,
00113                     bool negateComponent2)
00114 {
00115     vigra_precondition(src.size(sul) == 2,
00116                        "vectorToTensor(): input image must have 2 bands.");
00117     vigra_precondition(dest.size(dul) == 3,
00118                        "vectorToTensor(): output image must have 3 bands.");
00119 
00120     int w = slr.x - sul.x;
00121     int h = slr.y - sul.y;
00122 
00123     for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
00124     {
00125         typename SrcIterator::row_iterator s = sul.rowIterator();
00126         typename SrcIterator::row_iterator send = s + w;
00127         typename DestIterator::row_iterator d = dul.rowIterator();
00128         if(negateComponent2)
00129         {
00130             for(; s < send; ++s, ++d)
00131             {
00132                 dest.setComponent(sq(src.getComponent(s, 0)), d, 0);
00133                 dest.setComponent(-src.getComponent(s, 0)*src.getComponent(s, 1), d, 1);
00134                                // ^ negative sign to turn left-handed into right-handed coordinates
00135                 dest.setComponent(sq(src.getComponent(s, 1)), d, 2);
00136             }
00137         }
00138         else
00139         {
00140             for(; s < send; ++s, ++d)
00141             {
00142                 dest.setComponent(sq(src.getComponent(s, 0)), d, 0);
00143                 dest.setComponent(src.getComponent(s, 0)*src.getComponent(s, 1), d, 1);
00144                 dest.setComponent(sq(src.getComponent(s, 1)), d, 2);
00145             }
00146         }
00147     }
00148 }
00149 
00150 template <class SrcIterator, class SrcAccessor,
00151           class DestIterator, class DestAccessor>
00152 inline
00153 void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00154                     DestIterator dul, DestAccessor dest)
00155 {
00156     vectorToTensor(sul, slr, src, dul, dest, true);
00157 }
00158 
00159 template <class SrcIterator, class SrcAccessor,
00160           class DestIterator, class DestAccessor>
00161 inline
00162 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00163                      pair<DestIterator, DestAccessor> d,
00164                      bool negateComponent2)
00165 {
00166     vectorToTensor(s.first, s.second, s.third, d.first, d.second, negateComponent2);
00167 }
00168 
00169 template <class SrcIterator, class SrcAccessor,
00170           class DestIterator, class DestAccessor>
00171 inline
00172 void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00173                     pair<DestIterator, DestAccessor> d)
00174 {
00175     vectorToTensor(s.first, s.second, s.third, d.first, d.second, true);
00176 }
00177 
00178 /********************************************************/
00179 /*                                                      */
00180 /*               tensorEigenRepresentation              */
00181 /*                                                      */
00182 /********************************************************/
00183 
00184 /** \brief Calculate eigen representation of a symmetric 2x2 tensor.
00185 
00186     This function turns a 3-band image representing the tensor components
00187     t11, t12 (== t21 due to symmetry), t22 into the a 3-band image holding the eigen
00188     representation e1, e2, and angle, where e1 &gt; e2. The original tensor must be
00189     defined in a right-handed coordinate system, and the angle of the tensor will
00190     then be given in mathematical positive (counter-clockwise) orientation, starting
00191     at the x-axis.
00192     
00193     <b> Declarations:</b>
00194 
00195     pass arguments explicitly:
00196     \code
00197     namespace vigra {
00198         template <class SrcIterator, class SrcAccessor,
00199                 class DestIterator, class DestAccessor>
00200         void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00201                                        DestIterator dul, DestAccessor dest);
00202     }
00203     \endcode
00204 
00205 
00206     use argument objects in conjunction with \ref ArgumentObjectFactories:
00207     \code
00208     namespace vigra {
00209         template <class SrcIterator, class SrcAccessor,
00210                 class DestIterator, class DestAccessor>
00211         void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00212                                        pair<DestIterator, DestAccessor> d);
00213     }
00214     \endcode
00215 
00216     <b> Usage:</b>
00217 
00218     <b>\#include</b> "<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>"
00219 
00220     \code
00221     FVector3Image tensor(w,h);
00222     FVector3Image eigen(w,h);
00223     
00224     tensorEigenRepresentation(srcImageRange(tensor), destImage(eigen));
00225     \endcode
00226 
00227 */
00228 template <class SrcIterator, class SrcAccessor,
00229           class DestIterator, class DestAccessor>
00230 void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00231                                DestIterator dul, DestAccessor dest)
00232 {
00233     vigra_precondition(src.size(sul) == 3,
00234                        "tensorEigenRepresentation(): input image must have 3 bands.");
00235     vigra_precondition(dest.size(dul) == 3,
00236                        "tensorEigenRepresentation(): output image must have 3 bands.");
00237 
00238     int w = slr.x - sul.x;
00239     int h = slr.y - sul.y;
00240 
00241     for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
00242     {
00243         typename SrcIterator::row_iterator s = sul.rowIterator();
00244         typename SrcIterator::row_iterator send = s + w;
00245         typename DestIterator::row_iterator d = dul.rowIterator();
00246         for(; s < send; ++s, ++d)
00247         {
00248             typedef typename 
00249                NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType;
00250             TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2);
00251             TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2);
00252             TmpType d3 = 2.0 * src.getComponent(s,1);
00253             TmpType d4 = VIGRA_CSTD::sqrt(sq(d2) + sq(d3));
00254             
00255             dest.setComponent(0.5 * (d1 + d4), d, 0); // large EV
00256             dest.setComponent(0.5 * (d1 - d4), d, 1); // small EV
00257             if(d2==0.0 && d3==0.0)
00258             {
00259                 dest.setComponent(0, d, 2); // orientation
00260             }
00261             else
00262             {
00263                 dest.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), d, 2); // orientation
00264             }
00265         }
00266     }
00267 }
00268 
00269 template <class SrcIterator, class SrcAccessor,
00270           class DestIterator, class DestAccessor>
00271 inline
00272 void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00273                                pair<DestIterator, DestAccessor> d)
00274 {
00275     tensorEigenRepresentation(s.first, s.second, s.third, d.first, d.second);
00276 }
00277 
00278 /********************************************************/
00279 /*                                                      */
00280 /*                      tensorTrace                     */
00281 /*                                                      */
00282 /********************************************************/
00283 
00284 /** \brief Calculate the trace of a 2x2 tensor.
00285 
00286     This function turns a 3-band image representing the tensor components
00287     t11, t12 (== t21 due to symmetry), t22 into the a 1-band image holding the 
00288     tensor trace t11 + t22.
00289     
00290     <b> Declarations:</b>
00291 
00292     pass arguments explicitly:
00293     \code
00294     namespace vigra {
00295         template <class SrcIterator, class SrcAccessor,
00296                 class DestIterator, class DestAccessor>
00297         void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00298                          DestIterator dul, DestAccessor dest);
00299     }
00300     \endcode
00301 
00302 
00303     use argument objects in conjunction with \ref ArgumentObjectFactories:
00304     \code
00305     namespace vigra {
00306         template <class SrcIterator, class SrcAccessor,
00307                 class DestIterator, class DestAccessor>
00308         void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00309                          pair<DestIterator, DestAccessor> d);
00310     }
00311     \endcode
00312 
00313     <b> Usage:</b>
00314 
00315     <b>\#include</b> "<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>"
00316 
00317     \code
00318     FVector3Image tensor(w,h);
00319     FImage trace(w,h);
00320     
00321     tensorTrace(srcImageRange(tensor), destImage(trace));
00322     \endcode
00323 
00324 */
00325 template <class SrcIterator, class SrcAccessor,
00326           class DestIterator, class DestAccessor>
00327 void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00328                  DestIterator dul, DestAccessor dest)
00329 {
00330     vigra_precondition(src.size(sul) == 3,
00331                        "tensorTrace(): input image must have 3 bands.");
00332 
00333     int w = slr.x - sul.x;
00334     int h = slr.y - sul.y;
00335 
00336     for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
00337     {
00338         typename SrcIterator::row_iterator s = sul.rowIterator();
00339         typename SrcIterator::row_iterator send = s + w;
00340         typename DestIterator::row_iterator d = dul.rowIterator();
00341         for(; s < send; ++s, ++d)
00342         {
00343             dest.set(src.getComponent(s,0) + src.getComponent(s,2), d);
00344         }
00345     }
00346 }
00347 
00348 template <class SrcIterator, class SrcAccessor,
00349           class DestIterator, class DestAccessor>
00350 inline
00351 void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00352                  pair<DestIterator, DestAccessor> d)
00353 {
00354     tensorTrace(s.first, s.second, s.third, d.first, d.second);
00355 }
00356 
00357 /********************************************************/
00358 /*                                                      */
00359 /*                  tensorToEdgeCorner                  */
00360 /*                                                      */
00361 /********************************************************/
00362 
00363 /** \brief Decompose a symmetric 2x2 tensor into its edge and corner parts.
00364 
00365     This function turns a 3-band image representing the tensor components
00366     t11, t12 (== t21 due to symmetry), t22 into the a 2-band image holding 
00367     the tensor's edgeness (difference of the tensor's 
00368     eigenvalues) and orientation, and a 1-band image representing its corner part 
00369     (equal to the twice the small eigen value). The original tensor must be 
00370     positive definite and defined in a right-handed coordinate system (e.g.
00371     the tensor resulting from \ref boundaryTensor()).
00372     
00373     <b> Declarations:</b>
00374 
00375     pass arguments explicitly:
00376     \code
00377     namespace vigra {
00378         template <class SrcIterator, class SrcAccessor,
00379                   class DestIterator1, class DestAccessor1,
00380                   class DestIterator2, class DestAccessor2>
00381         void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00382                                 DestIterator1 edgeul, DestAccessor1 edge,
00383                                 DestIterator2 cornerul, DestAccessor2 corner);
00384     }
00385     \endcode
00386 
00387 
00388     use argument objects in conjunction with \ref ArgumentObjectFactories:
00389     \code
00390     namespace vigra {
00391         template <class SrcIterator, class SrcAccessor,
00392                   class DestIterator1, class DestAccessor1,
00393                   class DestIterator2, class DestAccessor2>
00394         void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00395                                 pair<DestIterator1, DestAccessor1> edge,
00396                                 pair<DestIterator2, DestAccessor2> corner);
00397     }
00398     \endcode
00399 
00400     <b> Usage:</b>
00401 
00402     <b>\#include</b> "<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>"
00403 
00404     \code
00405     FVector3Image tensor(w,h);
00406     FVector2Image edgePart(w,h);
00407     FImage cornerPart(w,h);
00408     
00409     tensorTrace(srcImageRange(tensor), destImage(edgePart), destImage(cornerPart));
00410     \endcode
00411 
00412 */
00413 template <class SrcIterator, class SrcAccessor,
00414           class DestIterator1, class DestAccessor1,
00415           class DestIterator2, class DestAccessor2>
00416 void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00417                         DestIterator1 edgeul, DestAccessor1 edge,
00418                         DestIterator2 cornerul, DestAccessor2 corner)
00419 {
00420     vigra_precondition(src.size(sul) == 3,
00421                        "tensorToEdgeCorner(): input image must have 3 bands.");
00422     vigra_precondition(edge.size(edgeul) == 2,
00423                        "tensorToEdgeCorner(): edge image must have 2 bands.");
00424 
00425     int w = slr.x - sul.x;
00426     int h = slr.y - sul.y;
00427 
00428     for(int y=0; y<h; ++y, ++sul.y, ++edgeul.y, ++cornerul.y)
00429     {
00430         typename SrcIterator::row_iterator s = sul.rowIterator();
00431         typename SrcIterator::row_iterator send = s + w;
00432         typename DestIterator1::row_iterator e = edgeul.rowIterator();
00433         typename DestIterator2::row_iterator c = cornerul.rowIterator();
00434         for(; s < send; ++s, ++e, ++c)
00435         {
00436             typedef typename 
00437                NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType;
00438             TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2);
00439             TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2);
00440             TmpType d3 = 2.0 * src.getComponent(s,1);
00441             TmpType d4 = VIGRA_CSTD::sqrt(sq(d2) + sq(d3));
00442             
00443             edge.setComponent(d4, e, 0); // edgeness = difference of EVs
00444             if(d2 == 0.0 && d3 == 0.0)
00445             {
00446                 edge.setComponent(0.0, e, 1); // orientation
00447             }
00448             else
00449             {
00450                 edge.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), e, 1); // orientation
00451             }
00452             corner.set(d1 - d4, c); // cornerness = 2 * small EV
00453         }
00454     }
00455 }
00456 
00457 template <class SrcIterator, class SrcAccessor,
00458           class DestIterator1, class DestAccessor1,
00459           class DestIterator2, class DestAccessor2>
00460 inline
00461 void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00462                         pair<DestIterator1, DestAccessor1> edge,
00463                         pair<DestIterator2, DestAccessor2> corner)
00464 {
00465     tensorToEdgeCorner(s.first, s.second, s.third, 
00466                        edge.first, edge.second, corner.first, corner.second);
00467 }
00468 
00469 //@}
00470 
00471 } // namespace vigra
00472 
00473 #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.5.0 (7 Dec 2006)