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