channel_algorithm.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. #ifndef BOOST_GIL_GIL_CHANNEL_ALGORITHM_HPP
  9. #define BOOST_GIL_GIL_CHANNEL_ALGORITHM_HPP
  10. #include <boost/gil/channel.hpp>
  11. #include <boost/gil/promote_integral.hpp>
  12. #include <boost/gil/typedefs.hpp>
  13. #include <boost/gil/detail/is_channel_integral.hpp>
  14. #include <boost/gil/detail/mp11.hpp>
  15. #include <limits>
  16. #include <type_traits>
  17. namespace boost { namespace gil {
  18. namespace detail {
  19. // some forward declarations
  20. template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
  21. struct channel_converter_unsigned_impl;
  22. template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater>
  23. struct channel_converter_unsigned_integral;
  24. template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible>
  25. struct channel_converter_unsigned_integral_impl;
  26. template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger>
  27. struct channel_converter_unsigned_integral_nondivisible;
  28. //////////////////////////////////////
  29. //// unsigned_integral_max_value - given an unsigned integral channel type,
  30. //// returns its maximum value as an integral constant
  31. //////////////////////////////////////
  32. template <typename UnsignedIntegralChannel>
  33. struct unsigned_integral_max_value
  34. : std::integral_constant
  35. <
  36. UnsignedIntegralChannel,
  37. (std::numeric_limits<UnsignedIntegralChannel>::max)()
  38. >
  39. {};
  40. template <>
  41. struct unsigned_integral_max_value<uint8_t>
  42. : std::integral_constant<uint32_t, 0xFF>
  43. {};
  44. template <>
  45. struct unsigned_integral_max_value<uint16_t>
  46. : std::integral_constant<uint32_t, 0xFFFF>
  47. {};
  48. template <>
  49. struct unsigned_integral_max_value<uint32_t>
  50. : std::integral_constant<uintmax_t, 0xFFFFFFFF>
  51. {};
  52. template <int K>
  53. struct unsigned_integral_max_value<packed_channel_value<K>>
  54. : std::integral_constant
  55. <
  56. typename packed_channel_value<K>::integer_t,
  57. (uint64_t(1)<<K)-1
  58. >
  59. {};
  60. //////////////////////////////////////
  61. //// unsigned_integral_num_bits - given an unsigned integral channel type,
  62. //// returns the minimum number of bits needed to represent it
  63. //////////////////////////////////////
  64. template <typename UnsignedIntegralChannel>
  65. struct unsigned_integral_num_bits
  66. : std::integral_constant<int, static_cast<int>(sizeof(UnsignedIntegralChannel) * 8)>
  67. {};
  68. template <int K>
  69. struct unsigned_integral_num_bits<packed_channel_value<K>>
  70. : std::integral_constant<int, K>
  71. {};
  72. } // namespace detail
  73. /// \defgroup ChannelConvertAlgorithm channel_convert
  74. /// \brief Converting from one channel type to another
  75. /// \ingroup ChannelAlgorithm
  76. ///
  77. /// Conversion is done as a simple linear mapping of one channel range to the other,
  78. /// such that the minimum/maximum value of the source maps to the minimum/maximum value of the destination.
  79. /// One implication of this is that the value 0 of signed channels may not be preserved!
  80. ///
  81. /// When creating new channel models, it is often a good idea to provide specializations for the channel conversion algorithms, for
  82. /// example, for performance optimizations. If the new model is an integral type that can be signed, it is easier to define the conversion
  83. /// only for the unsigned type (\p channel_converter_unsigned) and provide specializations of \p detail::channel_convert_to_unsigned
  84. /// and \p detail::channel_convert_from_unsigned to convert between the signed and unsigned type.
  85. ///
  86. /// Example:
  87. /// \code
  88. /// // float32_t is a floating point channel with range [0.0f ... 1.0f]
  89. /// float32_t src_channel = channel_traits<float32_t>::max_value();
  90. /// assert(src_channel == 1);
  91. ///
  92. /// // uint8_t is 8-bit unsigned integral channel (aliased from unsigned char)
  93. /// uint8_t dst_channel = channel_convert<uint8_t>(src_channel);
  94. /// assert(dst_channel == 255); // max value goes to max value
  95. /// \endcode
  96. ///
  97. /// \defgroup ChannelConvertUnsignedAlgorithm channel_converter_unsigned
  98. /// \ingroup ChannelConvertAlgorithm
  99. /// \brief Convert one unsigned/floating point channel to another. Converts both the channel type and range
  100. /// @{
  101. //////////////////////////////////////
  102. //// channel_converter_unsigned
  103. //////////////////////////////////////
  104. template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
  105. struct channel_converter_unsigned
  106. : detail::channel_converter_unsigned_impl
  107. <
  108. SrcChannelV,
  109. DstChannelV,
  110. detail::is_channel_integral<SrcChannelV>::value,
  111. detail::is_channel_integral<DstChannelV>::value
  112. >
  113. {};
  114. /// \brief Converting a channel to itself - identity operation
  115. template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
  116. namespace detail {
  117. //////////////////////////////////////
  118. //// channel_converter_unsigned_impl
  119. //////////////////////////////////////
  120. /// \brief This is the default implementation. Performance specializatons are provided
  121. template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
  122. struct channel_converter_unsigned_impl {
  123. using argument_type = SrcChannelV;
  124. using result_type = DstChannelV;
  125. auto operator()(SrcChannelV src) const -> DstChannelV
  126. {
  127. return DstChannelV(channel_traits<DstChannelV>::min_value() +
  128. (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
  129. }
  130. private:
  131. template <typename C>
  132. static auto channel_range() -> double
  133. {
  134. return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
  135. }
  136. };
  137. // When both the source and the destination are integral channels, perform a faster conversion
  138. template <typename SrcChannelV, typename DstChannelV>
  139. struct channel_converter_unsigned_impl<SrcChannelV, DstChannelV, true, true>
  140. : channel_converter_unsigned_integral
  141. <
  142. SrcChannelV,
  143. DstChannelV,
  144. mp11::mp_less
  145. <
  146. unsigned_integral_max_value<SrcChannelV>,
  147. unsigned_integral_max_value<DstChannelV>
  148. >::value
  149. >
  150. {};
  151. //////////////////////////////////////
  152. //// channel_converter_unsigned_integral
  153. //////////////////////////////////////
  154. template <typename SrcChannelV, typename DstChannelV>
  155. struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
  156. : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
  157. !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
  158. template <typename SrcChannelV, typename DstChannelV>
  159. struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
  160. : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
  161. !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
  162. //////////////////////////////////////
  163. //// channel_converter_unsigned_integral_impl
  164. //////////////////////////////////////
  165. // Both source and destination are unsigned integral channels,
  166. // the src max value is less than the dst max value,
  167. // and the dst max value is divisible by the src max value
  168. template <typename SrcChannelV, typename DstChannelV>
  169. struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
  170. auto operator()(SrcChannelV src) const -> DstChannelV
  171. {
  172. using integer_t = typename unsigned_integral_max_value<DstChannelV>::value_type;
  173. static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
  174. return DstChannelV(src * mul);
  175. }
  176. };
  177. // Both source and destination are unsigned integral channels,
  178. // the dst max value is less than (or equal to) the src max value,
  179. // and the src max value is divisible by the dst max value
  180. template <typename SrcChannelV, typename DstChannelV>
  181. struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
  182. auto operator()(SrcChannelV src) const -> DstChannelV
  183. {
  184. using integer_t = typename unsigned_integral_max_value<SrcChannelV>::value_type;
  185. static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
  186. static const integer_t div2 = div/2;
  187. return DstChannelV((src + div2) / div);
  188. }
  189. };
  190. // Prevent overflow for the largest integral type
  191. template <typename DstChannelV>
  192. struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
  193. auto operator()(uintmax_t src) const -> DstChannelV
  194. {
  195. static const uintmax_t div = unsigned_integral_max_value<uint32_t>::value / unsigned_integral_max_value<DstChannelV>::value;
  196. static const uintmax_t div2 = div/2;
  197. if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
  198. return unsigned_integral_max_value<DstChannelV>::value;
  199. return DstChannelV((src + div2) / div);
  200. }
  201. };
  202. // Both source and destination are unsigned integral channels,
  203. // and the dst max value is not divisible by the src max value
  204. // See if you can represent the expression (src * dst_max) / src_max in integral form
  205. template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
  206. struct channel_converter_unsigned_integral_impl<SrcChannelV, DstChannelV, SrcLessThanDst, false>
  207. : channel_converter_unsigned_integral_nondivisible
  208. <
  209. SrcChannelV,
  210. DstChannelV,
  211. SrcLessThanDst,
  212. mp11::mp_less
  213. <
  214. unsigned_integral_num_bits<uintmax_t>,
  215. mp11::mp_plus
  216. <
  217. unsigned_integral_num_bits<SrcChannelV>,
  218. unsigned_integral_num_bits<DstChannelV>
  219. >
  220. >::value
  221. >
  222. {};
  223. // Both source and destination are unsigned integral channels,
  224. // the src max value is less than the dst max value,
  225. // and the dst max value is not divisible by the src max value
  226. // The expression (src * dst_max) / src_max fits in an integer
  227. template <typename SrcChannelV, typename DstChannelV>
  228. struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, false>
  229. {
  230. auto operator()(SrcChannelV src) const -> DstChannelV
  231. {
  232. using dest_t = typename base_channel_type<DstChannelV>::type;
  233. return DstChannelV(
  234. static_cast<dest_t>(src * unsigned_integral_max_value<DstChannelV>::value)
  235. / unsigned_integral_max_value<SrcChannelV>::value);
  236. }
  237. };
  238. // Both source and destination are unsigned integral channels,
  239. // the src max value is less than the dst max value,
  240. // and the dst max value is not divisible by the src max value
  241. // The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
  242. template <typename SrcChannelV, typename DstChannelV>
  243. struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, true>
  244. {
  245. auto operator()(SrcChannelV src) const -> DstChannelV
  246. {
  247. static const double mul
  248. = unsigned_integral_max_value<DstChannelV>::value
  249. / double(unsigned_integral_max_value<SrcChannelV>::value);
  250. return DstChannelV(src * mul);
  251. }
  252. };
  253. // Both source and destination are unsigned integral channels,
  254. // the dst max value is less than (or equal to) the src max value,
  255. // and the src max value is not divisible by the dst max value
  256. template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
  257. struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit>
  258. {
  259. auto operator()(SrcChannelV src) const -> DstChannelV
  260. {
  261. using src_integer_t = typename detail::unsigned_integral_max_value<SrcChannelV>::value_type;
  262. using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
  263. static const double div = unsigned_integral_max_value<SrcChannelV>::value
  264. / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
  265. static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
  266. return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
  267. }
  268. };
  269. } // namespace detail
  270. /////////////////////////////////////////////////////
  271. /// float32_t conversion
  272. /////////////////////////////////////////////////////
  273. template <typename DstChannelV> struct channel_converter_unsigned<float32_t,DstChannelV> {
  274. using argument_type = float32_t;
  275. using result_type = DstChannelV;
  276. auto operator()(float32_t x) const -> DstChannelV
  277. {
  278. using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
  279. return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
  280. }
  281. };
  282. template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,float32_t> {
  283. using argument_type = float32_t;
  284. using result_type = SrcChannelV;
  285. auto operator()(SrcChannelV x) const -> float32_t { return float32_t(x/float(channel_traits<SrcChannelV>::max_value())); }
  286. };
  287. template <> struct channel_converter_unsigned<float32_t,float32_t> {
  288. using argument_type = float32_t;
  289. using result_type = float32_t;
  290. auto operator()(float32_t x) const -> float32_t { return x; }
  291. };
  292. /// \brief 32 bit <-> float channel conversion
  293. template <> struct channel_converter_unsigned<uint32_t,float32_t> {
  294. using argument_type = uint32_t;
  295. using result_type = float32_t;
  296. auto operator()(uint32_t x) const -> float32_t
  297. {
  298. // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of uint32_t matches max_value of float32_t
  299. if (x>=channel_traits<uint32_t>::max_value()) return channel_traits<float32_t>::max_value();
  300. return float(x) / float(channel_traits<uint32_t>::max_value());
  301. }
  302. };
  303. /// \brief 32 bit <-> float channel conversion
  304. template <> struct channel_converter_unsigned<float32_t,uint32_t> {
  305. using argument_type = float32_t;
  306. using result_type = uint32_t;
  307. auto operator()(float32_t x) const -> uint32_t
  308. {
  309. // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of uint32_t matches max_value of float32_t
  310. if (x>=channel_traits<float32_t>::max_value())
  311. return channel_traits<uint32_t>::max_value();
  312. auto const max_value = channel_traits<uint32_t>::max_value();
  313. auto const result = x * static_cast<float32_t::base_channel_t>(max_value) + 0.5f;
  314. return static_cast<uint32_t>(result);
  315. }
  316. };
  317. /// @}
  318. namespace detail {
  319. // Converting from signed to unsigned integral channel.
  320. // It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
  321. template <typename ChannelValue> // Model ChannelValueConcept
  322. struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
  323. using type = ChannelValue;
  324. };
  325. template <> struct channel_convert_to_unsigned<int8_t> {
  326. using argument_type = int8_t;
  327. using result_type = uint8_t;
  328. using type = uint8_t;
  329. type operator()(int8_t val) const {
  330. return static_cast<uint8_t>(static_cast<uint32_t>(val) + 128u);
  331. }
  332. };
  333. template <> struct channel_convert_to_unsigned<int16_t> {
  334. using argument_type = int16_t;
  335. using result_type = uint16_t;
  336. using type = uint16_t;
  337. type operator()(int16_t val) const {
  338. return static_cast<uint16_t>(static_cast<uint32_t>(val) + 32768u);
  339. }
  340. };
  341. template <> struct channel_convert_to_unsigned<int32_t> {
  342. using argument_type = int32_t;
  343. using result_type = uint32_t;
  344. using type = uint32_t;
  345. type operator()(int32_t val) const {
  346. return static_cast<uint32_t>(val)+(1u<<31);
  347. }
  348. };
  349. // Converting from unsigned to signed integral channel
  350. // It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
  351. template <typename ChannelValue> // Model ChannelValueConcept
  352. struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
  353. using type = ChannelValue;
  354. };
  355. template <> struct channel_convert_from_unsigned<int8_t> {
  356. using argument_type = uint8_t;
  357. using result_type = int8_t;
  358. using type = int8_t;
  359. type operator()(uint8_t val) const {
  360. return static_cast<int8_t>(static_cast<int32_t>(val) - 128);
  361. }
  362. };
  363. template <> struct channel_convert_from_unsigned<int16_t> {
  364. using argument_type = uint16_t;
  365. using result_type = int16_t;
  366. using type = int16_t;
  367. type operator()(uint16_t val) const {
  368. return static_cast<int16_t>(static_cast<int32_t>(val) - 32768);
  369. }
  370. };
  371. template <> struct channel_convert_from_unsigned<int32_t> {
  372. using argument_type = uint32_t;
  373. using result_type = int32_t;
  374. using type = int32_t;
  375. type operator()(uint32_t val) const {
  376. return static_cast<int32_t>(val - (1u<<31));
  377. }
  378. };
  379. } // namespace detail
  380. /// \ingroup ChannelConvertAlgorithm
  381. /// \brief A unary function object converting between channel types
  382. template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
  383. struct channel_converter {
  384. using argument_type = SrcChannelV;
  385. using result_type = DstChannelV;
  386. auto operator()(SrcChannelV const& src) const -> DstChannelV
  387. {
  388. using to_unsigned = detail::channel_convert_to_unsigned<SrcChannelV>;
  389. using from_unsigned = detail::channel_convert_from_unsigned<DstChannelV>;
  390. using converter_unsigned = channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type>;
  391. return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
  392. }
  393. };
  394. /// \ingroup ChannelConvertAlgorithm
  395. /// \brief Converting from one channel type to another.
  396. template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
  397. inline auto channel_convert(SrcChannel const& src) -> typename channel_traits<DstChannel>::value_type
  398. {
  399. return channel_converter<typename channel_traits<SrcChannel>::value_type,
  400. typename channel_traits<DstChannel>::value_type>()(src);
  401. }
  402. /// \ingroup ChannelConvertAlgorithm
  403. /// \brief Same as channel_converter, except it takes the destination channel by reference, which allows
  404. /// us to move the templates from the class level to the method level. This is important when invoking it
  405. /// on heterogeneous pixels.
  406. struct default_channel_converter {
  407. template <typename Ch1, typename Ch2>
  408. void operator()(Ch1 const& src, Ch2& dst) const
  409. {
  410. dst=channel_convert<Ch2>(src);
  411. }
  412. };
  413. namespace detail
  414. {
  415. // fast integer division by 255
  416. inline auto div255(uint32_t in) -> uint32_t
  417. {
  418. uint32_t tmp = in + 128;
  419. return (tmp + (tmp >> 8)) >> 8;
  420. }
  421. // fast integer divison by 32768
  422. inline auto div32768(uint32_t in) -> uint32_t
  423. {
  424. return (in + 16384) >> 15;
  425. }
  426. }
  427. /// \defgroup ChannelMultiplyAlgorithm channel_multiply
  428. /// \ingroup ChannelAlgorithm
  429. /// \brief Multiplying unsigned channel values of the same type. Performs scaled multiplication result = a * b / max_value
  430. ///
  431. /// Example:
  432. /// \code
  433. /// uint8_t x=128;
  434. /// uint8_t y=128;
  435. /// uint8_t mul = channel_multiply(x,y);
  436. /// assert(mul == 64); // 64 = 128 * 128 / 255
  437. /// \endcode
  438. /// @{
  439. /// \brief This is the default implementation. Performance specializatons are provided
  440. template <typename ChannelValue>
  441. struct channel_multiplier_unsigned {
  442. using first_argument_type = ChannelValue;
  443. using second_argument_type = ChannelValue;
  444. using result_type = ChannelValue;
  445. auto operator()(ChannelValue a, ChannelValue b) const -> ChannelValue
  446. {
  447. return ChannelValue(static_cast<typename base_channel_type<ChannelValue>::type>(a / double(channel_traits<ChannelValue>::max_value()) * b));
  448. }
  449. };
  450. /// \brief Specialization of channel_multiply for 8-bit unsigned channels
  451. template<> struct channel_multiplier_unsigned<uint8_t> {
  452. using first_argument_type = uint8_t;
  453. using second_argument_type = uint8_t;
  454. using result_type = uint8_t;
  455. auto operator()(uint8_t a, uint8_t b) const -> uint8_t { return uint8_t(detail::div255(uint32_t(a) * uint32_t(b))); }
  456. };
  457. /// \brief Specialization of channel_multiply for 16-bit unsigned channels
  458. template<> struct channel_multiplier_unsigned<uint16_t> {
  459. using first_argument_type = uint16_t;
  460. using second_argument_type = uint16_t;
  461. using result_type = uint16_t;
  462. auto operator()(uint16_t a, uint16_t b) const -> uint16_t { return uint16_t((uint32_t(a) * uint32_t(b))/65535); }
  463. };
  464. /// \brief Specialization of channel_multiply for float 0..1 channels
  465. template<> struct channel_multiplier_unsigned<float32_t> {
  466. using first_argument_type = float32_t;
  467. using second_argument_type = float32_t;
  468. using result_type = float32_t;
  469. auto operator()(float32_t a, float32_t b) const -> float32_t { return a*b; }
  470. };
  471. /// \brief A function object to multiply two channels. result = a * b / max_value
  472. template <typename ChannelValue>
  473. struct channel_multiplier {
  474. using first_argument_type = ChannelValue;
  475. using second_argument_type = ChannelValue;
  476. using result_type = ChannelValue;
  477. auto operator()(ChannelValue a, ChannelValue b) const -> ChannelValue
  478. {
  479. using to_unsigned = detail::channel_convert_to_unsigned<ChannelValue>;
  480. using from_unsigned = detail::channel_convert_from_unsigned<ChannelValue>;
  481. using multiplier_unsigned = channel_multiplier_unsigned<typename to_unsigned::result_type>;
  482. return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
  483. }
  484. };
  485. /// \brief A function multiplying two channels. result = a * b / max_value
  486. template <typename Channel> // Models ChannelConcept (could be a channel reference)
  487. inline auto channel_multiply(Channel a, Channel b) -> typename channel_traits<Channel>::value_type
  488. {
  489. return channel_multiplier<typename channel_traits<Channel>::value_type>()(a,b);
  490. }
  491. /// @}
  492. /// \defgroup ChannelInvertAlgorithm channel_invert
  493. /// \ingroup ChannelAlgorithm
  494. /// \brief Returns the inverse of a channel. result = max_value - x + min_value
  495. ///
  496. /// Example:
  497. /// \code
  498. /// // uint8_t == uint8_t == unsigned char
  499. /// uint8_t x=255;
  500. /// uint8_t inv = channel_invert(x);
  501. /// assert(inv == 0);
  502. /// \endcode
  503. /// \brief Default implementation. Provide overloads for performance
  504. /// \ingroup ChannelInvertAlgorithm channel_invert
  505. template <typename Channel> // Models ChannelConcept (could be a channel reference)
  506. inline auto channel_invert(Channel x) -> typename channel_traits<Channel>::value_type
  507. {
  508. using base_t = typename base_channel_type<Channel>::type;
  509. using promoted_t = typename promote_integral<base_t>::type;
  510. promoted_t const promoted_x = x;
  511. promoted_t const promoted_max = channel_traits<Channel>::max_value();
  512. promoted_t const promoted_min = channel_traits<Channel>::min_value();
  513. promoted_t const promoted_inverted_x = promoted_max - promoted_x + promoted_min;
  514. auto const inverted_x = static_cast<base_t>(promoted_inverted_x);
  515. return inverted_x;
  516. }
  517. }} // namespace boost::gil
  518. #endif