TuttleOFX  1
channel_algorithm.hpp
Go to the documentation of this file.
00001 /*
00002     Copyright 2005-2007 Adobe Systems Incorporated
00003    
00004     Use, modification and distribution are subject to the Boost Software License,
00005     Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
00006     http://www.boost.org/LICENSE_1_0.txt).
00007 
00008     See http://opensource.adobe.com/gil for most recent version including documentation.
00009 */
00010 /*************************************************************************************************/
00011 
00012 #ifndef GIL_CHANNEL_ALGORITHM_HPP
00013 #define GIL_CHANNEL_ALGORITHM_HPP
00014 
00015 ////////////////////////////////////////////////////////////////////////////////////////
00016 /// \file               
00017 /// \brief Channel algorithms
00018 /// \author Lubomir Bourdev and Hailin Jin \n
00019 ///         Adobe Systems Incorporated
00020 /// \date   2005-2007 \n Last updated on May 6, 2007
00021 ///
00022 /// Definitions of standard GIL 8-bit, 16-bit, 32-bit channels
00023 ///
00024 ////////////////////////////////////////////////////////////////////////////////////////
00025 
00026 #include <boost/gil/gil_config.hpp>
00027 #include <boost/gil/channel.hpp>
00028 #include <boost/mpl/less.hpp>
00029 #include <boost/mpl/integral_c.hpp>
00030 #include <boost/mpl/greater.hpp>
00031 #include <boost/type_traits.hpp>
00032 
00033 namespace boost { namespace gil {
00034 
00035 //#ifdef _MSC_VER
00036 //#pragma warning(push)
00037 //#pragma warning(disable: 4309)      // disable truncation of constant value warning (using -1 to get the max value of an integral)
00038 //#endif
00039 
00040 namespace detail {
00041 
00042 // some forward declarations
00043 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral> struct channel_converter_unsigned_impl;
00044 template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater> struct channel_converter_unsigned_integral;
00045 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible> struct channel_converter_unsigned_integral_impl;
00046 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger> struct channel_converter_unsigned_integral_nondivisible;
00047 
00048 //////////////////////////////////////
00049 ////  unsigned_integral_max_value - given an unsigned integral channel type, returns its maximum value as an MPL integral constant
00050 //////////////////////////////////////
00051 
00052 
00053 template <typename UnsignedIntegralChannel>
00054 struct unsigned_integral_max_value : public mpl::integral_c<UnsignedIntegralChannel,-1> {};
00055 
00056 template <>
00057 struct unsigned_integral_max_value<uint8_t> : public mpl::integral_c<uint32_t,0xFF> {};
00058 template <>
00059 struct unsigned_integral_max_value<uint16_t> : public mpl::integral_c<uint32_t,0xFFFF> {};
00060 template <>
00061 struct unsigned_integral_max_value<uint32_t> : public mpl::integral_c<uintmax_t,0xFFFFFFFF> {};
00062 
00063 
00064 template <int K>
00065 struct unsigned_integral_max_value<packed_channel_value<K> >
00066     : public mpl::integral_c<typename packed_channel_value<K>::integer_t, (1<<K)-1> {};
00067 
00068 //////////////////////////////////////
00069 ////  unsigned_integral_num_bits - given an unsigned integral channel type, returns the minimum number of bits needed to represent it
00070 //////////////////////////////////////
00071 
00072 template <typename UnsignedIntegralChannel>
00073 struct unsigned_integral_num_bits : public mpl::int_<sizeof(UnsignedIntegralChannel)*8> {};
00074 
00075 template <int K>
00076 struct unsigned_integral_num_bits<packed_channel_value<K> >
00077     : public mpl::int_<K> {};
00078 
00079 } // namespace detail
00080 
00081 /**
00082 \defgroup ChannelConvertAlgorithm channel_convert
00083 \brief Converting from one channel type to another
00084 \ingroup ChannelAlgorithm
00085 
00086 Conversion is done as a simple linear mapping of one channel range to the other, 
00087 such that the minimum/maximum value of the source maps to the minimum/maximum value of the destination.
00088 One implication of this is that the value 0 of signed channels may not be preserved!
00089 
00090 When creating new channel models, it is often a good idea to provide specializations for the channel conversion algorithms, for
00091 example, for performance optimizations. If the new model is an integral type that can be signed, it is easier to define the conversion 
00092 only for the unsigned type (\p channel_converter_unsigned) and provide specializations of \p detail::channel_convert_to_unsigned 
00093 and \p detail::channel_convert_from_unsigned to convert between the signed and unsigned type.
00094 
00095 Example:
00096 \code
00097 // bits32f is a floating point channel with range [0.0f ... 1.0f]
00098 bits32f src_channel = channel_traits<bits32f>::max_value();
00099 assert(src_channel == 1);
00100 
00101 // bits8 is 8-bit unsigned integral channel (typedef-ed from unsigned char)
00102 bits8 dst_channel = channel_convert<bits8>(src_channel);
00103 assert(dst_channel == 255);     // max value goes to max value
00104 \endcode
00105 */
00106 
00107 /** 
00108 \defgroup ChannelConvertUnsignedAlgorithm channel_converter_unsigned
00109 \ingroup ChannelConvertAlgorithm
00110 \brief Convert one unsigned/floating point channel to another. Converts both the channel type and range
00111  @{
00112  */
00113 
00114 //////////////////////////////////////
00115 ////  channel_converter_unsigned
00116 //////////////////////////////////////
00117 
00118 template <typename SrcChannelV, typename DstChannelV>     // Model ChannelValueConcept
00119 struct channel_converter_unsigned
00120     : public detail::channel_converter_unsigned_impl<SrcChannelV,DstChannelV,is_integral<SrcChannelV>::value,is_integral<DstChannelV>::value> {};
00121 
00122 
00123 /// \brief Converting a channel to itself - identity operation
00124 template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
00125 
00126 
00127 namespace detail {
00128 
00129 //////////////////////////////////////
00130 ////  channel_converter_unsigned_impl
00131 //////////////////////////////////////
00132 
00133 /// \brief This is the default implementation. Performance specializatons are provided
00134 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral> 
00135 struct channel_converter_unsigned_impl : public std::unary_function<DstChannelV,SrcChannelV> {
00136     DstChannelV operator()(SrcChannelV src) const { 
00137         return DstChannelV(channel_traits<DstChannelV>::min_value() +
00138             (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>()); 
00139     }
00140 private:
00141     template <typename C>
00142     static double channel_range() {
00143         return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
00144     }
00145 };
00146 
00147 // When both the source and the destination are integral channels, perform a faster conversion
00148 template <typename SrcChannelV, typename DstChannelV> 
00149 struct channel_converter_unsigned_impl<SrcChannelV,DstChannelV,true,true>
00150     : public channel_converter_unsigned_integral<SrcChannelV,DstChannelV,
00151     mpl::less<unsigned_integral_max_value<SrcChannelV>,unsigned_integral_max_value<DstChannelV> >::value > {};
00152 
00153 
00154 //////////////////////////////////////
00155 ////  channel_converter_unsigned_integral
00156 //////////////////////////////////////
00157 
00158 template <typename SrcChannelV, typename DstChannelV> 
00159 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
00160     : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
00161     !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
00162 
00163 template <typename SrcChannelV, typename DstChannelV> 
00164 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
00165     : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
00166     !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
00167 
00168 
00169 //////////////////////////////////////
00170 ////  channel_converter_unsigned_integral_impl
00171 //////////////////////////////////////
00172 
00173 // Both source and destination are unsigned integral channels, 
00174 // the src max value is less than the dst max value,
00175 // and the dst max value is divisible by the src max value
00176 template <typename SrcChannelV, typename DstChannelV> 
00177 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
00178     DstChannelV operator()(SrcChannelV src) const { 
00179         typedef typename unsigned_integral_max_value<DstChannelV>::value_type integer_t;
00180         static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
00181         return DstChannelV(src * mul);
00182     }
00183 };
00184 
00185 // Both source and destination are unsigned integral channels, 
00186 // the dst max value is less than (or equal to) the src max value,
00187 // and the src max value is divisible by the dst max value
00188 template <typename SrcChannelV, typename DstChannelV> 
00189 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
00190     DstChannelV operator()(SrcChannelV src) const { 
00191         typedef typename unsigned_integral_max_value<SrcChannelV>::value_type integer_t;
00192         static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
00193         static const integer_t div2 = div/2;
00194         return DstChannelV((src + div2) / div);
00195     }
00196 };
00197 
00198 // Prevent overflow for the largest integral type
00199 template <typename DstChannelV> 
00200 struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
00201     DstChannelV operator()(uintmax_t src) const { 
00202         static const uintmax_t div = unsigned_integral_max_value<bits32>::value / unsigned_integral_max_value<DstChannelV>::value;
00203         static const uintmax_t div2 = div/2;
00204         if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
00205             return unsigned_integral_max_value<DstChannelV>::value;
00206         return DstChannelV((src + div2) / div);
00207     }
00208 };
00209 
00210 // Both source and destination are unsigned integral channels, 
00211 // and the dst max value is not divisible by the src max value
00212 // See if you can represent the expression (src * dst_max) / src_max in integral form
00213 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst> 
00214 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,SrcLessThanDst,false> 
00215     : public channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,SrcLessThanDst,
00216     mpl::greater<
00217         mpl::plus<unsigned_integral_num_bits<SrcChannelV>,unsigned_integral_num_bits<DstChannelV> >,
00218         unsigned_integral_num_bits<uintmax_t>
00219     >::value> {};
00220 
00221 
00222 // Both source and destination are unsigned integral channels, 
00223 // the src max value is less than the dst max value,
00224 // and the dst max value is not divisible by the src max value
00225 // The expression (src * dst_max) / src_max fits in an integer
00226 template <typename SrcChannelV, typename DstChannelV> 
00227 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,false> {
00228     DstChannelV operator()(SrcChannelV src) const {
00229         typedef typename detail::min_fast_uint<unsigned_integral_num_bits<SrcChannelV>::value+unsigned_integral_num_bits<DstChannelV>::value>::type integer_t;
00230         return DstChannelV(integer_t(src * unsigned_integral_max_value<DstChannelV>::value) / unsigned_integral_max_value<SrcChannelV>::value);
00231     }
00232 };
00233 
00234 // Both source and destination are unsigned integral channels, 
00235 // the src max value is less than the dst max value,
00236 // and the dst max value is not divisible by the src max value
00237 // The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
00238 template <typename SrcChannelV, typename DstChannelV> 
00239 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,true> {
00240     DstChannelV operator()(SrcChannelV src) const {
00241         static const double mul = unsigned_integral_max_value<DstChannelV>::value / double(unsigned_integral_max_value<SrcChannelV>::value);
00242         return DstChannelV(src * mul);
00243     }
00244 };
00245 
00246 // Both source and destination are unsigned integral channels, 
00247 // the dst max value is less than (or equal to) the src max value,
00248 // and the src max value is not divisible by the dst max value
00249 template <typename SrcChannelV, typename DstChannelV, bool CannotFit> 
00250 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit> {
00251     DstChannelV operator()(SrcChannelV src) const { 
00252 
00253         typedef typename detail::unsigned_integral_max_value< SrcChannelV >::value_type src_integer_t;
00254         typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
00255 
00256         static const double div = unsigned_integral_max_value<SrcChannelV>::value 
00257                                 / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
00258 
00259         static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
00260 
00261         return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
00262     }
00263 };
00264 
00265 } // namespace detail
00266 
00267 /////////////////////////////////////////////////////
00268 ///  bits32f conversion
00269 /////////////////////////////////////////////////////
00270 
00271 template <typename DstChannelV> struct channel_converter_unsigned<bits32f,DstChannelV> : public std::unary_function<bits32f,DstChannelV> {
00272     DstChannelV operator()(bits32f x) const
00273     {
00274         typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
00275         
00276         const bits32f convertedValue = x * channel_traits<DstChannelV>::max_value() + 0.5f;
00277         const bits32f clampedValue = std::min(
00278                 (bits32f)channel_traits<DstChannelV>::max_value(),
00279                 std::max( (bits32f)channel_traits<DstChannelV>::min_value(), convertedValue ) );
00280         
00281         return DstChannelV( static_cast< dst_integer_t >(clampedValue) );
00282     }
00283 };
00284 
00285 template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,bits32f> : public std::unary_function<SrcChannelV,bits32f> {
00286     bits32f operator()(SrcChannelV   x) const { return bits32f(x/float(channel_traits<SrcChannelV>::max_value())); }
00287 };
00288 
00289 template <> struct channel_converter_unsigned<bits32f,bits32f> : public std::unary_function<bits32f,bits32f> {
00290     bits32f operator()(bits32f   x) const { return x; }
00291 };
00292 
00293 
00294 /// \brief 32 bit <-> float channel conversion
00295 template <> struct channel_converter_unsigned<bits32,bits32f> : public std::unary_function<bits32,bits32f> {
00296     bits32f operator()(bits32 x) const { 
00297         // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of bits32 matches max_value of bits32f
00298         if (x>=channel_traits<bits32>::max_value()) return channel_traits<bits32f>::max_value();
00299         return float(x) / float(channel_traits<bits32>::max_value());
00300     }
00301 };
00302 /// \brief 32 bit <-> float channel conversion
00303 template <> struct channel_converter_unsigned<bits32f,bits32> : public std::unary_function<bits32f,bits32> {
00304     bits32 operator()(bits32f x) const { 
00305         // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of bits32 matches max_value of bits32f
00306         if (x>=channel_traits<bits32f>::max_value()) return channel_traits<bits32>::max_value();
00307         return bits32(x * channel_traits<bits32>::max_value() + 0.5f); 
00308     }
00309 };
00310 
00311 /// @} 
00312 
00313 namespace detail {
00314 // Converting from signed to unsigned integral channel. 
00315 // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
00316 template <typename ChannelValue>     // Model ChannelValueConcept
00317 struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
00318     typedef ChannelValue type;
00319 };
00320 
00321 template <> struct channel_convert_to_unsigned<bits8s> : public std::unary_function<bits8s,bits8> { 
00322     typedef bits8 type;
00323     type operator()(bits8s  val) const { return val+128; } 
00324 };
00325 
00326 template <> struct channel_convert_to_unsigned<bits16s> : public std::unary_function<bits16s,bits16> { 
00327     typedef bits16 type;
00328     type operator()(bits16s  val) const { return val+32768; } 
00329 };
00330 
00331 template <> struct channel_convert_to_unsigned<bits32s> : public std::unary_function<bits32s,bits32> {
00332     typedef bits32 type;
00333     type operator()(bits32s x) const { return static_cast<bits32>(x+(1<<31)); }
00334 };
00335 
00336 
00337 // Converting from unsigned to signed integral channel
00338 // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
00339 template <typename ChannelValue>     // Model ChannelValueConcept
00340 struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
00341     typedef ChannelValue type;
00342 };
00343 
00344 template <> struct channel_convert_from_unsigned<bits8s> : public std::unary_function<bits8,bits8s> { 
00345     typedef bits8s type;
00346     type  operator()(bits8  val) const { return val-128; } 
00347 };
00348 
00349 template <> struct channel_convert_from_unsigned<bits16s> : public std::unary_function<bits16,bits16s> { 
00350     typedef bits16s type;
00351     type operator()(bits16 val) const { return val-32768; } 
00352 };
00353 
00354 template <> struct channel_convert_from_unsigned<bits32s> : public std::unary_function<bits32,bits32s> {
00355     typedef bits32s type;
00356     type operator()(bits32 x) const { return static_cast<bits32s>(x-(1<<31)); }
00357 };
00358 
00359 }   // namespace detail
00360 
00361 /// \ingroup ChannelConvertAlgorithm
00362 /// \brief A unary function object converting between channel types
00363 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
00364 struct channel_converter : public std::unary_function<SrcChannelV,DstChannelV> {
00365     DstChannelV operator()(const SrcChannelV& src) const {
00366         typedef detail::channel_convert_to_unsigned<SrcChannelV> to_unsigned;
00367         typedef detail::channel_convert_from_unsigned<DstChannelV>   from_unsigned;
00368         typedef channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type> converter_unsigned;
00369         return from_unsigned()(converter_unsigned()(to_unsigned()(src))); 
00370     }
00371 };
00372 
00373 /// \ingroup ChannelConvertAlgorithm
00374 /// \brief Converting from one channel type to another.
00375 template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
00376 inline typename channel_traits<DstChannel>::value_type channel_convert(const SrcChannel& src) { 
00377     return channel_converter<typename channel_traits<SrcChannel>::value_type,
00378                              typename channel_traits<DstChannel>::value_type>()(src); 
00379 }
00380 
00381 /// \ingroup ChannelConvertAlgorithm
00382 /// \brief Same as channel_converter, except it takes the destination channel by reference, which allows 
00383 ///        us to move the templates from the class level to the method level. This is important when invoking it
00384 ///        on heterogeneous pixels.
00385 struct default_channel_converter {
00386     template <typename Ch1, typename Ch2>
00387     void operator()(const Ch1& src, Ch2& dst) const {
00388         dst=channel_convert<Ch2>(src);
00389     }
00390 };
00391 
00392 namespace detail {
00393     // fast integer division by 255
00394     inline uint32_t div255(uint32_t in) { uint32_t tmp=in+128; return (tmp + (tmp>>8))>>8; }
00395 
00396     // fast integer divison by 32768
00397     inline uint32_t div32768(uint32_t in) { return (in+16384)>>15; }
00398 }
00399 
00400 /**
00401 \defgroup ChannelMultiplyAlgorithm channel_multiply
00402 \ingroup ChannelAlgorithm
00403 \brief Multiplying unsigned channel values of the same type. Performs scaled multiplication result = a * b / max_value
00404 
00405 Example:
00406 \code
00407 bits8 x=128;
00408 bits8 y=128;
00409 bits8 mul = channel_multiply(x,y);
00410 assert(mul == 64);    // 64 = 128 * 128 / 255
00411 \endcode
00412 */
00413 /// @{
00414 
00415 /// \brief This is the default implementation. Performance specializatons are provided
00416 template <typename ChannelValue>
00417 struct channel_multiplier_unsigned : public std::binary_function<ChannelValue,ChannelValue,ChannelValue> {
00418     ChannelValue operator()(ChannelValue a, ChannelValue b) const {
00419         return ChannelValue(a / double(channel_traits<ChannelValue>::max_value()) * b);
00420     }
00421 };
00422 
00423 /// \brief Specialization of channel_multiply for 8-bit unsigned channels
00424 template<> struct channel_multiplier_unsigned<bits8> : public std::binary_function<bits8,bits8,bits8> {
00425     bits8 operator()(bits8 a, bits8 b) const { return bits8(detail::div255(uint32_t(a) * uint32_t(b))); }
00426 };
00427 
00428 /// \brief Specialization of channel_multiply for 16-bit unsigned channels
00429 template<> struct channel_multiplier_unsigned<bits16> : public std::binary_function<bits16,bits16,bits16> {
00430     bits16 operator()(bits16 a, bits16 b) const { return bits16((uint32_t(a) * uint32_t(b))/65535); }
00431 };
00432 
00433 /// \brief Specialization of channel_multiply for float 0..1 channels
00434 template<> struct channel_multiplier_unsigned<bits32f> : public std::binary_function<bits32f,bits32f,bits32f> {
00435     bits32f operator()(bits32f a, bits32f b) const { return a*b; }
00436 };
00437 
00438 /// \brief A function object to multiply two channels. result = a * b / max_value
00439 template <typename ChannelValue>
00440 struct channel_multiplier : public std::binary_function<ChannelValue, ChannelValue, ChannelValue> {
00441     ChannelValue operator()(ChannelValue a, ChannelValue b) const {
00442         typedef detail::channel_convert_to_unsigned<ChannelValue> to_unsigned;
00443         typedef detail::channel_convert_from_unsigned<ChannelValue>   from_unsigned;
00444         typedef channel_multiplier_unsigned<typename to_unsigned::result_type> multiplier_unsigned;
00445         return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b))); 
00446     }
00447 };
00448 
00449 /// \brief A function multiplying two channels. result = a * b / max_value
00450 template <typename Channel> // Models ChannelConcept (could be a channel reference)
00451 inline typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b) { 
00452     return channel_multiplier<typename channel_traits<Channel>::value_type>()(a,b);
00453 }
00454 /// @} 
00455 
00456 /**
00457 \defgroup ChannelInvertAlgorithm channel_invert
00458 \ingroup ChannelAlgorithm
00459 \brief Returns the inverse of a channel. result = max_value - x + min_value
00460 
00461 Example:
00462 \code
00463 // bits8 == uint8_t == unsigned char
00464 bits8 x=255;
00465 bits8 inv = channel_invert(x);
00466 assert(inv == 0);
00467 \endcode
00468 */
00469 
00470 /// \brief Default implementation. Provide overloads for performance
00471 /// \ingroup ChannelInvertAlgorithm channel_invert
00472 template <typename Channel> // Models ChannelConcept (could be a channel reference)
00473 inline typename channel_traits<Channel>::value_type channel_invert(Channel x) { 
00474     return channel_traits<Channel>::max_value()-x + channel_traits<Channel>::min_value(); 
00475 }
00476 
00477 //#ifdef _MSC_VER
00478 //#pragma warning(pop)
00479 //#endif
00480 
00481 } }  // namespace boost::gil
00482 
00483 #endif