VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
grcolourspace.h
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 ///
18 /// \file grcolourspace.h
19 ///
20 
21 #ifndef G_COLOURSPACE__H
22 #define G_COLOURSPACE__H
23 
24 #include "gdef.h"
25 #include <vector>
26 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30 unsigned int g_colourspace_r( unsigned int y , unsigned int u , unsigned int v ) ;
31 unsigned int g_colourspace_g( unsigned int y , unsigned int u , unsigned int v ) ;
32 unsigned int g_colourspace_b( unsigned int y , unsigned int u , unsigned int v ) ;
33 unsigned int g_colourspace_y( unsigned int r , unsigned int g , unsigned int b ) ;
34 unsigned int g_colourspace_u( unsigned int r , unsigned int g , unsigned int b ) ;
35 unsigned int g_colourspace_v( unsigned int r , unsigned int g , unsigned int b ) ;
36 #ifdef __cplusplus
37 }
38 #endif
39 
40 #ifdef __cplusplus
41 
42 namespace Gr
43 {
44  /// \namespace Gr::ColourSpace
45  /// Provides rgb/yuv colourspace mapping functions.
46  ///
47  /// Synopsis.
48  /// \code
49  ///
50  /// typedef Gr::ColourSpace::triple<unsigned char> triple_t ;
51  /// triple_t rgb = Gr::ColourSpace::rgb_int( triple_t(y,u,v) ) ;
52  /// triple_t yuv = Gr::ColourSpace::yuv_int( triple_t(r,g,b) ) ;
53  /// triple_t rgb = Gr::ColourSpace::rgb( triple_t(y,u,v) ) ;
54  /// triple_t yuv = Gr::ColourSpace::yuv( triple_t(r,g,b) ) ;
55  ///
56  /// \endcode
57  /// Most code will be content to use just the two lookup functions rgb_int()
58  /// and yuv_int(), and in that case the bulk of the code here is only used
59  /// at built-time to generate the lookup tables that underlie those functions.
60  ///
61  /// Otherwise, there are two top-level functions rgb_imp() and yuv_imp()
62  /// with lots of template parameters providing maximum flexibility, and
63  /// two convenience functions rgb() and yuv() that use rgb_imp()
64  /// and yuv_imp() with sensible template defaults.
65  ///
66  /// The implementation recognises that the core matrix multiplication
67  /// has to be performed with a higher-precision numeric datatype than
68  /// is used at the interface, and that the values used at the interface
69  /// are sometimes constrained to a range that is not a convenient
70  /// power of two (ie. head-room and toe-room for YUV values). The
71  /// internal datatype can be considered to be "analogue" and the
72  /// external datatype "digital", alluding to their different levels
73  /// of precision.
74  ///
75  /// The internal datatype is most naturally "double", but for speed on
76  /// some machines it can be better to used a fixed-point type. Two
77  /// fixed-point classes are provided, "fp_256" and "fp_1000", together
78  /// with adaptors that are used to convert between internal and external
79  /// values. If any internal datatype other than "double", "fp_256" or
80  /// "fp_1000" is used then it will need to have a corresponding
81  /// adaptor class (as per "converter_double").
82  ///
83  namespace ColourSpace
84  {
85  template <typename T> struct triple ;
86  }
87 }
88 
89 /// \class Gr::ColourSpace::triple
90 /// A 3-tuple for holding rgb or yuv triples.
91 ///
92 template <typename T>
94 {
95  typedef T value_type ;
96  T m_1 ;
97  T m_2 ;
98  T m_3 ;
99  triple( T a , T b , T c ) : m_1(a) , m_2(b) , m_3(c) {}
100  T r() const g__noexcept { return m_1 ; }
101  T g() const g__noexcept { return m_2 ; }
102  T b() const g__noexcept { return m_3 ; }
103  T y() const g__noexcept { return m_1 ; }
104  T u() const g__noexcept { return m_2 ; }
105  T v() const g__noexcept { return m_3 ; }
106  T operator[]( int c ) const { return c == 0 ? m_1 : ( c == 1 ? m_2 : m_3 ) ; }
107 } ;
108 
109 #include "grcolourspacematrix.h"
110 #include "grcolourspacetypes.h"
111 #include "grcolourspaceranges.h"
112 #include "grcolourspacemap.h"
113 #include "grcolourspacetables.h"
114 
115 namespace Gr
116 {
117 namespace ColourSpace
118 {
119 
120 /// Does a cross-product using fp types.
121 ///
122 template <typename Tmatrix, typename Tconverter, typename Ta, typename Ttriple>
123 g__constexpr
124 typename Tconverter::fp_type product( Ta a1 , Ta a2 , Ta a3 , Ttriple tfp ) g__noexcept
125 {
126  return
127  tfp.m_1 * Tconverter::make_fp(a1,Tmatrix::scale) +
128  tfp.m_2 * Tconverter::make_fp(a2,Tmatrix::scale) +
129  tfp.m_3 * Tconverter::make_fp(a3,Tmatrix::scale) ;
130 }
131 
132 /// Calculates y from rgb using fp types.
133 /// Uses the matrix given by the template parameter.
134 ///
135 template <typename Tmatrix, typename Tconverter, typename Ttriple>
136 g__constexpr
137 typename Tconverter::fp_type y_imp( Ttriple rgb ) g__noexcept
138 {
139  return product<Tmatrix,Tconverter>( Tmatrix::yr , Tmatrix::yg , Tmatrix::yb , rgb ) ;
140 }
141 
142 /// Calculates u (cb) from rgb using fp types.
143 /// Uses the matrix given by the template parameter.
144 ///
145 template <typename Tmatrix, typename Tconverter, typename Ttriple>
146 g__constexpr
147 typename Tconverter::fp_type u_imp( Ttriple rgb ) g__noexcept
148 {
149  return product<Tmatrix,Tconverter>( Tmatrix::ur , Tmatrix::ug , Tmatrix::ub , rgb ) ;
150 }
151 
152 /// Calculates v (cr) from rgb using fp types.
153 /// Uses the matrix given by the template parameter.
154 ///
155 template <typename Tmatrix, typename Tconverter, typename Ttriple>
156 g__constexpr
157 typename Tconverter::fp_type v_imp( Ttriple rgb ) g__noexcept
158 {
159  return product<Tmatrix,Tconverter>( Tmatrix::vr , Tmatrix::vg , Tmatrix::vb , rgb ) ;
160 }
161 
162 /// Calculates r from yuv using fp types.
163 /// Uses the matrix given by the template parameter.
164 ///
165 template <typename Tmatrix, typename Tconverter, typename Ttriple>
166 g__constexpr
167 typename Tconverter::fp_type r_imp( Ttriple yuv ) g__noexcept
168 {
169  return product<Tmatrix,Tconverter>( Tmatrix::ry , Tmatrix::ru , Tmatrix::rv , yuv ) ;
170 }
171 
172 /// Calculates g from yuv using fp types.
173 /// Uses the matrix given by the template parameter.
174 ///
175 template <typename Tmatrix, typename Tconverter, typename Ttriple>
176 g__constexpr
177 typename Tconverter::fp_type g_imp( Ttriple yuv ) g__noexcept
178 {
179  return product<Tmatrix,Tconverter>( Tmatrix::gy , Tmatrix::gu , Tmatrix::gv , yuv ) ;
180 }
181 
182 /// Calculates b from yuv using fp types.
183 /// Uses the matrix given by the template parameter.
184 ///
185 template <typename Tmatrix, typename Tconverter, typename Ttriple>
186 g__constexpr
187 typename Tconverter::fp_type b_imp( Ttriple yuv ) g__noexcept
188 {
189  return product<Tmatrix,Tconverter>( Tmatrix::by , Tmatrix::bu , Tmatrix::bv , yuv ) ;
190 }
191 
192 /// A top-level function that calculates yuv from rgb
193 /// with all the implementation options exposed as template parameters.
194 ///
195 template <typename Tmatrix, typename Tconverter,
196  typename Trange_rgb , typename Trange_y, typename Trange_uv,
197  typename Ttriple>
198 Ttriple yuv_imp( Ttriple rgb ) g__noexcept
199 {
200  return Ttriple(
201  map_to_range<Trange_y,Tconverter> ( y_imp<Tmatrix,Tconverter>( map_to_space<Tconverter,Trange_rgb,Trange_rgb,Trange_rgb>(rgb) ) ) ,
202  map_to_range<Trange_uv,Tconverter>( u_imp<Tmatrix,Tconverter>( map_to_space<Tconverter,Trange_rgb,Trange_rgb,Trange_rgb>(rgb) ) ) ,
203  map_to_range<Trange_uv,Tconverter>( v_imp<Tmatrix,Tconverter>( map_to_space<Tconverter,Trange_rgb,Trange_rgb,Trange_rgb>(rgb) ) ) ) ;
204 }
205 
206 /// A top-level function that calculates rgb from yuv
207 /// with all the implementation options exposed as template parameters.
208 ///
209 template <typename Tmatrix, typename Tconverter,
210  typename Trange_rgb , typename Trange_y, typename Trange_uv,
211  typename Ttriple>
212 Ttriple rgb_imp( Ttriple yuv ) g__noexcept
213 {
214  typedef typename Tmatrix::inverse_type matrix_type ;
215  return Ttriple(
216  map_to_range<Trange_rgb,Tconverter>( r_imp<matrix_type,Tconverter>( map_to_space<Tconverter,Trange_y,Trange_uv,Trange_uv>(yuv) ) ) ,
217  map_to_range<Trange_rgb,Tconverter>( g_imp<matrix_type,Tconverter>( map_to_space<Tconverter,Trange_y,Trange_uv,Trange_uv>(yuv) ) ) ,
218  map_to_range<Trange_rgb,Tconverter>( b_imp<matrix_type,Tconverter>( map_to_space<Tconverter,Trange_y,Trange_uv,Trange_uv>(yuv) ) ) ) ;
219 }
220 
221 /// A top-level function that calculates yuv from rgb
222 /// with default implementation options.
223 ///
225 {
226  return yuv_imp<matrix_256,converter_fp<fp_256>,range_rgb,range_y,range_uv>( rgb ) ;
227 }
228 
229 /// A top-level function that calculates rgb from yuv
230 /// with default implementation options.
231 ///
233 {
234  return rgb_imp<matrix_256,converter_fp<fp_256>,range_rgb,range_y,range_uv>( yuv ) ;
235 }
236 
237 /// A fast conversion from yuv to r.
238 ///
239 inline unsigned char r_int( unsigned char y , unsigned char /*u*/ , unsigned char v ) g__noexcept
240 {
241  const int r = table_r_from_y[y] + table_r_from_v[v] ;
242  return clamp<range_rgb,unsigned char>(r) ;
243 }
244 
245 /// A fast conversion from yuv to g.
246 ///
247 inline unsigned char g_int( unsigned char y , unsigned char u , unsigned char v ) g__noexcept
248 {
249  const int g = table_g_from_y[y] + table_g_from_u[u] + table_g_from_v[v] ;
250  return clamp<range_rgb,unsigned char>(g) ;
251 }
252 
253 /// A fast conversion from yuv to b.
254 ///
255 inline unsigned char b_int( unsigned char y , unsigned char u , unsigned char /*v*/ ) g__noexcept
256 {
257  const int b = table_b_from_y[y] + table_b_from_u[u] ;
258  return clamp<range_rgb,unsigned char>(b) ;
259 }
260 
261 /// A fast conversion from yuv to rgb.
262 ///
264 {
265  return triple<unsigned char>( r_int(yuv.y(),yuv.u(),yuv.v()) , g_int(yuv.y(),yuv.u(),yuv.v()) , b_int(yuv.y(),yuv.u(),yuv.v()) ) ;
266 }
267 
268 /// A fast conversion from rgb to y.
269 ///
270 inline unsigned char y_int( unsigned char r , unsigned char g , unsigned char b )
271 {
272  const int y = table_y_from_r[r] + table_y_from_g[g] + table_y_from_b[b] ;
273  return clamp<range_y,unsigned char>( y + range_y::min ) ;
274 }
275 
276 /// A fast conversion from rgb to u.
277 ///
278 inline unsigned char u_int( unsigned char r , unsigned char g , unsigned char b )
279 {
280  static g__constexpr int bias = ( static_cast<int>(range_uv::max) + static_cast<int>(range_uv::min) ) / 2 ;
281  const int u = table_u_from_r[r] + table_u_from_g[g] + table_u_from_b[b] ;
282  return clamp<range_uv,unsigned char>( u + bias ) ;
283 }
284 
285 /// A fast conversion from rgb to v.
286 ///
287 inline unsigned char v_int( unsigned char r , unsigned char g , unsigned char b )
288 {
289  static g__constexpr int bias = ( static_cast<int>(range_uv::max) + static_cast<int>(range_uv::min) ) / 2 ;
290  const int v = table_v_from_r[r] + table_v_from_g[g] + table_v_from_b[b] ;
291  return clamp<range_uv,unsigned char>( v + bias ) ;
292 }
293 
294 /// A fast conversion from rgb to yuv.
295 ///
297 {
298  return triple<unsigned char>( y_int(rgb.r(),rgb.g(),rgb.b()) , u_int(rgb.r(),rgb.g(),rgb.b()) , v_int(rgb.r(),rgb.g(),rgb.b()) ) ;
299 }
300 
301 
302 /// \class Gr::ColourSpace::cache
303 /// A cache for a complete set of rgb/yuv mappings, amounting
304 /// to about 50MB of data.
305 /// Eg:
306 /// \code
307 /// Gr::ColourSpace::cache<unsigned char> cache( Gr::ColourSpace::rgb ) ;
308 /// unsigned int rgb = cache.value<unsigned int>( y , u , v ) ;
309 /// \endcode
310 ///
311 template <typename T>
312 class cache
313 {
314 public:
315  typedef triple<T> triple_t ;
316  typedef std::vector<triple_t> table_t ;
317  table_t table ;
318  cache() {}
319  cache( triple_t (*fn)(triple_t) ) :
320  table(256*256*256,triple_t(0,0,0))
321  {
322  fill( fn ) ;
323  }
324  void fill( triple_t (*fn)(triple_t) )
325  {
326  if( table.empty() ) table.resize( 256*256*256 , triple_t(0,0,0) ) ;
327  typename table_t::iterator p = table.begin() ;
328  for( unsigned int a = 0 ; a <= 255 ; ++a )
329  for( unsigned int b = 0 ; b <= 255 ; ++b )
330  for( unsigned int c = 0 ; c <= 255 ; ++c )
331  *p++ = fn( triple_t(a,b,c) ) ;
332  }
333  triple_t operator()( triple_t abc ) const
334  {
335  typedef g_uint32_t index_t ;
336  return table[
337  (static_cast<index_t>(abc.m_1)<<16) |
338  (static_cast<index_t>(abc.m_2)<<8) |
339  (static_cast<index_t>(abc.m_3)) ] ;
340  }
341  template <typename Tout>
342  Tout value( T a , T b , T c ) const
343  {
344  typedef g_uint32_t index_t ;
345  const index_t index =
346  (static_cast<index_t>(a)<<16) |
347  (static_cast<index_t>(b)<<8) |
348  (static_cast<index_t>(c)) ;
349  return
350  (static_cast<Tout>(table[index].m_1)<<16) |
351  (static_cast<Tout>(table[index].m_2)<<8) |
352  (static_cast<Tout>(table[index].m_3)) ;
353  }
354 } ;
355 
356 }
357 }
358 
359 #endif
360 
361 #endif
triple< unsigned char > rgb(triple< unsigned char > yuv) g__noexcept
A top-level function that calculates rgb from yuv with default implementation options.
unsigned char v_int(unsigned char r, unsigned char g, unsigned char b)
A fast conversion from rgb to v.
unsigned char b_int(unsigned char y, unsigned char u, unsigned char) g__noexcept
A fast conversion from yuv to b.
triple< unsigned char > rgb_int(triple< unsigned char > yuv) g__noexcept
A fast conversion from yuv to rgb.
A 3-tuple for holding rgb or yuv triples.
Definition: grcolourspace.h:85
g__constexpr Tconverter::fp_type product(Ta a1, Ta a2, Ta a3, Ttriple tfp) g__noexcept
Does a cross-product using fp types.
unsigned char u_int(unsigned char r, unsigned char g, unsigned char b)
A fast conversion from rgb to u.
Ttriple rgb_imp(Ttriple yuv) g__noexcept
A top-level function that calculates rgb from yuv with all the implementation options exposed as temp...
unsigned char g_int(unsigned char y, unsigned char u, unsigned char v) g__noexcept
A fast conversion from yuv to g.
g__constexpr Tconverter::fp_type y_imp(Ttriple rgb) g__noexcept
Calculates y from rgb using fp types.
g__constexpr Tconverter::fp_type u_imp(Ttriple rgb) g__noexcept
Calculates u (cb) from rgb using fp types.
Ttriple yuv_imp(Ttriple rgb) g__noexcept
A top-level function that calculates yuv from rgb with all the implementation options exposed as temp...
g__constexpr Tconverter::fp_type g_imp(Ttriple yuv) g__noexcept
Calculates g from yuv using fp types.
g__constexpr Tconverter::fp_type v_imp(Ttriple rgb) g__noexcept
Calculates v (cr) from rgb using fp types.
unsigned char r_int(unsigned char y, unsigned char, unsigned char v) g__noexcept
A fast conversion from yuv to r.
unsigned char y_int(unsigned char r, unsigned char g, unsigned char b)
A fast conversion from rgb to y.
Defines the "digital" range for y component.
g__constexpr Tconverter::fp_type b_imp(Ttriple yuv) g__noexcept
Calculates b from yuv using fp types.
Defines the "digital" range for u/v components.
triple< unsigned char > yuv(triple< unsigned char > rgb) g__noexcept
A top-level function that calculates yuv from rgb with default implementation options.
This file has been machine generated – do not edit.
Defines the "digital" range for r/g/b components.
A cache for a complete set of rgb/yuv mappings, amounting to about 50MB of data.
triple< unsigned char > yuv_int(triple< unsigned char > rgb) g__noexcept
A fast conversion from rgb to yuv.
g__constexpr Tconverter::fp_type r_imp(Ttriple yuv) g__noexcept
Calculates r from yuv using fp types.
This file has been machine generated – do not edit.