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