123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- #ifndef BOOST_GIL_GIL_CHANNEL_ALGORITHM_HPP
- #define BOOST_GIL_GIL_CHANNEL_ALGORITHM_HPP
- #include <boost/gil/channel.hpp>
- #include <boost/gil/promote_integral.hpp>
- #include <boost/gil/typedefs.hpp>
- #include <boost/gil/detail/is_channel_integral.hpp>
- #include <boost/gil/detail/mp11.hpp>
- #include <limits>
- #include <type_traits>
- namespace boost { namespace gil {
- namespace detail {
- template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
- struct channel_converter_unsigned_impl;
- template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater>
- struct channel_converter_unsigned_integral;
- template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible>
- struct channel_converter_unsigned_integral_impl;
- template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger>
- struct channel_converter_unsigned_integral_nondivisible;
- template <typename UnsignedIntegralChannel>
- struct unsigned_integral_max_value
- : std::integral_constant
- <
- UnsignedIntegralChannel,
- (std::numeric_limits<UnsignedIntegralChannel>::max)()
- >
- {};
- template <>
- struct unsigned_integral_max_value<uint8_t>
- : std::integral_constant<uint32_t, 0xFF>
- {};
- template <>
- struct unsigned_integral_max_value<uint16_t>
- : std::integral_constant<uint32_t, 0xFFFF>
- {};
- template <>
- struct unsigned_integral_max_value<uint32_t>
- : std::integral_constant<uintmax_t, 0xFFFFFFFF>
- {};
- template <int K>
- struct unsigned_integral_max_value<packed_channel_value<K>>
- : std::integral_constant
- <
- typename packed_channel_value<K>::integer_t,
- (uint64_t(1)<<K)-1
- >
- {};
- template <typename UnsignedIntegralChannel>
- struct unsigned_integral_num_bits
- : std::integral_constant<int, static_cast<int>(sizeof(UnsignedIntegralChannel) * 8)>
- {};
- template <int K>
- struct unsigned_integral_num_bits<packed_channel_value<K>>
- : std::integral_constant<int, K>
- {};
- }
- template <typename SrcChannelV, typename DstChannelV>
- struct channel_converter_unsigned
- : detail::channel_converter_unsigned_impl
- <
- SrcChannelV,
- DstChannelV,
- detail::is_channel_integral<SrcChannelV>::value,
- detail::is_channel_integral<DstChannelV>::value
- >
- {};
- template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
- namespace detail {
- template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
- struct channel_converter_unsigned_impl {
- using argument_type = SrcChannelV;
- using result_type = DstChannelV;
- auto operator()(SrcChannelV src) const -> DstChannelV
- {
- return DstChannelV(channel_traits<DstChannelV>::min_value() +
- (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
- }
- private:
- template <typename C>
- static auto channel_range() -> double
- {
- return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
- }
- };
- template <typename SrcChannelV, typename DstChannelV>
- struct channel_converter_unsigned_impl<SrcChannelV, DstChannelV, true, true>
- : channel_converter_unsigned_integral
- <
- SrcChannelV,
- DstChannelV,
- mp11::mp_less
- <
- unsigned_integral_max_value<SrcChannelV>,
- unsigned_integral_max_value<DstChannelV>
- >::value
- >
- {};
- template <typename SrcChannelV, typename DstChannelV>
- struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
- : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
- !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
- template <typename SrcChannelV, typename DstChannelV>
- struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
- : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
- !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
- template <typename SrcChannelV, typename DstChannelV>
- struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
- auto operator()(SrcChannelV src) const -> DstChannelV
- {
- using integer_t = typename unsigned_integral_max_value<DstChannelV>::value_type;
- static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
- return DstChannelV(src * mul);
- }
- };
- template <typename SrcChannelV, typename DstChannelV>
- struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
- auto operator()(SrcChannelV src) const -> DstChannelV
- {
- using integer_t = typename unsigned_integral_max_value<SrcChannelV>::value_type;
- static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
- static const integer_t div2 = div/2;
- return DstChannelV((src + div2) / div);
- }
- };
- template <typename DstChannelV>
- struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
- auto operator()(uintmax_t src) const -> DstChannelV
- {
- static const uintmax_t div = unsigned_integral_max_value<uint32_t>::value / unsigned_integral_max_value<DstChannelV>::value;
- static const uintmax_t div2 = div/2;
- if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
- return unsigned_integral_max_value<DstChannelV>::value;
- return DstChannelV((src + div2) / div);
- }
- };
- template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
- struct channel_converter_unsigned_integral_impl<SrcChannelV, DstChannelV, SrcLessThanDst, false>
- : channel_converter_unsigned_integral_nondivisible
- <
- SrcChannelV,
- DstChannelV,
- SrcLessThanDst,
- mp11::mp_less
- <
- unsigned_integral_num_bits<uintmax_t>,
- mp11::mp_plus
- <
- unsigned_integral_num_bits<SrcChannelV>,
- unsigned_integral_num_bits<DstChannelV>
- >
- >::value
- >
- {};
- template <typename SrcChannelV, typename DstChannelV>
- struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, false>
- {
- auto operator()(SrcChannelV src) const -> DstChannelV
- {
- using dest_t = typename base_channel_type<DstChannelV>::type;
- return DstChannelV(
- static_cast<dest_t>(src * unsigned_integral_max_value<DstChannelV>::value)
- / unsigned_integral_max_value<SrcChannelV>::value);
- }
- };
- template <typename SrcChannelV, typename DstChannelV>
- struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, true>
- {
- auto operator()(SrcChannelV src) const -> DstChannelV
- {
- static const double mul
- = unsigned_integral_max_value<DstChannelV>::value
- / double(unsigned_integral_max_value<SrcChannelV>::value);
- return DstChannelV(src * mul);
- }
- };
- template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
- struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit>
- {
- auto operator()(SrcChannelV src) const -> DstChannelV
- {
- using src_integer_t = typename detail::unsigned_integral_max_value<SrcChannelV>::value_type;
- using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
- static const double div = unsigned_integral_max_value<SrcChannelV>::value
- / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
- static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
- return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
- }
- };
- }
- template <typename DstChannelV> struct channel_converter_unsigned<float32_t,DstChannelV> {
- using argument_type = float32_t;
- using result_type = DstChannelV;
- auto operator()(float32_t x) const -> DstChannelV
- {
- using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
- return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
- }
- };
- template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,float32_t> {
- using argument_type = float32_t;
- using result_type = SrcChannelV;
- auto operator()(SrcChannelV x) const -> float32_t { return float32_t(x/float(channel_traits<SrcChannelV>::max_value())); }
- };
- template <> struct channel_converter_unsigned<float32_t,float32_t> {
- using argument_type = float32_t;
- using result_type = float32_t;
- auto operator()(float32_t x) const -> float32_t { return x; }
- };
- template <> struct channel_converter_unsigned<uint32_t,float32_t> {
- using argument_type = uint32_t;
- using result_type = float32_t;
- auto operator()(uint32_t x) const -> float32_t
- {
-
- if (x>=channel_traits<uint32_t>::max_value()) return channel_traits<float32_t>::max_value();
- return float(x) / float(channel_traits<uint32_t>::max_value());
- }
- };
- template <> struct channel_converter_unsigned<float32_t,uint32_t> {
- using argument_type = float32_t;
- using result_type = uint32_t;
- auto operator()(float32_t x) const -> uint32_t
- {
-
- if (x>=channel_traits<float32_t>::max_value())
- return channel_traits<uint32_t>::max_value();
- auto const max_value = channel_traits<uint32_t>::max_value();
- auto const result = x * static_cast<float32_t::base_channel_t>(max_value) + 0.5f;
- return static_cast<uint32_t>(result);
- }
- };
- namespace detail {
- template <typename ChannelValue>
- struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
- using type = ChannelValue;
- };
- template <> struct channel_convert_to_unsigned<int8_t> {
- using argument_type = int8_t;
- using result_type = uint8_t;
- using type = uint8_t;
- type operator()(int8_t val) const {
- return static_cast<uint8_t>(static_cast<uint32_t>(val) + 128u);
- }
- };
- template <> struct channel_convert_to_unsigned<int16_t> {
- using argument_type = int16_t;
- using result_type = uint16_t;
- using type = uint16_t;
- type operator()(int16_t val) const {
- return static_cast<uint16_t>(static_cast<uint32_t>(val) + 32768u);
- }
- };
- template <> struct channel_convert_to_unsigned<int32_t> {
- using argument_type = int32_t;
- using result_type = uint32_t;
- using type = uint32_t;
- type operator()(int32_t val) const {
- return static_cast<uint32_t>(val)+(1u<<31);
- }
- };
- template <typename ChannelValue>
- struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
- using type = ChannelValue;
- };
- template <> struct channel_convert_from_unsigned<int8_t> {
- using argument_type = uint8_t;
- using result_type = int8_t;
- using type = int8_t;
- type operator()(uint8_t val) const {
- return static_cast<int8_t>(static_cast<int32_t>(val) - 128);
- }
- };
- template <> struct channel_convert_from_unsigned<int16_t> {
- using argument_type = uint16_t;
- using result_type = int16_t;
- using type = int16_t;
- type operator()(uint16_t val) const {
- return static_cast<int16_t>(static_cast<int32_t>(val) - 32768);
- }
- };
- template <> struct channel_convert_from_unsigned<int32_t> {
- using argument_type = uint32_t;
- using result_type = int32_t;
- using type = int32_t;
- type operator()(uint32_t val) const {
- return static_cast<int32_t>(val - (1u<<31));
- }
- };
- }
- template <typename SrcChannelV, typename DstChannelV>
- struct channel_converter {
- using argument_type = SrcChannelV;
- using result_type = DstChannelV;
- auto operator()(SrcChannelV const& src) const -> DstChannelV
- {
- using to_unsigned = detail::channel_convert_to_unsigned<SrcChannelV>;
- using from_unsigned = detail::channel_convert_from_unsigned<DstChannelV>;
- using converter_unsigned = channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type>;
- return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
- }
- };
- template <typename DstChannel, typename SrcChannel>
- inline auto channel_convert(SrcChannel const& src) -> typename channel_traits<DstChannel>::value_type
- {
- return channel_converter<typename channel_traits<SrcChannel>::value_type,
- typename channel_traits<DstChannel>::value_type>()(src);
- }
- struct default_channel_converter {
- template <typename Ch1, typename Ch2>
- void operator()(Ch1 const& src, Ch2& dst) const
- {
- dst=channel_convert<Ch2>(src);
- }
- };
- namespace detail
- {
-
- inline auto div255(uint32_t in) -> uint32_t
- {
- uint32_t tmp = in + 128;
- return (tmp + (tmp >> 8)) >> 8;
- }
-
- inline auto div32768(uint32_t in) -> uint32_t
- {
- return (in + 16384) >> 15;
- }
- }
- template <typename ChannelValue>
- struct channel_multiplier_unsigned {
- using first_argument_type = ChannelValue;
- using second_argument_type = ChannelValue;
- using result_type = ChannelValue;
- auto operator()(ChannelValue a, ChannelValue b) const -> ChannelValue
- {
- return ChannelValue(static_cast<typename base_channel_type<ChannelValue>::type>(a / double(channel_traits<ChannelValue>::max_value()) * b));
- }
- };
- template<> struct channel_multiplier_unsigned<uint8_t> {
- using first_argument_type = uint8_t;
- using second_argument_type = uint8_t;
- using result_type = uint8_t;
- auto operator()(uint8_t a, uint8_t b) const -> uint8_t { return uint8_t(detail::div255(uint32_t(a) * uint32_t(b))); }
- };
- template<> struct channel_multiplier_unsigned<uint16_t> {
- using first_argument_type = uint16_t;
- using second_argument_type = uint16_t;
- using result_type = uint16_t;
- auto operator()(uint16_t a, uint16_t b) const -> uint16_t { return uint16_t((uint32_t(a) * uint32_t(b))/65535); }
- };
- template<> struct channel_multiplier_unsigned<float32_t> {
- using first_argument_type = float32_t;
- using second_argument_type = float32_t;
- using result_type = float32_t;
- auto operator()(float32_t a, float32_t b) const -> float32_t { return a*b; }
- };
- template <typename ChannelValue>
- struct channel_multiplier {
- using first_argument_type = ChannelValue;
- using second_argument_type = ChannelValue;
- using result_type = ChannelValue;
- auto operator()(ChannelValue a, ChannelValue b) const -> ChannelValue
- {
- using to_unsigned = detail::channel_convert_to_unsigned<ChannelValue>;
- using from_unsigned = detail::channel_convert_from_unsigned<ChannelValue>;
- using multiplier_unsigned = channel_multiplier_unsigned<typename to_unsigned::result_type>;
- return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
- }
- };
- template <typename Channel>
- inline auto channel_multiply(Channel a, Channel b) -> typename channel_traits<Channel>::value_type
- {
- return channel_multiplier<typename channel_traits<Channel>::value_type>()(a,b);
- }
- template <typename Channel>
- inline auto channel_invert(Channel x) -> typename channel_traits<Channel>::value_type
- {
- using base_t = typename base_channel_type<Channel>::type;
- using promoted_t = typename promote_integral<base_t>::type;
- promoted_t const promoted_x = x;
- promoted_t const promoted_max = channel_traits<Channel>::max_value();
- promoted_t const promoted_min = channel_traits<Channel>::min_value();
- promoted_t const promoted_inverted_x = promoted_max - promoted_x + promoted_min;
- auto const inverted_x = static_cast<base_t>(promoted_inverted_x);
- return inverted_x;
- }
- }}
- #endif
|