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

vigra/rgbvalue.hxx

00001 /************************************************************************/
00002 /*                                                                      */
00003 /*               Copyright 1998-2002 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 
00038 #ifndef VIGRA_RGBVALUE_HXX
00039 #define VIGRA_RGBVALUE_HXX
00040 
00041 #include <cmath>    // abs(double)
00042 #include <cstdlib>  // abs(int)
00043 #include "config.hxx"
00044 #include "numerictraits.hxx"
00045 #include "accessor.hxx"
00046 #include "tinyvector.hxx"
00047 #include "static_assert.hxx"
00048 
00049 namespace vigra {
00050 
00051 namespace detail {
00052 
00053 template <unsigned int I, unsigned int R, unsigned int G, unsigned int B>
00054 struct SelectColorIndexRHS;
00055 
00056 template <unsigned int R, unsigned int G, unsigned int B>
00057 struct SelectColorIndexRHS<0, R, G, B>
00058 {
00059     enum { res = R };
00060 };
00061 
00062 template <unsigned int R, unsigned int G, unsigned int B>
00063 struct SelectColorIndexRHS<1, R, G, B>
00064 {
00065     enum { res = G };
00066 };
00067 
00068 template <unsigned int R, unsigned int G, unsigned int B>
00069 struct SelectColorIndexRHS<2, R, G, B>
00070 {
00071     enum { res = B };
00072 };
00073 
00074 } // namespace detail
00075 
00076 #ifndef DOXYGEN
00077 
00078 template <unsigned int R, unsigned int G, unsigned int B>
00079 struct RGBValue_bad_color_indices
00080 : staticAssert::AssertBool<(R < 3 && G < 3 && B < 3 &&
00081                            ((1 << R) + (1 << G) + (1 << B) == 7))>
00082 {};
00083 
00084 #endif /* DOXYGEN */
00085 
00086 
00087 /********************************************************/
00088 /*                                                      */
00089 /*                      RGBValue                        */
00090 /*                                                      */
00091 /********************************************************/
00092 
00093 /** \brief Class for a single RGB value.
00094 
00095     This class contains three values (of the specified type) that represent
00096     red, green, and blue color channels. By means of the template parameters
00097     <tt>RED_IDX, GREEN_IDX, BLUE_IDX</tt>, the indices 0, 1, 2 can be assigned to
00098     the three colors arbitrarily, so that, for example, a BGR type can be created
00099     as
00100 
00101     \code
00102     typedef RGBValue<unsigned char, 2,1,0> BGRValue;
00103     \endcode
00104 
00105     The standard order red=0, green=1, blue=2 is the default. There are three possibilities
00106     to access the color values: accessor functions (\ref red(), \ref green(),
00107     \ref blue()), index operator (operator[](dx), where the <tt>rgb[RED_IDX]</tt>
00108     returns red etc.) and iterator (STL-compatible random access
00109     iterator that references the three colors in turn). The latter two
00110     methods, together with the necessary embedded typedefs, ensure
00111     compatibility of a RGBValue with a STL vector.
00112 
00113     \ref RGBValueOperators "Arithmetic operations" are defined as component-wise applications of these
00114     operations. Addition, subtraction, and multiplication of two RGBValues
00115     (+=, -=, *=, +, -, *, unary -), multiplication and division of an
00116     RGBValue with a double, and NumericTraits/PromoteTraits are defined,
00117     so that RGBValue fulfills the requirements of a \ref LinearAlgebraConcept "Linear Algebra".
00118 
00119     A number of \ref RGBValueAccessors "accessors" are provided
00120     that support access to RGBValues as a whole, to a selected
00121     color component, or to the luminance value.
00122 
00123     <b>\#include</b> <<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.hxx</a>><br>
00124     Namespace: vigra
00125 */
00126 template <class VALUETYPE, unsigned int RED_IDX = 0, unsigned int GREEN_IDX = 1, unsigned int BLUE_IDX = 2>
00127 class RGBValue
00128 : public TinyVector<VALUETYPE, 3>
00129 {
00130     typedef TinyVector<VALUETYPE, 3> Base;
00131 
00132         // inverse mapping from index to color
00133     enum {
00134       IDX0 = (RED_IDX == 0) ? 0 : (GREEN_IDX == 0) ? 1 : 2,
00135       IDX1 = (RED_IDX == 1) ? 0 : (GREEN_IDX == 1) ? 1 : 2,
00136       IDX2 = (RED_IDX == 2) ? 0 : (GREEN_IDX == 2) ? 1 : 2
00137     };
00138 
00139   public:
00140         /** STL-compatible definition of valuetype
00141         */
00142     typedef typename Base::value_type value_type;
00143         /** STL-compatible definition of iterator
00144         */
00145     typedef typename Base::iterator iterator;
00146         /** STL-compatible definition of const iterator
00147         */
00148     typedef typename Base::const_iterator const_iterator;
00149         /** squared norm type (result of squaredManitude())
00150         */
00151     typedef typename Base::SquaredNormType SquaredNormType;
00152         /** norm type (result of magnitude())
00153         */
00154     typedef typename Base::NormType NormType;
00155 
00156         /** Color index positions
00157         */
00158     enum
00159     {
00160       RedIdx = RED_IDX,
00161       GreenIdx = GREEN_IDX,
00162       BlueIdx = BLUE_IDX
00163     };
00164 
00165         /** Construct from explicit color values.
00166             \a first, \a second, \a third are written in this order,
00167             irrespective of how the color indices are specified.
00168         */
00169     RGBValue(value_type first, value_type second, value_type third)
00170     : Base(first, second, third)
00171     {
00172         VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX, BLUE_IDX>));
00173     }
00174 
00175         /** Construct gray value
00176         */
00177     RGBValue(value_type gray)
00178     : Base(gray, gray, gray)
00179     {
00180         VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX, BLUE_IDX>));
00181     }
00182 
00183         /** Construct from another sequence (must have length 3!)
00184         */
00185     template <class Iterator>
00186     RGBValue(Iterator i, Iterator end)
00187     : Base(i[0], i[1], i[2])
00188     {
00189         VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX, BLUE_IDX>));
00190     }
00191 
00192         /** Default constructor (sets all components to 0)
00193         */
00194     RGBValue()
00195     : Base(0, 0, 0)
00196     {
00197         VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX, BLUE_IDX>));
00198     }
00199 
00200 #if !defined(TEMPLATE_COPY_CONSTRUCTOR_BUG)
00201 
00202     RGBValue(RGBValue const & r)
00203     : Base(r)
00204     {
00205         VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX, BLUE_IDX>));
00206     }
00207 
00208     RGBValue & operator=(RGBValue const & r)
00209     {
00210         Base::operator=(r);
00211         return *this;
00212     }
00213 
00214 #endif // TEMPLATE_COPY_CONSTRUCTOR_BUG
00215 
00216         /** Copy constructor.
00217         */
00218     template <class U, unsigned int R, unsigned int G, unsigned int B>
00219     RGBValue(RGBValue<U, R, G, B> const & r)
00220     : Base(detail::RequiresExplicitCast<value_type>::cast(r[detail::SelectColorIndexRHS<IDX0, R, G, B>::res]),
00221            detail::RequiresExplicitCast<value_type>::cast(r[detail::SelectColorIndexRHS<IDX1, R, G, B>::res]),
00222            detail::RequiresExplicitCast<value_type>::cast(r[detail::SelectColorIndexRHS<IDX2, R, G, B>::res]))
00223     {
00224         VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX, BLUE_IDX>));
00225     }
00226 
00227         /** Copy assignment.
00228         */
00229     template <class U, unsigned int R, unsigned int G, unsigned int B>
00230     RGBValue & operator=(RGBValue<U, R, G, B> const & r)
00231     {
00232         setRed(detail::RequiresExplicitCast<value_type>::cast(r.red()));
00233         setGreen(detail::RequiresExplicitCast<value_type>::cast(r.green()));
00234         setBlue(detail::RequiresExplicitCast<value_type>::cast(r.blue()));
00235         return *this;
00236     }
00237 
00238         /** construct from TinyVector
00239         */
00240     RGBValue(TinyVector<value_type, 3> const & r)
00241     : Base(r)
00242     {
00243         VIGRA_STATIC_ASSERT((RGBValue_bad_color_indices<RED_IDX, GREEN_IDX, BLUE_IDX>));
00244     }
00245 
00246         /** assign TinyVector.
00247         */
00248     RGBValue & operator=(TinyVector<value_type, 3> const & r)
00249     {
00250         Base::operator=(r);
00251         return *this;
00252     }
00253 
00254         /** Unary negation (construct RGBValue with negative values)
00255         */
00256     RGBValue operator-() const
00257     {
00258         return RGBValue(-red(), -green(), -blue());
00259     }
00260 
00261         /** Access red component.
00262         */
00263     value_type & red() { return (*this)[RED_IDX]; }
00264 
00265         /** Access green component.
00266         */
00267     value_type & green() { return (*this)[GREEN_IDX]; }
00268 
00269         /** Access blue component.
00270         */
00271     value_type & blue() { return (*this)[BLUE_IDX]; }
00272 
00273         /** Get red component.
00274         */
00275     value_type const & red() const { return (*this)[RED_IDX]; }
00276 
00277         /** Get green component.
00278         */
00279     value_type const & green() const { return (*this)[GREEN_IDX]; }
00280 
00281         /** Get blue component.
00282         */
00283     value_type const & blue() const { return (*this)[BLUE_IDX]; }
00284 
00285         /** Calculate luminance.
00286         */
00287     value_type luminance() const {
00288          return detail::RequiresExplicitCast<value_type>::cast(0.3*red() + 0.59*green() + 0.11*blue()); }
00289 
00290         /** Calculate magnitude.
00291         */
00292     NormType magnitude() const {
00293          return Base::magnitude();
00294     }
00295 
00296         /** Calculate squared magnitude.
00297         */
00298     SquaredNormType squaredMagnitude() const {
00299          return Base::squaredMagnitude();
00300     }
00301 
00302         /** Set red component. The type <TT>V</TT> of the passed
00303             in <TT>value</TT> is automatically converted to <TT>VALUETYPE</TT>.
00304         */
00305     template <class V>
00306     void setRed(V value) { (*this)[RED_IDX] = detail::RequiresExplicitCast<value_type>::cast(value); }
00307 
00308         /** Set green component.The type <TT>V</TT> of the passed
00309             in <TT>value</TT> is automatically converted to <TT>VALUETYPE</TT>.
00310         */
00311     template <class V>
00312     void setGreen(V value) { (*this)[GREEN_IDX] = detail::RequiresExplicitCast<value_type>::cast(value); }
00313 
00314         /** Set blue component.The type <TT>V</TT> of the passed
00315             in <TT>value</TT> is automatically converted to <TT>VALUETYPE</TT>.
00316         */
00317     template <class V>
00318     void setBlue(V value) { (*this)[BLUE_IDX] = detail::RequiresExplicitCast<value_type>::cast(value); }
00319 
00320 
00321     template <class V>
00322     void setRGB(V r, V g, V b)
00323     {
00324         (*this)[RED_IDX] = detail::RequiresExplicitCast<value_type>::cast(r);
00325         (*this)[GREEN_IDX] = detail::RequiresExplicitCast<value_type>::cast(g);
00326         (*this)[BLUE_IDX] = detail::RequiresExplicitCast<value_type>::cast(b);
00327     }
00328 };
00329 
00330 /********************************************************/
00331 /*                                                      */
00332 /*                     RGBValue Comparison              */
00333 /*                                                      */
00334 /********************************************************/
00335 
00336 /** \addtogroup RGBValueOperators Functions for RGBValue
00337 
00338     \brief Implement basic arithmetic and equality for RGBValue.
00339 
00340     These functions fulfill the requirements of a Linear Algebra.
00341     Return types are determined according to \ref RGBValueTraits.
00342 
00343     <b>\#include</b> <<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.hxx</a>><br>
00344     Namespace: vigra
00345     <p>
00346 
00347  */
00348 //@{
00349     /// component-wise equal
00350 template <class V1, unsigned int RIDX1, unsigned int GIDX1, unsigned int BIDX1,
00351           class V2, unsigned int RIDX2, unsigned int GIDX2, unsigned int BIDX2>
00352 inline
00353 bool
00354 operator==(RGBValue<V1, RIDX1, GIDX1, BIDX1> const & l,
00355            RGBValue<V2, RIDX2, GIDX2, BIDX2> const & r)
00356 {
00357     return (l.red() == r.red()) &&
00358            (l.green() == r.green()) &&
00359            (l.blue() == r.blue());
00360 }
00361 
00362     /// component-wise not equal
00363 template <class V1, unsigned int RIDX1, unsigned int GIDX1, unsigned int BIDX1,
00364           class V2, unsigned int RIDX2, unsigned int GIDX2, unsigned int BIDX2>
00365 inline
00366 bool
00367 operator!=(RGBValue<V1, RIDX1, GIDX1, BIDX1> const & l,
00368            RGBValue<V2, RIDX2, GIDX2, BIDX2> const & r)
00369 {
00370     return (l.red() != r.red()) ||
00371            (l.green() != r.green()) ||
00372            (l.blue() != r.blue());
00373 }
00374 
00375 
00376 //@}
00377 
00378 /********************************************************/
00379 /*                                                      */
00380 /*                      RGBValue-Traits                 */
00381 /*                                                      */
00382 /********************************************************/
00383 
00384 /** \page RGBValueTraits Numeric and Promote Traits of RGBValue
00385     The numeric and promote traits for RGBValues follow
00386     the general specifications for \ref NumericPromotionTraits.
00387     They are implemented in terms of the traits of the basic types by
00388     partial template specialization. Note that PromoteTraits are only defined
00389     for the case that the color indices are the same in both RGBValues.
00390 
00391     \code
00392 
00393     template <class T, unsigned int R, unsigned int G, unsigned int B>
00394     struct NumericTraits<RGBValue<T, R, G, B> >
00395     {
00396         typedef RGBValue<T, R, G, B> Type;
00397         typedef RGBValue<typename NumericTraits<T>::Promote, R, G, B> Promote;
00398         typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> RealPromote;
00399         typedef RGBValue<typename NumericTraits<T>::ComplexPromote, R, G, B> ComplexPromote;
00400         typedef T ValueType;
00401 
00402         typedef typename NumericTraits<T>::isIntegral isIntegral;
00403         typedef VigraFalseType isScalar;
00404         typedef typename NumericTraits<T>::isSigned isSigned;
00405 
00406         // etc.
00407     };
00408 
00409     template <class T, unsigned int R, unsigned int G, unsigned int B>
00410     struct NormTraits<RGBValue<T, R, G, B> >
00411     {
00412         typedef RGBValue<T, R, G, B> Type;
00413         typedef typename Type::SquaredNormType    SquaredNormType;
00414         typedef typename Type::NormType           NormType;
00415     };
00416 
00417     template <class T1, unsigned int R, unsigned int G, unsigned int B, class T2>
00418     struct PromoteTraits<RGBValue<T1, R, G, B>, RGBValue<T2, R, G, B> >
00419     {
00420         typedef RGBValue<typename PromoteTraits<T1, T2>::Promote, R, G, B> Promote;
00421     };
00422 
00423     template <class T, unsigned int R, unsigned int G, unsigned int B>
00424     struct PromoteTraits<RGBValue<T, R, G, B>, double >
00425     {
00426         typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> Promote;
00427     };
00428 
00429     template <class T, unsigned int R, unsigned int G, unsigned int B>
00430     struct PromoteTraits<double, RGBValue<T, R, G, B> >
00431     {
00432         typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> Promote;
00433     };
00434     \endcode
00435 
00436     <b>\#include</b> <<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.hxx</a>><br>
00437     Namespace: vigra
00438 
00439 */
00440 
00441 #if !defined(NO_PARTIAL_TEMPLATE_SPECIALIZATION)
00442 
00443 template <class T, unsigned int R, unsigned int G, unsigned int B>
00444 struct NumericTraits<RGBValue<T, R, G, B> >
00445 {
00446     typedef RGBValue<T, R, G, B> Type;
00447     typedef RGBValue<typename NumericTraits<T>::Promote, R, G, B> Promote;
00448     typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> RealPromote;
00449     typedef RGBValue<typename NumericTraits<T>::ComplexPromote, R, G, B> ComplexPromote;
00450     typedef T ValueType;
00451 
00452     typedef typename NumericTraits<T>::isIntegral isIntegral;
00453     typedef VigraFalseType isScalar;
00454     typedef typename NumericTraits<T>::isSigned isSigned;
00455     typedef VigraFalseType isOrdered;
00456     typedef VigraFalseType isComplex;
00457 
00458     static Type zero() {
00459         return Type(NumericTraits<T>::zero());
00460     }
00461     static Type one() {
00462         return Type(NumericTraits<T>::one());
00463     }
00464     static Type nonZero() {
00465         return Type(NumericTraits<T>::nonZero());
00466     }
00467 
00468     static Promote toPromote(Type const & v) {
00469         return Promote(v);
00470     }
00471     static RealPromote toRealPromote(Type const & v) {
00472         return RealPromote(v);
00473     }
00474     static Type fromPromote(Promote const & v) {
00475       return Type(NumericTraits<T>::fromPromote(v.red()),
00476                   NumericTraits<T>::fromPromote(v.green()),
00477                   NumericTraits<T>::fromPromote(v.blue()));
00478     }
00479     static Type fromRealPromote(RealPromote const & v) {
00480         return Type(NumericTraits<T>::fromRealPromote(v.red()),
00481                     NumericTraits<T>::fromRealPromote(v.green()),
00482                     NumericTraits<T>::fromRealPromote(v.blue()));
00483     }
00484 };
00485 
00486 template <class T, unsigned int R, unsigned int G, unsigned int B>
00487 struct NormTraits<RGBValue<T, R, G, B> >
00488 {
00489     typedef RGBValue<T, R, G, B> Type;
00490     typedef typename Type::SquaredNormType    SquaredNormType;
00491     typedef typename Type::NormType           NormType;
00492 };
00493 
00494 template <class T1, unsigned int R, unsigned int G, unsigned int B, class T2>
00495 struct PromoteTraits<RGBValue<T1, R, G, B>, RGBValue<T2, R, G, B> >
00496 {
00497     typedef RGBValue<typename PromoteTraits<T1, T2>::Promote, R, G, B> Promote;
00498 };
00499 
00500 template <class T, unsigned int R, unsigned int G, unsigned int B>
00501 struct PromoteTraits<RGBValue<T, R, G, B>, double >
00502 {
00503     typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> Promote;
00504 };
00505 
00506 template <class T, unsigned int R, unsigned int G, unsigned int B>
00507 struct PromoteTraits<double, RGBValue<T, R, G, B> >
00508 {
00509     typedef RGBValue<typename NumericTraits<T>::RealPromote, R, G, B> Promote;
00510 };
00511 
00512 #else // NO_PARTIAL_TEMPLATE_SPECIALIZATION
00513 
00514 #define RGBVALUE_NUMTRAITS(T) \
00515 template<>\
00516 struct NumericTraits<RGBValue<T, 0, 1, 2> >\
00517 {\
00518     typedef RGBValue<T> Type; \
00519     typedef RGBValue<NumericTraits<T>::Promote> Promote; \
00520     typedef RGBValue<NumericTraits<T>::RealPromote> RealPromote; \
00521     typedef RGBValue<NumericTraits<T>::ComplexPromote> ComplexPromote; \
00522     typedef T ValueType; \
00523     \
00524     typedef NumericTraits<T>::isIntegral isIntegral; \
00525     typedef VigraFalseType isScalar; \
00526     typedef NumericTraits<T>::isSigned isSigned; \
00527     typedef VigraFalseType isOrdered; \
00528     typedef VigraFalseType isComplex; \
00529     \
00530     static RGBValue<T> zero() { \
00531         return RGBValue<T>(NumericTraits<T>::zero()); \
00532     }\
00533     static RGBValue<T> one() { \
00534         return RGBValue<T>(NumericTraits<T>::one()); \
00535     }\
00536     static RGBValue<T> nonZero() { \
00537         return RGBValue<T>(NumericTraits<T>::nonZero()); \
00538     }\
00539     \
00540     static Promote toPromote(RGBValue<T> const & v) { \
00541         return Promote(v); \
00542     }\
00543     static RealPromote toRealPromote(RGBValue<T> const & v) { \
00544         return RealPromote(v); \
00545     }\
00546     static RGBValue<T> fromPromote(Promote const & v) { \
00547         RGBValue<T> res;\
00548         RGBValue<T>::iterator d = res.begin();\
00549         Promote::const_iterator s = v.begin();\
00550         for(; d != res.end(); ++d, ++s)\
00551             *d = NumericTraits<T>::fromPromote(*s);\
00552         return res;\
00553     }\
00554     static RGBValue<T> fromRealPromote(RealPromote const & v) {\
00555         RGBValue<T> res;\
00556         RGBValue<T>::iterator d = res.begin();\
00557         RealPromote::const_iterator s = v.begin();\
00558         for(; d != res.end(); ++d, ++s)\
00559             *d = NumericTraits<T>::fromRealPromote(*s);\
00560         return res;\
00561     }\
00562 }; \
00563 template<>\
00564 struct NormTraits<RGBValue<T, 0, 1, 2> >\
00565 {\
00566     typedef RGBValue<T> Type;\
00567     typedef Type::SquaredNormType           SquaredNormType; \
00568     typedef Type::NormType NormType; \
00569 };
00570 
00571 #define RGBVALUE_PROMTRAITS1(type1) \
00572 template<> \
00573 struct PromoteTraits<RGBValue<type1, 0, 1, 2>, RGBValue<type1, 0, 1, 2> > \
00574 { \
00575     typedef RGBValue<PromoteTraits<type1, type1>::Promote> Promote; \
00576     static Promote toPromote(RGBValue<type1> const & v) { \
00577         return static_cast<Promote>(v); } \
00578 }; \
00579 template <> \
00580 struct PromoteTraits<RGBValue<type1, 0, 1, 2>, double > \
00581 { \
00582     typedef RGBValue<typename NumericTraits<type1>::RealPromote> Promote; \
00583 }; \
00584 template <> \
00585 struct PromoteTraits<double, RGBValue<type1, 0, 1, 2> > \
00586 { \
00587     typedef RGBValue<typename NumericTraits<type1>::RealPromote> Promote; \
00588 };
00589 
00590 #define RGBVALUE_PROMTRAITS2(type1, type2) \
00591 template<> \
00592 struct PromoteTraits<RGBValue<type1, 0, 1, 2>, RGBValue<type2, 0, 1, 2> > \
00593 { \
00594     typedef RGBValue<PromoteTraits<type1, type2>::Promote> Promote; \
00595     static Promote toPromote(RGBValue<type1> const & v) { \
00596         return static_cast<Promote>(v); } \
00597     static Promote toPromote(RGBValue<type2> const & v) { \
00598         return static_cast<Promote>(v); } \
00599 };
00600 
00601 RGBVALUE_NUMTRAITS(unsigned char)
00602 RGBVALUE_NUMTRAITS(int)
00603 RGBVALUE_NUMTRAITS(float)
00604 RGBVALUE_NUMTRAITS(double)
00605 RGBVALUE_PROMTRAITS1(unsigned char)
00606 RGBVALUE_PROMTRAITS1(int)
00607 RGBVALUE_PROMTRAITS1(float)
00608 RGBVALUE_PROMTRAITS1(double)
00609 RGBVALUE_PROMTRAITS2(float, unsigned char)
00610 RGBVALUE_PROMTRAITS2(unsigned char, float)
00611 RGBVALUE_PROMTRAITS2(int, unsigned char)
00612 RGBVALUE_PROMTRAITS2(unsigned char, int)
00613 RGBVALUE_PROMTRAITS2(int, float)
00614 RGBVALUE_PROMTRAITS2(float, int)
00615 RGBVALUE_PROMTRAITS2(double, unsigned char)
00616 RGBVALUE_PROMTRAITS2(unsigned char, double)
00617 RGBVALUE_PROMTRAITS2(int, double)
00618 RGBVALUE_PROMTRAITS2(double, int)
00619 RGBVALUE_PROMTRAITS2(double, float)
00620 RGBVALUE_PROMTRAITS2(float, double)
00621 
00622 #undef RGBVALUE_NUMTRAITS
00623 #undef RGBVALUE_PROMTRAITS1
00624 #undef RGBVALUE_PROMTRAITS2
00625 
00626 #endif // NO_PARTIAL_TEMPLATE_SPECIALIZATION
00627 
00628 
00629 /********************************************************/
00630 /*                                                      */
00631 /*                      RGBValue-Arithmetic             */
00632 /*                                                      */
00633 /********************************************************/
00634 
00635 /** \addtogroup RGBValueOperators
00636  */
00637 //@{
00638     /// componentwise add-assignment
00639 template <class V1, unsigned int RIDX1, unsigned int GIDX1, unsigned int BIDX1,
00640           class V2, unsigned int RIDX2, unsigned int GIDX2, unsigned int BIDX2>
00641 inline
00642 RGBValue<V1, RIDX1, GIDX1, BIDX1> &
00643 operator+=(RGBValue<V1, RIDX1, GIDX1, BIDX1> & l,
00644            RGBValue<V2, RIDX2, GIDX2, BIDX2> const & r)
00645 {
00646     l.red() += r.red();
00647     l.green() += r.green();
00648     l.blue() += r.blue();
00649     return l;
00650 }
00651 
00652     /// componentwise subtract-assignment
00653 template <class V1, unsigned int RIDX1, unsigned int GIDX1, unsigned int BIDX1,
00654           class V2, unsigned int RIDX2, unsigned int GIDX2, unsigned int BIDX2>
00655 inline
00656 RGBValue<V1, RIDX1, GIDX1, BIDX1> &
00657 operator-=(RGBValue<V1, RIDX1, GIDX1, BIDX1> & l,
00658            RGBValue<V2, RIDX2, GIDX2, BIDX2> const & r)
00659 {
00660     l.red() -= r.red();
00661     l.green() -= r.green();
00662     l.blue() -= r.blue();
00663     return l;
00664 }
00665 
00666     /// componentwise multiply-assignment
00667 template <class V1, unsigned int RIDX1, unsigned int GIDX1, unsigned int BIDX1,
00668           class V2, unsigned int RIDX2, unsigned int GIDX2, unsigned int BIDX2>
00669 inline
00670 RGBValue<V1, RIDX1, GIDX1, BIDX1> &
00671 operator*=(RGBValue<V1, RIDX1, GIDX1, BIDX1> & l,
00672            RGBValue<V2, RIDX2, GIDX2, BIDX2> const & r)
00673 {
00674     l.red() *= r.red();
00675     l.green() *= r.green();
00676     l.blue() *= r.blue();
00677     return l;
00678 }
00679 
00680     /// componentwise scalar multiply-assignment
00681 template <class V, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX>
00682 inline
00683 RGBValue<V, RIDX, GIDX, BIDX> &
00684 operator*=(RGBValue<V, RIDX, GIDX, BIDX> & l, double r)
00685 {
00686     l.red() *= r;
00687     l.green() *= r;
00688     l.blue() *= r;
00689     return l;
00690 }
00691 
00692     /// componentwise scalar divide-assignment
00693 template <class V, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX>
00694 inline
00695 RGBValue<V, RIDX, GIDX, BIDX> &
00696 operator/=(RGBValue<V, RIDX, GIDX, BIDX> & l, double r)
00697 {
00698     l.red() /= r;
00699     l.green() /= r;
00700     l.blue() /= r;
00701     return l;
00702 }
00703 
00704 using VIGRA_CSTD::abs;
00705 
00706     /// component-wise absolute value
00707 template <class T, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX>
00708 inline
00709 RGBValue<T, RIDX, GIDX, BIDX>
00710 abs(RGBValue<T, RIDX, GIDX, BIDX> const & v)
00711 {
00712   return RGBValue<T, RIDX, GIDX, BIDX>(abs(v.red()), abs(v.green()), abs(v.blue()));
00713 }
00714 
00715     /// component-wise addition
00716 template <class V1, unsigned int R, unsigned int G, unsigned int B, class V2>
00717 inline
00718 typename PromoteTraits<RGBValue<V1, R, G, B>,
00719                        RGBValue<V2, R, G, B> >::Promote
00720 operator+(RGBValue<V1, R, G, B> const & r1,
00721           RGBValue<V2, R, G, B> const & r2)
00722 {
00723     typename PromoteTraits<RGBValue<V1, R, G, B>,
00724                            RGBValue<V2, R, G, B> >::Promote res(r1);
00725 
00726     res += r2;
00727 
00728     return res;
00729 }
00730 
00731     /// component-wise subtraction
00732 template <class V1, unsigned int R, unsigned int G, unsigned int B, class V2>
00733 inline
00734 typename PromoteTraits<RGBValue<V1, R, G, B>,
00735                        RGBValue<V2, R, G, B> >::Promote
00736 operator-(RGBValue<V1, R, G, B> const & r1,
00737           RGBValue<V2, R, G, B> const & r2)
00738 {
00739     typename PromoteTraits<RGBValue<V1, R, G, B>,
00740                            RGBValue<V2, R, G, B> >::Promote res(r1);
00741 
00742     res -= r2;
00743 
00744     return res;
00745 }
00746 
00747     /// component-wise multiplication
00748 template <class V1, unsigned int R, unsigned int G, unsigned int B, class V2>
00749 inline
00750 typename PromoteTraits<RGBValue<V1, R, G, B>,
00751                        RGBValue<V2, R, G, B> >::Promote
00752 operator*(RGBValue<V1, R, G, B> const & r1,
00753           RGBValue<V2, R, G, B> const & r2)
00754 {
00755     typename PromoteTraits<RGBValue<V1, R, G, B>,
00756                            RGBValue<V2, R, G, B> >::Promote res(r1);
00757 
00758     res *= r2;
00759 
00760     return res;
00761 }
00762 
00763     /// component-wise left scalar multiplication
00764 template <class V, unsigned int R, unsigned int G, unsigned int B>
00765 inline
00766 typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote
00767 operator*(double v, RGBValue<V, R, G, B> const & r)
00768 {
00769     typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote res(r);
00770 
00771     res *= v;
00772 
00773     return res;
00774 }
00775 
00776     /// component-wise right scalar multiplication
00777 template <class V, unsigned int R, unsigned int G, unsigned int B>
00778 inline
00779 typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote
00780 operator*(RGBValue<V, R, G, B> const & r, double v)
00781 {
00782     typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote res(r);
00783 
00784     res *= v;
00785 
00786     return res;
00787 }
00788 
00789     /// component-wise scalar division
00790 template <class V, unsigned int R, unsigned int G, unsigned int B>
00791 inline
00792 typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote
00793 operator/(RGBValue<V, R, G, B> const & r, double v)
00794 {
00795     typename NumericTraits<RGBValue<V, R, G, B> >::RealPromote res(r);
00796 
00797     res /= v;
00798 
00799     return res;
00800 }
00801 
00802     /// cross product
00803 template <class V1, unsigned int R, unsigned int G, unsigned int B, class V2>
00804 inline
00805 typename PromoteTraits<RGBValue<V1, R, G, B>,
00806                        RGBValue<V2, R, G, B> >::Promote
00807 cross(RGBValue<V1, R, G, B> const & r1,
00808       RGBValue<V2, R, G, B> const & r2)
00809 {
00810     typedef typename PromoteTraits<RGBValue<V1, R, G, B>,
00811                                    RGBValue<V2, R, G, B> >::Promote
00812             Res;
00813 
00814     return  Res(r1.green()*r2.blue() - r1.blue()*r2.green(),
00815                 r1.blue()*r2.red() - r1.red()*r2.blue(),
00816                 r1.red()*r2.green() - r1.green()*r2.red());
00817 }
00818 
00819     /// dot product
00820 template <class V1, unsigned int RIDX1, unsigned int GIDX1, unsigned int BIDX1,
00821           class V2, unsigned int RIDX2, unsigned int GIDX2, unsigned int BIDX2>
00822 inline
00823 typename PromoteTraits<V1, V2>::Promote
00824 dot(RGBValue<V1, RIDX1, GIDX1, BIDX1> const & r1,
00825     RGBValue<V2, RIDX2, GIDX2, BIDX2> const & r2)
00826 {
00827     return r1.red()*r2.red() + r1.green()*r2.green() + r1.blue()*r2.blue();
00828 }
00829 
00830 using VIGRA_CSTD::ceil;
00831 
00832     /** Apply ceil() function to each RGB component.
00833     */
00834 template <class V, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX>
00835 inline
00836 RGBValue<V, RIDX, GIDX, BIDX>
00837 ceil(RGBValue<V, RIDX, GIDX, BIDX> const & r)
00838 {
00839     return RGBValue<V, RIDX, GIDX, BIDX>(ceil(r.red()),
00840                                          ceil(r.green()),
00841                                          ceil(r.blue()));
00842 }
00843 
00844 using VIGRA_CSTD::floor;
00845 
00846     /** Apply floor() function to each RGB component.
00847     */
00848 template <class V, unsigned int RIDX, unsigned int GIDX, unsigned int BIDX>
00849 inline
00850 RGBValue<V, RIDX, GIDX, BIDX>
00851 floor(RGBValue<V, RIDX, GIDX, BIDX> const & r)
00852 {
00853     return RGBValue<V, RIDX, GIDX, BIDX>(floor(r.red()),
00854                                          floor(r.green()),
00855                                          floor(r.blue()));
00856 }
00857 
00858 //@}
00859 
00860 /********************************************************/
00861 /*                                                      */
00862 /*                      RGBValue-Accessors              */
00863 /*                                                      */
00864 /********************************************************/
00865 
00866 /** \addtogroup DataAccessors
00867 */
00868 //@{
00869 /** \defgroup RGBValueAccessors Accessors for RGBValue */
00870 //@{
00871     /** Encapsulate access to rgb values.
00872 
00873     <b>\#include</b> <<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.hxx</a>><br>
00874     Namespace: vigra
00875     */
00876 template <class RGBVALUE>
00877 class RGBAccessor
00878 : public VectorAccessor<RGBVALUE>
00879 {
00880   public:
00881 
00882     typedef typename RGBVALUE::value_type component_type;
00883 
00884         /** Get value of the red component
00885         */
00886     template <class RGBIterator>
00887     component_type const & red(RGBIterator const & rgb) const
00888     {
00889         return (*rgb).red();
00890     }
00891 
00892     template <class V, class RGBIterator>
00893     void setRGB(V r, V g, V b, RGBIterator const & rgb) const
00894     {
00895         (*rgb).setRGB( r, g, b );
00896     }
00897 
00898 
00899         /** Set value of the red component. The type <TT>V</TT> of the passed
00900             in <TT>value</TT> is automatically converted to <TT>component_type</TT>.
00901         */
00902     template <class V, class RGBIterator>
00903     void setRed(V value, RGBIterator const & rgb) const
00904     {
00905         (*rgb).setRed(value);
00906     }
00907 
00908         /** Get value of the red component at an offset
00909         */
00910     template <class RGBIterator, class DIFFERENCE>
00911     component_type const & red(RGBIterator const & rgb, DIFFERENCE diff) const
00912     {
00913         return rgb[diff].red();
00914     }
00915 
00916         /** Set value of the red component at an offset. The type <TT>V</TT> of the passed
00917             in <TT>value</TT> is automatically converted to <TT>component_type</TT>.
00918         */
00919     template <class V, class RGBIterator, class DIFFERENCE>
00920     void setRed(V value, RGBIterator const & rgb, DIFFERENCE diff) const
00921     {
00922         rgb[diff].setRed(value);
00923     }
00924 
00925         /** Get value of the green component
00926         */
00927     template <class RGBIterator>
00928     component_type const & green(RGBIterator const & rgb) const
00929     {
00930         return (*rgb).green();
00931     }
00932 
00933         /** Set value of the green component. The type <TT>V</TT> of the passed
00934             in <TT>value</TT> is automatically converted to <TT>component_type</TT>.
00935         */
00936     template <class V, class RGBIterator>
00937     void setGreen(V value, RGBIterator const & rgb) const
00938     {
00939         (*rgb).setGreen(value);
00940     }
00941 
00942         /** Get value of the green component at an offset
00943         */
00944     template <class RGBIterator, class DIFFERENCE>
00945     component_type const & green(RGBIterator const & rgb, DIFFERENCE d) const
00946     {
00947         return rgb[d].green();
00948     }
00949 
00950         /** Set value of the green component at an offset. The type <TT>V</TT> of the passed
00951             in <TT>value</TT> is automatically converted to <TT>component_type</TT>.
00952         */
00953     template <class V, class RGBIterator, class DIFFERENCE>
00954     void setGreen(V value, RGBIterator const & rgb, DIFFERENCE d) const
00955     {
00956         rgb[d].setGreen(value);
00957     }
00958 
00959         /** Get value of the blue component
00960         */
00961     template <class RGBIterator>
00962     component_type const & blue(RGBIterator const & rgb) const
00963     {
00964         return (*rgb).blue();
00965     }
00966 
00967         /** Set value of the blue component. The type <TT>V</TT> of the passed
00968             in <TT>value</TT> is automatically converted to <TT>component_type</TT>.
00969         */
00970     template <class V, class RGBIterator>
00971     void setBlue(V value, RGBIterator const & rgb) const
00972     {
00973         (*rgb).setBlue(value);
00974     }
00975 
00976         /** Get value of the blue component at an offset
00977         */
00978     template <class RGBIterator, class DIFFERENCE>
00979     component_type const & blue(RGBIterator const & rgb, DIFFERENCE d) const
00980     {
00981         return rgb[d].blue();
00982     }
00983 
00984         /** Set value of the blue component at an offset. The type <TT>V</TT> of the passed
00985             in <TT>value</TT> is automatically converted to <TT>component_type</TT>.
00986         */
00987     template <class V, class RGBIterator, class DIFFERENCE>
00988     void setBlue(V value, RGBIterator const & rgb, DIFFERENCE d) const
00989     {
00990         rgb[d].setBlue(value);
00991     }
00992 
00993 };
00994 
00995 
00996 /********************************************************/
00997 /*                                                      */
00998 /*                       RedAccessor                    */
00999 /*                                                      */
01000 /********************************************************/
01001 
01002     /** Encapsulate access to red band of an rgb value.
01003 
01004     <b>\#include</b> <<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.hxx</a>><br>
01005     Namespace: vigra
01006     */
01007 template <class RGBVALUE>
01008 class RedAccessor
01009 {
01010   public:
01011     typedef typename RGBVALUE::value_type value_type;
01012 
01013         /** Get value of the red component
01014         */
01015     template <class ITERATOR>
01016     value_type const & operator()(ITERATOR const & i) const {
01017         return (*i).red();
01018     }
01019 
01020         /** Get value of the red component at an offset
01021         */
01022     template <class ITERATOR, class DIFFERENCE>
01023     value_type const & operator()(ITERATOR const & i, DIFFERENCE d) const
01024     {
01025         return i[d].red();
01026     }
01027 
01028         /** Set value of the red component. The type <TT>V</TT> of the passed
01029             in <TT>value</TT> is automatically converted to <TT>value_type</TT>.
01030         */
01031     template <class V, class ITERATOR>
01032     void set(V value, ITERATOR const & i) const {
01033         (*i).setRed(value);
01034     }
01035 
01036 
01037         /** Set value of the red component at an offset. The type <TT>V</TT> of the passed
01038             in <TT>value</TT> is automatically converted to <TT>value_type</TT>.
01039         */
01040     template <class V, class ITERATOR, class DIFFERENCE>
01041     void set(V value, ITERATOR const & i, DIFFERENCE d) const
01042     {
01043         i[d].setRed(value);
01044     }
01045 };
01046 
01047 /********************************************************/
01048 /*                                                      */
01049 /*                     GreenAccessor                    */
01050 /*                                                      */
01051 /********************************************************/
01052 
01053     /** Encapsulate access to green band of an rgb value.
01054 
01055     <b>\#include</b> <<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.hxx</a>><br>
01056     Namespace: vigra
01057     */
01058 template <class RGBVALUE>
01059 class GreenAccessor
01060 {
01061   public:
01062     typedef typename RGBVALUE::value_type value_type;
01063 
01064         /** Get value of the green component
01065         */
01066     template <class ITERATOR>
01067     value_type const & operator()(ITERATOR const & i) const {
01068         return (*i).green();
01069     }
01070 
01071         /** Get value of the green component at an offset
01072         */
01073     template <class ITERATOR, class DIFFERENCE>
01074     value_type const & operator()(ITERATOR const & i, DIFFERENCE d) const
01075     {
01076         return i[d].green();
01077     }
01078 
01079         /** Set value of the green component. The type <TT>V</TT> of the passed
01080             in <TT>value</TT> is automatically converted to <TT>value_type</TT>.
01081         */
01082     template <class V, class ITERATOR>
01083     void set(V value, ITERATOR const & i) const {
01084         (*i).setGreen(value);
01085     }
01086 
01087 
01088         /** Set value of the green component at an offset. The type <TT>V</TT> of the passed
01089             in <TT>value</TT> is automatically converted to <TT>value_type</TT>.
01090         */
01091     template <class V, class ITERATOR, class DIFFERENCE>
01092     void set(V value, ITERATOR const & i, DIFFERENCE d) const
01093     {
01094         i[d].setGreen(value);
01095     }
01096 };
01097 
01098 /********************************************************/
01099 /*                                                      */
01100 /*                     BlueAccessor                     */
01101 /*                                                      */
01102 /********************************************************/
01103 
01104     /** Encapsulate access to blue band of an rgb value.
01105 
01106     <b>\#include</b> <<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.hxx</a>><br>
01107     Namespace: vigra
01108     */
01109 template <class RGBVALUE>
01110 class BlueAccessor
01111 {
01112   public:
01113     typedef typename RGBVALUE::value_type value_type;
01114 
01115         /** Get value of the blue component
01116         */
01117     template <class ITERATOR>
01118     value_type const & operator()(ITERATOR const & i) const {
01119         return (*i).blue();
01120     }
01121 
01122         /** Get value of the blue component at an offset
01123         */
01124     template <class ITERATOR, class DIFFERENCE>
01125     value_type const & operator()(ITERATOR const & i, DIFFERENCE d) const
01126     {
01127         return i[d].blue();
01128     }
01129 
01130         /** Set value of the blue component. The type <TT>V</TT> of the passed
01131             in <TT>value</TT> is automatically converted to <TT>value_type</TT>.
01132         */
01133     template <class V, class ITERATOR>
01134     void set(V value, ITERATOR const & i) const {
01135         (*i).setBlue(value);
01136     }
01137 
01138 
01139         /** Set value of the blue component at an offset. The type <TT>V</TT> of the passed
01140             in <TT>value</TT> is automatically converted to <TT>value_type</TT>.
01141         */
01142     template <class V, class ITERATOR, class DIFFERENCE>
01143     void set(V value, ITERATOR const & i, DIFFERENCE d) const
01144     {
01145         i[d].setBlue(value);
01146     }
01147 };
01148 
01149 /********************************************************/
01150 /*                                                      */
01151 /*                  RGBToGrayAccessor                   */
01152 /*                                                      */
01153 /********************************************************/
01154 
01155     /** Encapsulate access to luminance of an rgb value.
01156 
01157     <b>\#include</b> <<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.hxx</a>><br>
01158     Namespace: vigra
01159     */
01160 template <class RGBVALUE>
01161 class RGBToGrayAccessor
01162 {
01163   public:
01164     typedef typename RGBVALUE::value_type value_type;
01165 
01166         /** Get value of the luminance
01167         */
01168     template <class ITERATOR>
01169     value_type operator()(ITERATOR const & i) const {
01170                 return (*i).luminance(); }
01171 
01172         /** Get value of the luminance at an offset
01173         */
01174     template <class ITERATOR, class DIFFERENCE>
01175     value_type operator()(ITERATOR const & i, DIFFERENCE d) const
01176     {
01177         return i[d].luminance();
01178     }
01179 };
01180 
01181 
01182 /********************************************************/
01183 /*                                                      */
01184 /*                  GrayToRGBAccessor                   */
01185 /*                                                      */
01186 /********************************************************/
01187 
01188     /** Create an RGB view for a grayscale image by making all three channels
01189         equal.
01190 
01191     <b>\#include</b> <<a href="rgbvalue_8hxx-source.html">vigra/rgbvalue.hxx</a>><br>
01192     Namespace: vigra
01193     */
01194 template <class VALUETYPE>
01195 class GrayToRGBAccessor
01196 {
01197    public:
01198      typedef typename vigra::RGBValue<VALUETYPE> value_type;
01199 
01200          /** Get RGB value for the given pixel.
01201          */
01202      template <class ITERATOR>
01203      value_type operator()(ITERATOR const & i) const {
01204                  return value_type(*i,*i,*i); }
01205 
01206          /** Get RGB value at an offset
01207          */
01208      template <class ITERATOR, class DIFFERENCE>
01209      value_type operator()(ITERATOR const & i, DIFFERENCE d) const
01210      {
01211          return value_type(i[d],i[d],i[d]);
01212      }
01213 };
01214 
01215 
01216 //@}
01217 //@}
01218 
01219 
01220 } // namespace vigra
01221 
01222 #endif // VIGRA_RGBVALUE_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)