Chris@16: /* Chris@16: Copyright 2005-2007 Adobe Systems Incorporated Chris@16: Chris@16: Use, modification and distribution are subject to the Boost Software License, Chris@16: Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: http://www.boost.org/LICENSE_1_0.txt). Chris@16: Chris@16: See http://opensource.adobe.com/gil for most recent version including documentation. Chris@16: */ Chris@16: /*************************************************************************************************/ Chris@16: Chris@16: #ifndef GIL_CHANNEL_ALGORITHM_HPP Chris@16: #define GIL_CHANNEL_ALGORITHM_HPP Chris@16: Chris@16: //////////////////////////////////////////////////////////////////////////////////////// Chris@16: /// \file Chris@16: /// \brief Channel algorithms Chris@16: /// \author Lubomir Bourdev and Hailin Jin \n Chris@16: /// Adobe Systems Incorporated Chris@16: /// \date 2005-2007 \n Last updated on May 6, 2007 Chris@16: /// Chris@16: /// Definitions of standard GIL 8-bit, 16-bit, 32-bit channels Chris@16: /// Chris@16: //////////////////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: #include "gil_config.hpp" Chris@16: #include "channel.hpp" Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { namespace gil { Chris@16: Chris@16: //#ifdef _MSC_VER Chris@16: //#pragma warning(push) Chris@16: //#pragma warning(disable: 4309) // disable truncation of constant value warning (using -1 to get the max value of an integral) Chris@16: //#endif Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: // some forward declarations Chris@16: template struct channel_converter_unsigned_impl; Chris@16: template struct channel_converter_unsigned_integral; Chris@16: template struct channel_converter_unsigned_integral_impl; Chris@16: template struct channel_converter_unsigned_integral_nondivisible; Chris@16: Chris@16: ////////////////////////////////////// Chris@16: //// unsigned_integral_max_value - given an unsigned integral channel type, returns its maximum value as an MPL integral constant Chris@16: ////////////////////////////////////// Chris@16: Chris@16: Chris@16: template Chris@16: struct unsigned_integral_max_value : public mpl::integral_c {}; Chris@16: Chris@16: template <> Chris@16: struct unsigned_integral_max_value : public mpl::integral_c {}; Chris@16: template <> Chris@16: struct unsigned_integral_max_value : public mpl::integral_c {}; Chris@16: template <> Chris@16: struct unsigned_integral_max_value : public mpl::integral_c {}; Chris@16: Chris@16: Chris@16: template Chris@16: struct unsigned_integral_max_value > Chris@16: : public mpl::integral_c::integer_t, (1< {}; Chris@16: Chris@16: ////////////////////////////////////// Chris@16: //// unsigned_integral_num_bits - given an unsigned integral channel type, returns the minimum number of bits needed to represent it Chris@16: ////////////////////////////////////// Chris@16: Chris@16: template Chris@16: struct unsigned_integral_num_bits : public mpl::int_ {}; Chris@16: Chris@16: template Chris@16: struct unsigned_integral_num_bits > Chris@16: : public mpl::int_ {}; Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: /** Chris@16: \defgroup ChannelConvertAlgorithm channel_convert Chris@16: \brief Converting from one channel type to another Chris@16: \ingroup ChannelAlgorithm Chris@16: Chris@16: Conversion is done as a simple linear mapping of one channel range to the other, Chris@16: such that the minimum/maximum value of the source maps to the minimum/maximum value of the destination. Chris@16: One implication of this is that the value 0 of signed channels may not be preserved! Chris@16: Chris@16: When creating new channel models, it is often a good idea to provide specializations for the channel conversion algorithms, for Chris@16: example, for performance optimizations. If the new model is an integral type that can be signed, it is easier to define the conversion Chris@16: only for the unsigned type (\p channel_converter_unsigned) and provide specializations of \p detail::channel_convert_to_unsigned Chris@16: and \p detail::channel_convert_from_unsigned to convert between the signed and unsigned type. Chris@16: Chris@16: Example: Chris@16: \code Chris@16: // bits32f is a floating point channel with range [0.0f ... 1.0f] Chris@16: bits32f src_channel = channel_traits::max_value(); Chris@16: assert(src_channel == 1); Chris@16: Chris@16: // bits8 is 8-bit unsigned integral channel (typedef-ed from unsigned char) Chris@16: bits8 dst_channel = channel_convert(src_channel); Chris@16: assert(dst_channel == 255); // max value goes to max value Chris@16: \endcode Chris@16: */ Chris@16: Chris@16: /** Chris@16: \defgroup ChannelConvertUnsignedAlgorithm channel_converter_unsigned Chris@16: \ingroup ChannelConvertAlgorithm Chris@16: \brief Convert one unsigned/floating point channel to another. Converts both the channel type and range Chris@16: @{ Chris@16: */ Chris@16: Chris@16: ////////////////////////////////////// Chris@16: //// channel_converter_unsigned Chris@16: ////////////////////////////////////// Chris@16: Chris@16: template // Model ChannelValueConcept Chris@16: struct channel_converter_unsigned Chris@16: : public detail::channel_converter_unsigned_impl::value,is_integral::value> {}; Chris@16: Chris@16: Chris@16: /// \brief Converting a channel to itself - identity operation Chris@16: template struct channel_converter_unsigned : public detail::identity {}; Chris@16: Chris@16: Chris@16: namespace detail { Chris@16: Chris@16: ////////////////////////////////////// Chris@16: //// channel_converter_unsigned_impl Chris@16: ////////////////////////////////////// Chris@16: Chris@16: /// \brief This is the default implementation. Performance specializatons are provided Chris@16: template Chris@16: struct channel_converter_unsigned_impl : public std::unary_function { Chris@16: DstChannelV operator()(SrcChannelV src) const { Chris@16: return DstChannelV(channel_traits::min_value() + Chris@16: (src - channel_traits::min_value()) / channel_range() * channel_range()); Chris@16: } Chris@16: private: Chris@16: template Chris@16: static double channel_range() { Chris@16: return double(channel_traits::max_value()) - double(channel_traits::min_value()); Chris@16: } Chris@16: }; Chris@16: Chris@16: // When both the source and the destination are integral channels, perform a faster conversion Chris@16: template Chris@16: struct channel_converter_unsigned_impl Chris@16: : public channel_converter_unsigned_integral,unsigned_integral_max_value >::value > {}; Chris@16: Chris@16: Chris@16: ////////////////////////////////////// Chris@16: //// channel_converter_unsigned_integral Chris@16: ////////////////////////////////////// Chris@16: Chris@16: template Chris@16: struct channel_converter_unsigned_integral Chris@16: : public channel_converter_unsigned_integral_impl::value % unsigned_integral_max_value::value) > {}; Chris@16: Chris@16: template Chris@16: struct channel_converter_unsigned_integral Chris@16: : public channel_converter_unsigned_integral_impl::value % unsigned_integral_max_value::value) > {}; Chris@16: Chris@16: Chris@16: ////////////////////////////////////// Chris@16: //// channel_converter_unsigned_integral_impl Chris@16: ////////////////////////////////////// Chris@16: Chris@16: // Both source and destination are unsigned integral channels, Chris@16: // the src max value is less than the dst max value, Chris@16: // and the dst max value is divisible by the src max value Chris@16: template Chris@16: struct channel_converter_unsigned_integral_impl { Chris@16: DstChannelV operator()(SrcChannelV src) const { Chris@16: typedef typename unsigned_integral_max_value::value_type integer_t; Chris@16: static const integer_t mul = unsigned_integral_max_value::value / unsigned_integral_max_value::value; Chris@16: return DstChannelV(src * mul); Chris@16: } Chris@16: }; Chris@16: Chris@16: // Both source and destination are unsigned integral channels, Chris@16: // the dst max value is less than (or equal to) the src max value, Chris@16: // and the src max value is divisible by the dst max value Chris@16: template Chris@16: struct channel_converter_unsigned_integral_impl { Chris@16: DstChannelV operator()(SrcChannelV src) const { Chris@16: typedef typename unsigned_integral_max_value::value_type integer_t; Chris@16: static const integer_t div = unsigned_integral_max_value::value / unsigned_integral_max_value::value; Chris@16: static const integer_t div2 = div/2; Chris@16: return DstChannelV((src + div2) / div); Chris@16: } Chris@16: }; Chris@16: Chris@16: // Prevent overflow for the largest integral type Chris@16: template Chris@16: struct channel_converter_unsigned_integral_impl { Chris@16: DstChannelV operator()(uintmax_t src) const { Chris@16: static const uintmax_t div = unsigned_integral_max_value::value / unsigned_integral_max_value::value; Chris@16: static const uintmax_t div2 = div/2; Chris@16: if (src > unsigned_integral_max_value::value - div2) Chris@16: return unsigned_integral_max_value::value; Chris@16: return DstChannelV((src + div2) / div); Chris@16: } Chris@16: }; Chris@16: Chris@16: // Both source and destination are unsigned integral channels, Chris@16: // and the dst max value is not divisible by the src max value Chris@16: // See if you can represent the expression (src * dst_max) / src_max in integral form Chris@16: template Chris@16: struct channel_converter_unsigned_integral_impl Chris@16: : public channel_converter_unsigned_integral_nondivisible,unsigned_integral_num_bits >, Chris@16: unsigned_integral_num_bits Chris@16: >::value> {}; Chris@16: Chris@16: Chris@16: // Both source and destination are unsigned integral channels, Chris@16: // the src max value is less than the dst max value, Chris@16: // and the dst max value is not divisible by the src max value Chris@16: // The expression (src * dst_max) / src_max fits in an integer Chris@16: template Chris@16: struct channel_converter_unsigned_integral_nondivisible { Chris@16: DstChannelV operator()(SrcChannelV src) const { Chris@16: typedef typename detail::min_fast_uint::value+unsigned_integral_num_bits::value>::type integer_t; Chris@16: return DstChannelV(integer_t(src * unsigned_integral_max_value::value) / unsigned_integral_max_value::value); Chris@16: } Chris@16: }; Chris@16: Chris@16: // Both source and destination are unsigned integral channels, Chris@16: // the src max value is less than the dst max value, Chris@16: // and the dst max value is not divisible by the src max value Chris@16: // The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double Chris@16: template Chris@16: struct channel_converter_unsigned_integral_nondivisible { Chris@16: DstChannelV operator()(SrcChannelV src) const { Chris@16: static const double mul = unsigned_integral_max_value::value / double(unsigned_integral_max_value::value); Chris@16: return DstChannelV(src * mul); Chris@16: } Chris@16: }; Chris@16: Chris@16: // Both source and destination are unsigned integral channels, Chris@16: // the dst max value is less than (or equal to) the src max value, Chris@16: // and the src max value is not divisible by the dst max value Chris@16: template Chris@16: struct channel_converter_unsigned_integral_nondivisible { Chris@16: DstChannelV operator()(SrcChannelV src) const { Chris@16: Chris@16: typedef typename detail::unsigned_integral_max_value< SrcChannelV >::value_type src_integer_t; Chris@16: typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t; Chris@16: Chris@16: static const double div = unsigned_integral_max_value::value Chris@16: / static_cast< double >( unsigned_integral_max_value::value ); Chris@16: Chris@16: static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 ); Chris@16: Chris@16: return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div ))); Chris@16: } Chris@16: }; Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: ///////////////////////////////////////////////////// Chris@16: /// bits32f conversion Chris@16: ///////////////////////////////////////////////////// Chris@16: Chris@16: template struct channel_converter_unsigned : public std::unary_function { Chris@16: DstChannelV operator()(bits32f x) const Chris@16: { Chris@16: typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t; Chris@16: return DstChannelV( static_cast< dst_integer_t >(x*channel_traits::max_value()+0.5f )); Chris@16: } Chris@16: }; Chris@16: Chris@16: template struct channel_converter_unsigned : public std::unary_function { Chris@16: bits32f operator()(SrcChannelV x) const { return bits32f(x/float(channel_traits::max_value())); } Chris@16: }; Chris@16: Chris@16: template <> struct channel_converter_unsigned : public std::unary_function { Chris@16: bits32f operator()(bits32f x) const { return x; } Chris@16: }; Chris@16: Chris@16: Chris@16: /// \brief 32 bit <-> float channel conversion Chris@16: template <> struct channel_converter_unsigned : public std::unary_function { Chris@16: bits32f operator()(bits32 x) const { Chris@16: // 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 Chris@16: if (x>=channel_traits::max_value()) return channel_traits::max_value(); Chris@16: return float(x) / float(channel_traits::max_value()); Chris@16: } Chris@16: }; Chris@16: /// \brief 32 bit <-> float channel conversion Chris@16: template <> struct channel_converter_unsigned : public std::unary_function { Chris@16: bits32 operator()(bits32f x) const { Chris@16: // 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 Chris@16: if (x>=channel_traits::max_value()) return channel_traits::max_value(); Chris@16: return bits32(x * channel_traits::max_value() + 0.5f); Chris@16: } Chris@16: }; Chris@16: Chris@16: /// @} Chris@16: Chris@16: namespace detail { Chris@16: // Converting from signed to unsigned integral channel. Chris@16: // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type) Chris@16: template // Model ChannelValueConcept Chris@16: struct channel_convert_to_unsigned : public detail::identity { Chris@16: typedef ChannelValue type; Chris@16: }; Chris@16: Chris@16: template <> struct channel_convert_to_unsigned : public std::unary_function { Chris@16: typedef bits8 type; Chris@16: type operator()(bits8s val) const { return val+128; } Chris@16: }; Chris@16: Chris@16: template <> struct channel_convert_to_unsigned : public std::unary_function { Chris@16: typedef bits16 type; Chris@16: type operator()(bits16s val) const { return val+32768; } Chris@16: }; Chris@16: Chris@16: template <> struct channel_convert_to_unsigned : public std::unary_function { Chris@16: typedef bits32 type; Chris@16: type operator()(bits32s x) const { return static_cast(x+(1<<31)); } Chris@16: }; Chris@16: Chris@16: Chris@16: // Converting from unsigned to signed integral channel Chris@16: // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type) Chris@16: template // Model ChannelValueConcept Chris@16: struct channel_convert_from_unsigned : public detail::identity { Chris@16: typedef ChannelValue type; Chris@16: }; Chris@16: Chris@16: template <> struct channel_convert_from_unsigned : public std::unary_function { Chris@16: typedef bits8s type; Chris@16: type operator()(bits8 val) const { return val-128; } Chris@16: }; Chris@16: Chris@16: template <> struct channel_convert_from_unsigned : public std::unary_function { Chris@16: typedef bits16s type; Chris@16: type operator()(bits16 val) const { return val-32768; } Chris@16: }; Chris@16: Chris@16: template <> struct channel_convert_from_unsigned : public std::unary_function { Chris@16: typedef bits32s type; Chris@16: type operator()(bits32 x) const { return static_cast(x-(1<<31)); } Chris@16: }; Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: /// \ingroup ChannelConvertAlgorithm Chris@16: /// \brief A unary function object converting between channel types Chris@16: template // Model ChannelValueConcept Chris@16: struct channel_converter : public std::unary_function { Chris@16: DstChannelV operator()(const SrcChannelV& src) const { Chris@16: typedef detail::channel_convert_to_unsigned to_unsigned; Chris@16: typedef detail::channel_convert_from_unsigned from_unsigned; Chris@16: typedef channel_converter_unsigned converter_unsigned; Chris@16: return from_unsigned()(converter_unsigned()(to_unsigned()(src))); Chris@16: } Chris@16: }; Chris@16: Chris@16: /// \ingroup ChannelConvertAlgorithm Chris@16: /// \brief Converting from one channel type to another. Chris@16: template // Model ChannelConcept (could be channel references) Chris@16: inline typename channel_traits::value_type channel_convert(const SrcChannel& src) { Chris@16: return channel_converter::value_type, Chris@16: typename channel_traits::value_type>()(src); Chris@16: } Chris@16: Chris@16: /// \ingroup ChannelConvertAlgorithm Chris@16: /// \brief Same as channel_converter, except it takes the destination channel by reference, which allows Chris@16: /// us to move the templates from the class level to the method level. This is important when invoking it Chris@16: /// on heterogeneous pixels. Chris@16: struct default_channel_converter { Chris@16: template Chris@16: void operator()(const Ch1& src, Ch2& dst) const { Chris@16: dst=channel_convert(src); Chris@16: } Chris@16: }; Chris@16: Chris@16: namespace detail { Chris@16: // fast integer division by 255 Chris@16: inline uint32_t div255(uint32_t in) { uint32_t tmp=in+128; return (tmp + (tmp>>8))>>8; } Chris@16: Chris@16: // fast integer divison by 32768 Chris@16: inline uint32_t div32768(uint32_t in) { return (in+16384)>>15; } Chris@16: } Chris@16: Chris@16: /** Chris@16: \defgroup ChannelMultiplyAlgorithm channel_multiply Chris@16: \ingroup ChannelAlgorithm Chris@16: \brief Multiplying unsigned channel values of the same type. Performs scaled multiplication result = a * b / max_value Chris@16: Chris@16: Example: Chris@16: \code Chris@16: bits8 x=128; Chris@16: bits8 y=128; Chris@16: bits8 mul = channel_multiply(x,y); Chris@16: assert(mul == 64); // 64 = 128 * 128 / 255 Chris@16: \endcode Chris@16: */ Chris@16: /// @{ Chris@16: Chris@16: /// \brief This is the default implementation. Performance specializatons are provided Chris@16: template Chris@16: struct channel_multiplier_unsigned : public std::binary_function { Chris@16: ChannelValue operator()(ChannelValue a, ChannelValue b) const { Chris@16: return ChannelValue(a / double(channel_traits::max_value()) * b); Chris@16: } Chris@16: }; Chris@16: Chris@16: /// \brief Specialization of channel_multiply for 8-bit unsigned channels Chris@16: template<> struct channel_multiplier_unsigned : public std::binary_function { Chris@16: bits8 operator()(bits8 a, bits8 b) const { return bits8(detail::div255(uint32_t(a) * uint32_t(b))); } Chris@16: }; Chris@16: Chris@16: /// \brief Specialization of channel_multiply for 16-bit unsigned channels Chris@16: template<> struct channel_multiplier_unsigned : public std::binary_function { Chris@16: bits16 operator()(bits16 a, bits16 b) const { return bits16((uint32_t(a) * uint32_t(b))/65535); } Chris@16: }; Chris@16: Chris@16: /// \brief Specialization of channel_multiply for float 0..1 channels Chris@16: template<> struct channel_multiplier_unsigned : public std::binary_function { Chris@16: bits32f operator()(bits32f a, bits32f b) const { return a*b; } Chris@16: }; Chris@16: Chris@16: /// \brief A function object to multiply two channels. result = a * b / max_value Chris@16: template Chris@16: struct channel_multiplier : public std::binary_function { Chris@16: ChannelValue operator()(ChannelValue a, ChannelValue b) const { Chris@16: typedef detail::channel_convert_to_unsigned to_unsigned; Chris@16: typedef detail::channel_convert_from_unsigned from_unsigned; Chris@16: typedef channel_multiplier_unsigned multiplier_unsigned; Chris@16: return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b))); Chris@16: } Chris@16: }; Chris@16: Chris@16: /// \brief A function multiplying two channels. result = a * b / max_value Chris@16: template // Models ChannelConcept (could be a channel reference) Chris@16: inline typename channel_traits::value_type channel_multiply(Channel a, Channel b) { Chris@16: return channel_multiplier::value_type>()(a,b); Chris@16: } Chris@16: /// @} Chris@16: Chris@16: /** Chris@16: \defgroup ChannelInvertAlgorithm channel_invert Chris@16: \ingroup ChannelAlgorithm Chris@16: \brief Returns the inverse of a channel. result = max_value - x + min_value Chris@16: Chris@16: Example: Chris@16: \code Chris@16: // bits8 == uint8_t == unsigned char Chris@16: bits8 x=255; Chris@16: bits8 inv = channel_invert(x); Chris@16: assert(inv == 0); Chris@16: \endcode Chris@16: */ Chris@16: Chris@16: /// \brief Default implementation. Provide overloads for performance Chris@16: /// \ingroup ChannelInvertAlgorithm channel_invert Chris@16: template // Models ChannelConcept (could be a channel reference) Chris@16: inline typename channel_traits::value_type channel_invert(Channel x) { Chris@16: return channel_traits::max_value()-x + channel_traits::min_value(); Chris@16: } Chris@16: Chris@16: //#ifdef _MSC_VER Chris@16: //#pragma warning(pop) Chris@16: //#endif Chris@16: Chris@16: } } // namespace boost::gil Chris@16: Chris@16: #endif