ycbcr.hpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. //
  2. // Copyright 2013 Juan V. Puertos G-Cluster, Christian Henning
  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_EXTENSION_TOOLBOX_COLOR_SPACES_YCBCR_HPP
  9. #define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_YCBCR_HPP
  10. #include <boost/gil/extension/toolbox/metafunctions/get_num_bits.hpp>
  11. #include <boost/gil/color_convert.hpp>
  12. #include <boost/gil.hpp> // FIXME: Include what you use!
  13. #include <boost/gil/detail/mp11.hpp>
  14. #include <boost/config.hpp>
  15. #include <cstdint>
  16. #include <type_traits>
  17. namespace boost { namespace gil {
  18. /// \addtogroup ColorNameModel
  19. /// \{
  20. namespace ycbcr_601_color_space
  21. {
  22. /// \brief Luminance
  23. struct y_t {};
  24. /// \brief Blue chrominance component
  25. struct cb_t {};
  26. /// \brief Red chrominance component
  27. struct cr_t {};
  28. }
  29. namespace ycbcr_709_color_space
  30. {
  31. /// \brief Luminance
  32. struct y_t {};
  33. /// \brief Blue chrominance component
  34. struct cb_t {};
  35. /// \brief Red chrominance component
  36. struct cr_t {};
  37. }
  38. /// \}
  39. /// \ingroup ColorSpaceModel
  40. using ycbcr_601__t = mp11::mp_list
  41. <
  42. ycbcr_601_color_space::y_t,
  43. ycbcr_601_color_space::cb_t,
  44. ycbcr_601_color_space::cr_t
  45. >;
  46. /// \ingroup ColorSpaceModel
  47. using ycbcr_709__t = mp11::mp_list
  48. <
  49. ycbcr_709_color_space::y_t,
  50. ycbcr_709_color_space::cb_t,
  51. ycbcr_709_color_space::cr_t
  52. >;
  53. /// \ingroup LayoutModel
  54. using ycbcr_601__layout_t = boost::gil::layout<ycbcr_601__t>;
  55. using ycbcr_709__layout_t = boost::gil::layout<ycbcr_709__t>;
  56. //The channel depth is ALWAYS 8bits ofr YCbCr!
  57. GIL_DEFINE_ALL_TYPEDEFS(8, uint8_t, ycbcr_601_)
  58. GIL_DEFINE_ALL_TYPEDEFS(8, uint8_t, ycbcr_709_)
  59. namespace detail {
  60. // Source:boost/algorithm/clamp.hpp
  61. template<typename T>
  62. BOOST_CXX14_CONSTEXPR
  63. T const& clamp(
  64. T const& val,
  65. typename boost::mp11::mp_identity<T>::type const & lo,
  66. typename boost::mp11::mp_identity<T>::type const & hi)
  67. {
  68. // assert ( !p ( hi, lo )); // Can't assert p ( lo, hi ) b/c they might be equal
  69. auto const p = std::less<T>();
  70. return p(val, lo) ? lo : p(hi, val) ? hi : val;
  71. }
  72. } // namespace detail
  73. /*
  74. * 601 Source: http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
  75. * 709 Source: http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.709_conversion
  76. * (using values coming directly from ITU-R BT.601 recommendation)
  77. * (using values coming directly from ITU-R BT.709 recommendation)
  78. */
  79. /**
  80. * @brief Convert YCbCr ITU.BT-601 to RGB.
  81. */
  82. template<>
  83. struct default_color_converter_impl<ycbcr_601__t, rgb_t>
  84. {
  85. // Note: the RGB_t channels range can be set later on by the users. We dont want to cast to uint8_t or anything here.
  86. template < typename SRCP, typename DSTP >
  87. void operator()( const SRCP& src, DSTP& dst ) const
  88. {
  89. using dst_channel_t = typename channel_type<DSTP>::type;
  90. convert(src, dst, typename std::is_same
  91. <
  92. std::integral_constant<int, sizeof(dst_channel_t)>,
  93. std::integral_constant<int, 1>
  94. >::type());
  95. }
  96. private:
  97. // optimization for bit8 channels
  98. template< typename Src_Pixel
  99. , typename Dst_Pixel
  100. >
  101. void convert( const Src_Pixel& src
  102. , Dst_Pixel& dst
  103. , std::true_type // is 8 bit channel
  104. ) const
  105. {
  106. using namespace ycbcr_601_color_space;
  107. using src_channel_t = typename channel_type<Src_Pixel>::type;
  108. using dst_channel_t = typename channel_type<Dst_Pixel>::type;
  109. src_channel_t y = channel_convert<src_channel_t>( get_color(src, y_t()));
  110. src_channel_t cb = channel_convert<src_channel_t>( get_color(src, cb_t()));
  111. src_channel_t cr = channel_convert<src_channel_t>( get_color(src, cr_t()));
  112. // The intermediate results of the formulas require at least 16bits of precission.
  113. std::int_fast16_t c = y - 16;
  114. std::int_fast16_t d = cb - 128;
  115. std::int_fast16_t e = cr - 128;
  116. std::int_fast16_t red = detail::clamp((( 298 * c + 409 * e + 128) >> 8), 0, 255);
  117. std::int_fast16_t green = detail::clamp((( 298 * c - 100 * d - 208 * e + 128) >> 8), 0, 255);
  118. std::int_fast16_t blue = detail::clamp((( 298 * c + 516 * d + 128) >> 8), 0, 255);
  119. get_color( dst, red_t() ) = (dst_channel_t) red;
  120. get_color( dst, green_t() ) = (dst_channel_t) green;
  121. get_color( dst, blue_t() ) = (dst_channel_t) blue;
  122. }
  123. template< typename Src_Pixel
  124. , typename Dst_Pixel
  125. >
  126. void convert( const Src_Pixel& src
  127. , Dst_Pixel& dst
  128. , std::false_type // is 8 bit channel
  129. ) const
  130. {
  131. using namespace ycbcr_601_color_space;
  132. using dst_channel_t = typename channel_type<Dst_Pixel>::type;
  133. double y = get_color( src, y_t() );
  134. double cb = get_color( src, cb_t() );
  135. double cr = get_color( src, cr_t() );
  136. get_color(dst, red_t()) = static_cast<dst_channel_t>(
  137. detail::clamp(1.6438 * (y - 16.0) + 1.5960 * (cr -128.0), 0.0, 255.0));
  138. get_color(dst, green_t()) = static_cast<dst_channel_t>(
  139. detail::clamp(1.6438 * (y - 16.0) - 0.3917 * (cb - 128.0) + 0.8129 * (cr -128.0), 0.0, 255.0));
  140. get_color(dst, blue_t()) = static_cast<dst_channel_t>(
  141. detail::clamp(1.6438 * ( y - 16.0 ) - 2.0172 * ( cb -128.0 ), 0.0, 255.0));
  142. }
  143. };
  144. /*
  145. * Source: http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
  146. * digital Y'CbCr derived from digital R'dG'dB'd 8 bits per sample, each using the full range.
  147. * with NO footroom wither headroom.
  148. */
  149. /**
  150. * @brief Convert RGB to YCbCr ITU.BT-601.
  151. */
  152. template<>
  153. struct default_color_converter_impl<rgb_t, ycbcr_601__t>
  154. {
  155. template < typename SRCP, typename DSTP >
  156. void operator()( const SRCP& src, DSTP& dst ) const
  157. {
  158. using namespace ycbcr_601_color_space;
  159. using src_channel_t = typename channel_type<SRCP>::type;
  160. using dst_channel_t = typename channel_type<DSTP>::type;
  161. src_channel_t red = channel_convert<src_channel_t>( get_color(src, red_t()));
  162. src_channel_t green = channel_convert<src_channel_t>( get_color(src, green_t()));
  163. src_channel_t blue = channel_convert<src_channel_t>( get_color(src, blue_t()));
  164. double y = 16.0 + 0.2567 * red + 0.5041 * green + 0.0979 * blue;
  165. double cb = 128.0 - 0.1482 * red - 0.2909 * green + 0.4392 * blue;
  166. double cr = 128.0 + 0.4392 * red - 0.3677 * green - 0.0714 * blue;
  167. get_color( dst, y_t() ) = (dst_channel_t) y;
  168. get_color( dst, cb_t() ) = (dst_channel_t) cb;
  169. get_color( dst, cr_t() ) = (dst_channel_t) cr;
  170. }
  171. };
  172. /**
  173. * @brief Convert RGB to YCbCr ITU.BT-709.
  174. */
  175. template<>
  176. struct default_color_converter_impl<rgb_t, ycbcr_709__t>
  177. {
  178. template < typename SRCP, typename DSTP >
  179. void operator()( const SRCP& src, DSTP& dst ) const
  180. {
  181. using namespace ycbcr_709_color_space;
  182. using src_channel_t = typename channel_type<SRCP>::type;
  183. using dst_channel_t = typename channel_type<DSTP>::type;
  184. src_channel_t red = channel_convert<src_channel_t>( get_color(src, red_t()));
  185. src_channel_t green = channel_convert<src_channel_t>( get_color(src, green_t()));
  186. src_channel_t blue = channel_convert<src_channel_t>( get_color(src, blue_t()));
  187. double y = 0.299 * red + 0.587 * green + 0.114 * blue;
  188. double cb = 128.0 - 0.168736 * red - 0.331264 * green + 0.5 * blue;
  189. double cr = 128.0 + 0.5 * red - 0.418688 * green - 0.081312 * blue;
  190. get_color( dst, y_t() ) = (dst_channel_t) y;
  191. get_color( dst, cb_t() ) = (dst_channel_t) cb;
  192. get_color( dst, cr_t() ) = (dst_channel_t) cr;
  193. }
  194. };
  195. /**
  196. * @brief Convert RGB to YCbCr ITU.BT-709.
  197. */
  198. template<>
  199. struct default_color_converter_impl<ycbcr_709__t, rgb_t>
  200. {
  201. template < typename SRCP, typename DSTP >
  202. void operator()( const SRCP& src, DSTP& dst ) const
  203. {
  204. using namespace ycbcr_709_color_space;
  205. using src_channel_t = typename channel_type<SRCP>::type;
  206. using dst_channel_t = typename channel_type<DSTP>::type;
  207. src_channel_t y = channel_convert<src_channel_t>( get_color(src, y_t()) );
  208. src_channel_t cb_clipped = channel_convert<src_channel_t>( get_color(src, cb_t()) - 128 );
  209. src_channel_t cr_clipped = channel_convert<src_channel_t>( get_color(src, cr_t()) - 128 );
  210. double red = y + 1.042 * cr_clipped;
  211. double green = y - 0.34414 * cb_clipped - 0.71414 * cr_clipped;
  212. double blue = y + 1.772 * cb_clipped;
  213. get_color( dst, red_t() ) = (dst_channel_t) red;
  214. get_color( dst, green_t() ) = (dst_channel_t) green;
  215. get_color( dst, blue_t() ) = (dst_channel_t) blue;
  216. }
  217. };
  218. } // namespace gil
  219. } // namespace boost
  220. #endif