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