channel_algorithm.hpp 22 KB

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