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

vigra/tensorutilities.hxx VIGRA

00001 /************************************************************************/
00002 /*                                                                      */
00003 /*               Copyright 2002-2004 by Ullrich Koethe                  */
00004 /*                                                                      */
00005 /*    This file is part of the VIGRA computer vision library.           */
00006 /*    The VIGRA Website is                                              */
00007 /*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
00008 /*    Please direct questions, bug reports, and contributions to        */
00009 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
00010 /*        vigra@informatik.uni-hamburg.de                               */
00011 /*                                                                      */
00012 /*    Permission is hereby granted, free of charge, to any person       */
00013 /*    obtaining a copy of this software and associated documentation    */
00014 /*    files (the "Software"), to deal in the Software without           */
00015 /*    restriction, including without limitation the rights to use,      */
00016 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
00017 /*    sell copies of the Software, and to permit persons to whom the    */
00018 /*    Software is furnished to do so, subject to the following          */
00019 /*    conditions:                                                       */
00020 /*                                                                      */
00021 /*    The above copyright notice and this permission notice shall be    */
00022 /*    included in all copies or substantial portions of the             */
00023 /*    Software.                                                         */
00024 /*                                                                      */
00025 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
00026 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
00027 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
00028 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
00029 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
00030 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
00031 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
00032 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */                
00033 /*                                                                      */
00034 /************************************************************************/
00035 
00036 #ifndef VIGRA_TENSORUTILITIES_HXX
00037 #define VIGRA_TENSORUTILITIES_HXX
00038 
00039 #include <cmath>
00040 #include "utilities.hxx"
00041 #include "mathutil.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 input 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> In order to account for the left-handedness of the image coordinate system,
00064     the second tensor component (t12) can be negated by setting <tt>negateComponent2 = false</tt>.
00065     Angles will then be interpreted counter-clockwise rather than clockwise. By default,
00066     this behavior is switched off.
00067     
00068     <b> Declarations:</b>
00069 
00070     pass arguments explicitly:
00071     \code
00072     namespace vigra {
00073         template <class SrcIterator, class SrcAccessor,
00074                   class DestIterator, class DestAccessor>
00075         void vectorToTensor(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00076                             DestIterator dul, DestAccessor dest,
00077                             bool negateComponent2 = false);
00078     }
00079     \endcode
00080 
00081 
00082     use argument objects in conjunction with \ref ArgumentObjectFactories :
00083     \code
00084     namespace vigra {
00085         template <class SrcIterator, class SrcAccessor,
00086                   class DestIterator, class DestAccessor>
00087         void vectorToTensor(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00088                             pair<DestIterator, DestAccessor> d,
00089                             bool negateComponent2 = false);
00090     }
00091     \endcode
00092 
00093     <b> Usage:</b>
00094 
00095     <b>\#include</b> <vigra/tensorutilities.hxx>
00096 
00097     \code
00098     FImage img(w,h);
00099     FVector2Image gradient(w,h);
00100     FVector3Image tensor(w,h);
00101     
00102     gaussianGradient(srcImageRange(img), destImage(gradient), 2.0);
00103     vectorToTensor(srcImageRange(gradient), destImage(tensor));
00104     \endcode
00105 
00106 */
00107 doxygen_overloaded_function(template <...> void vectorToTensor)
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, false);
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, false);
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 > e2. When the tensor is
00189     defined in a left-handed coordinate system (the default on images), the angle will
00190     then be given in clockwise orientation, starting at the x-axis. Otherwise, it
00191     will be given in counter-clockwise orientation.
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> <vigra/tensorutilities.hxx>
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 doxygen_overloaded_function(template <...> void tensorEigenRepresentation)
00229 
00230 template <class SrcIterator, class SrcAccessor,
00231           class DestIterator, class DestAccessor>
00232 void tensorEigenRepresentation(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00233                                DestIterator dul, DestAccessor dest)
00234 {
00235     vigra_precondition(src.size(sul) == 3,
00236                        "tensorEigenRepresentation(): input image must have 3 bands.");
00237     vigra_precondition(dest.size(dul) == 3,
00238                        "tensorEigenRepresentation(): output image must have 3 bands.");
00239 
00240     int w = slr.x - sul.x;
00241     int h = slr.y - sul.y;
00242 
00243     for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
00244     {
00245         typename SrcIterator::row_iterator s = sul.rowIterator();
00246         typename SrcIterator::row_iterator send = s + w;
00247         typename DestIterator::row_iterator d = dul.rowIterator();
00248         for(; s < send; ++s, ++d)
00249         {
00250             typedef typename 
00251                NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType;
00252             TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2);
00253             TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2);
00254             TmpType d3 = TmpType(2.0) * src.getComponent(s,1);
00255             TmpType d4 = (TmpType)hypot(d2, d3);
00256             
00257             dest.setComponent(0.5 * (d1 + d4), d, 0); // large EV
00258             dest.setComponent(0.5 * (d1 - d4), d, 1); // small EV
00259             if(d2==0.0 && d3==0.0)
00260             {
00261                 dest.setComponent(0, d, 2); // orientation
00262             }
00263             else
00264             {
00265                 dest.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), d, 2); // orientation
00266             }
00267         }
00268     }
00269 }
00270 
00271 template <class SrcIterator, class SrcAccessor,
00272           class DestIterator, class DestAccessor>
00273 inline
00274 void tensorEigenRepresentation(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00275                                pair<DestIterator, DestAccessor> d)
00276 {
00277     tensorEigenRepresentation(s.first, s.second, s.third, d.first, d.second);
00278 }
00279 
00280 /********************************************************/
00281 /*                                                      */
00282 /*                      tensorTrace                     */
00283 /*                                                      */
00284 /********************************************************/
00285 
00286 /** \brief Calculate the trace of a 2x2 tensor.
00287 
00288     This function turns a 3-band image representing the tensor components
00289     t11, t12 (== t21 due to symmetry), t22 into the a 1-band image holding the 
00290     tensor trace t11 + t22.
00291     
00292     <b> Declarations:</b>
00293 
00294     pass arguments explicitly:
00295     \code
00296     namespace vigra {
00297         template <class SrcIterator, class SrcAccessor,
00298                   class DestIterator, class DestAccessor>
00299         void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00300                          DestIterator dul, DestAccessor dest);
00301     }
00302     \endcode
00303 
00304 
00305     use argument objects in conjunction with \ref ArgumentObjectFactories :
00306     \code
00307     namespace vigra {
00308         template <class SrcIterator, class SrcAccessor,
00309                   class DestIterator, class DestAccessor>
00310         void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00311                          pair<DestIterator, DestAccessor> d);
00312     }
00313     \endcode
00314 
00315     <b> Usage:</b>
00316 
00317     <b>\#include</b> <vigra/tensorutilities.hxx>
00318 
00319     \code
00320     FVector3Image tensor(w,h);
00321     FImage trace(w,h);
00322     
00323     tensorTrace(srcImageRange(tensor), destImage(trace));
00324     \endcode
00325 
00326 */
00327 doxygen_overloaded_function(template <...> void tensorTrace)
00328 
00329 template <class SrcIterator, class SrcAccessor,
00330           class DestIterator, class DestAccessor>
00331 void tensorTrace(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00332                  DestIterator dul, DestAccessor dest)
00333 {
00334     vigra_precondition(src.size(sul) == 3,
00335                        "tensorTrace(): input image must have 3 bands.");
00336 
00337     int w = slr.x - sul.x;
00338     int h = slr.y - sul.y;
00339 
00340     for(int y=0; y<h; ++y, ++sul.y, ++dul.y)
00341     {
00342         typename SrcIterator::row_iterator s = sul.rowIterator();
00343         typename SrcIterator::row_iterator send = s + w;
00344         typename DestIterator::row_iterator d = dul.rowIterator();
00345         for(; s < send; ++s, ++d)
00346         {
00347             dest.set(src.getComponent(s,0) + src.getComponent(s,2), d);
00348         }
00349     }
00350 }
00351 
00352 template <class SrcIterator, class SrcAccessor,
00353           class DestIterator, class DestAccessor>
00354 inline
00355 void tensorTrace(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00356                  pair<DestIterator, DestAccessor> d)
00357 {
00358     tensorTrace(s.first, s.second, s.third, d.first, d.second);
00359 }
00360 
00361 /********************************************************/
00362 /*                                                      */
00363 /*                  tensorToEdgeCorner                  */
00364 /*                                                      */
00365 /********************************************************/
00366 
00367 /** \brief Decompose a symmetric 2x2 tensor into its edge and corner parts.
00368 
00369     This function turns a 3-band image representing the tensor components
00370     t11, t12 (== t21 due to symmetry), t22 into the a 2-band image holding 
00371     the tensor's edgeness (difference of the tensor's 
00372     eigenvalues) and orientation, and a 1-band image representing its corner part 
00373     (equal to the twice the small eigen value). The original tensor must be 
00374     positive definite and defined in a right-handed coordinate system (e.g.
00375     the tensor resulting from \ref boundaryTensor()).
00376     
00377     <b> Declarations:</b>
00378 
00379     pass arguments explicitly:
00380     \code
00381     namespace vigra {
00382         template <class SrcIterator, class SrcAccessor,
00383                   class DestIterator1, class DestAccessor1,
00384                   class DestIterator2, class DestAccessor2>
00385         void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00386                                 DestIterator1 edgeul, DestAccessor1 edge,
00387                                 DestIterator2 cornerul, DestAccessor2 corner);
00388     }
00389     \endcode
00390 
00391 
00392     use argument objects in conjunction with \ref ArgumentObjectFactories :
00393     \code
00394     namespace vigra {
00395         template <class SrcIterator, class SrcAccessor,
00396                   class DestIterator1, class DestAccessor1,
00397                   class DestIterator2, class DestAccessor2>
00398         void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00399                                 pair<DestIterator1, DestAccessor1> edge,
00400                                 pair<DestIterator2, DestAccessor2> corner);
00401     }
00402     \endcode
00403 
00404     <b> Usage:</b>
00405 
00406     <b>\#include</b> <vigra/tensorutilities.hxx>
00407 
00408     \code
00409     FVector3Image tensor(w,h);
00410     FVector2Image edgePart(w,h);
00411     FImage cornerPart(w,h);
00412     
00413     tensorTrace(srcImageRange(tensor), destImage(edgePart), destImage(cornerPart));
00414     \endcode
00415 
00416 */
00417 doxygen_overloaded_function(template <...> void tensorToEdgeCorner)
00418 
00419 template <class SrcIterator, class SrcAccessor,
00420           class DestIterator1, class DestAccessor1,
00421           class DestIterator2, class DestAccessor2>
00422 void tensorToEdgeCorner(SrcIterator sul, SrcIterator slr, SrcAccessor src,
00423                         DestIterator1 edgeul, DestAccessor1 edge,
00424                         DestIterator2 cornerul, DestAccessor2 corner)
00425 {
00426     vigra_precondition(src.size(sul) == 3,
00427                        "tensorToEdgeCorner(): input image must have 3 bands.");
00428     vigra_precondition(edge.size(edgeul) == 2,
00429                        "tensorToEdgeCorner(): edge image must have 2 bands.");
00430 
00431     int w = slr.x - sul.x;
00432     int h = slr.y - sul.y;
00433 
00434     for(int y=0; y<h; ++y, ++sul.y, ++edgeul.y, ++cornerul.y)
00435     {
00436         typename SrcIterator::row_iterator s = sul.rowIterator();
00437         typename SrcIterator::row_iterator send = s + w;
00438         typename DestIterator1::row_iterator e = edgeul.rowIterator();
00439         typename DestIterator2::row_iterator c = cornerul.rowIterator();
00440         for(; s < send; ++s, ++e, ++c)
00441         {
00442             typedef typename 
00443                NumericTraits<typename SrcAccessor::component_type>::RealPromote TmpType;
00444             TmpType d1 = src.getComponent(s,0) + src.getComponent(s,2);
00445             TmpType d2 = src.getComponent(s,0) - src.getComponent(s,2);
00446             TmpType d3 = 2.0 * src.getComponent(s,1);
00447             TmpType d4 = (TmpType)hypot(d2, d3);
00448             
00449             edge.setComponent(d4, e, 0); // edgeness = difference of EVs
00450             if(d2 == 0.0 && d3 == 0.0)
00451             {
00452                 edge.setComponent(0.0, e, 1); // orientation
00453             }
00454             else
00455             {
00456                 edge.setComponent(0.5 * VIGRA_CSTD::atan2(d3, d2), e, 1); // orientation
00457             }
00458             corner.set(d1 - d4, c); // cornerness = 2 * small EV
00459         }
00460     }
00461 }
00462 
00463 template <class SrcIterator, class SrcAccessor,
00464           class DestIterator1, class DestAccessor1,
00465           class DestIterator2, class DestAccessor2>
00466 inline
00467 void tensorToEdgeCorner(triple<SrcIterator, SrcIterator, SrcAccessor> s,
00468                         pair<DestIterator1, DestAccessor1> edge,
00469                         pair<DestIterator2, DestAccessor2> corner)
00470 {
00471     tensorToEdgeCorner(s.first, s.second, s.third, 
00472                        edge.first, edge.second, corner.first, corner.second);
00473 }
00474 
00475 //@}
00476 
00477 } // namespace vigra
00478 
00479 #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.9.0 (Tue Nov 6 2012)