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

vigra/tensorutilities.hxx |

    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 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> 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> <<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>>
    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> <<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 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> <<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>>
    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> <<a href="tensorutilities_8hxx-source.html">vigra/tensorutilities.hxx</a>>
    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.7.1 (3 Dec 2010)