libcvd
convert_pixel_types.h
1 #ifndef CVD_CONVERT_PIXEL_TYPES_H
2 #define CVD_CONVERT_PIXEL_TYPES_H
3 
4 #include <cstring>
5 #include <cvd/internal/builtin_components.h>
6 #include <cvd/internal/rgb_components.h>
7 #include <cvd/internal/scalar_convert.h>
8 #include <limits>
9 #include <math.h>
10 #include <type_traits>
11 
12 namespace CVD
13 {
14 namespace Pixel
15 {
16  //All "conversion" classes must have a "void convert_pixel(from, to)"
17  //nonstatic templated member.
18 
19  //This conversion knows how to convert from any size pixel to any other.
20 
21  template <class From, class To, int CF = Pixel::Component<From>::count, int CT = Pixel::Component<To>::count>
23 
24  template <class From, class To>
25  struct GenericConversion<From, To, 1, 1>
26  {
27  static inline void convert(const From& from, To& to)
28  {
29  to = scalar_convert<To, From>(from);
30  }
31  };
32 
33  template <class From, class To, int N>
34  struct GenericConversion<From, To, N, N>
35  {
36  typedef typename Pixel::Component<From>::type FromS;
37  typedef typename Pixel::Component<To>::type ToS;
38  static inline void convert(const From& from, To& to)
39  {
40  for(int i = 0; i < N; i++)
41  Pixel::Component<To>::get(to, i) = scalar_convert<ToS, FromS>(Pixel::Component<From>::get(from, i));
42  }
43  };
44 
45  template <class T, int N>
46  struct GenericConversion<T, T, N, N>
47  {
48  static inline void convert(const T& from, T& to)
49  {
50  to = from;
51  }
52  };
53 
54  template <class T, int N>
55  struct GenericConversion<T[N], T[N], N, N>
56  {
57  typedef T array[N];
58  static inline void convert(const array& from, array& to)
59  {
60  for(int i = 0; i < N; i++)
61  to[i] = from[i];
62  }
63  };
64 
65  template <class Rgbish, class Scalar>
66  struct CIE
67  {
68  static inline void convert(const Rgbish& from, Scalar& to)
69  {
70  // "Correct" values are:
71  // const double wr=0.299, wg=0.587, wb=0.114;
72  // Since these are not representable as floating point values
73  // They do not sum exactly to 1.
74  // Instead, convert them using floor(x * 0x10000 + 0.5)/0x10000
75  // So that they use exactly 16 bits of precision.
76  // This should be OK for pretty mych everything
77  // 0.299 ~= 19595/0x10000 == 0x4c8bp-16 == 0.2989959716796875
78  // 0.587 ~= 38470/0x10000 == 0x9646p-16 == 0.587005615234375
79  // 0.114 ~= 7471/0x10000 == 0x1d2fp-16 == 0.1139984130859375
80  // These will sum exactly to 1. C++ does not yet allow hex floating point
81  // literals
82  const double wr = 0.2989959716796875, wg = 0.587005615234375, wb = 0.1139984130859375;
83 
84  /*
85  The old method does not work properly because the conversion to double from int_type
86  is inexact. Ttuncation of this causes errors. However, it is unnecessary to convert
87  to the double pixel type first: the arithmetic merely needs to be done with doubles.
88 
89  to = scalar_convert<Scalar,double>(wr*scalar_convert<double,typename Pixel::Component<Rgbish>::type>(from.red) +
90  wg*scalar_convert<double,typename Pixel::Component<Rgbish>::type>(from.green) +
91  wb*scalar_convert<double,typename Pixel::Component<Rgbish>::type>(from.blue));
92 
93  Fortunately, we have forseen this eventuality, and scalar_convert can convert from
94  type A, to type B when pixel type B is held in a variable of type C
95  */
96  to = scalar_convert<Scalar, typename Pixel::Component<Rgbish>::type, double>(wr * static_cast<double>(from.red) + wg * static_cast<double>(from.green) + wb * static_cast<double>(from.blue));
97 
98  /* The following method could be used (for speed):
99 
100  to = scalar_convert<Scalar,typename Pixel::Component<Rgbish>::type>(
101  static_cast<typename Pixel::Component<Rgbish>::type>(wr*from.red + wg*from.green + wb*from.blue));
102 
103  but this looses precision and may produce odd results for rgb(x,y,z) (x!=y!=z). Does this matter? Bear
104  in mind that wr, wg, wb are only approximations of "average" human eye response anyway.
105  */
106  }
107  };
108 
109  template <class P, class Scalar>
110  struct Uniform
111  {
112  static inline void convert(const P& from, Scalar& to)
113  {
114  typedef typename Pixel::Component<P>::type T;
115  typename traits<T>::wider_type sum = Pixel::Component<P>::get(from, 0);
116  for(unsigned int i = 1; i < Pixel::Component<P>::count; i++)
117  sum += Pixel::Component<P>::get(from, i);
118  to = scalar_convert<Scalar, T>(sum / Pixel::Component<P>::count);
119  }
120  };
121 
122  template <class P, class Scalar>
123  struct RMS
124  {
125  static inline void convert(const P& from, Scalar& to)
126  {
127  typedef typename Pixel::Component<P>::type T;
128  double sum = Pixel::Component<P>::get(from, 0);
129  sum *= sum;
130  for(unsigned int i = 1; i < Pixel::Component<P>::count; i++)
131  {
132  double w = Pixel::Component<P>::get(from, i);
133  sum += w * w;
134  }
135  to = scalar_convert<Scalar, T, double>(sqrt(sum / (Pixel::Component<P>::count)));
136  }
137  };
138 
139  template <class P, class Scalar>
140  struct L2Norm
141  {
142  static inline void convert(const P& from, Scalar& to)
143  {
144  typedef typename Pixel::Component<P>::type T;
145  double sum = Pixel::Component<P>::get(from, 0);
146  sum *= sum;
147  for(unsigned int i = 1; i < Pixel::Component<P>::count; i++)
148  {
149  double w = Pixel::Component<P>::get(from, i);
150  sum += w * w;
151  }
152  to = scalar_convert<Scalar, T, double>(sqrt(sum));
153  }
154  };
155 
156  template <class P, class Scalar>
158  {
159  static inline void convert(const P& from, Scalar& to)
160  {
161  typedef typename Pixel::Component<P>::type T;
162  double sum = Pixel::Component<P>::get(from, 0);
163  sum *= sum;
164  for(unsigned int i = 1; i < Pixel::Component<P>::count; i++)
165  {
166  double w = Pixel::Component<P>::get(from, i);
167  sum += w * w;
168  }
169  to = scalar_convert<Scalar, T, double>(sum);
170  }
171  };
172 
173  template <class Scalar, class Vec>
174  struct Replicate
175  {
176  static inline void convert(const Scalar& from, Vec& to)
177  {
178  typedef typename Pixel::Component<Vec>::type T;
179  Pixel::Component<Vec>::get(to, 0) = scalar_convert<T, Scalar>(from);
180  for(size_t i = 1; i < Pixel::Component<Vec>::count; i++)
182  }
183  };
184 
185  template <class Scalar, class T>
186  struct GreyToRgba
187  {
188  static inline void convert(const Scalar& from, Rgba<T>& to)
189  {
190  to.red = to.green = to.blue = scalar_convert<T, Scalar>(from);
192  }
193  };
194 
195  template <class A, class B>
196  inline void RgbToRgb(const A& from, B& to)
197  {
198  typedef typename Pixel::Component<A>::type T;
199  typedef typename Pixel::Component<B>::type S;
200  to.red = scalar_convert<S, T>(from.red);
201  to.green = scalar_convert<S, T>(from.green);
202  to.blue = scalar_convert<S, T>(from.blue);
203  }
204 
205  template <class A, class B>
207  {
208  static inline void convert(const A& from, B& to)
209  {
210  RgbToRgb(from, to);
211  }
212  };
213 
214  template <class A, class T>
215  struct RgbishToRgbish<A, Rgba<T>>
216  {
217  static inline void convert(const A& from, Rgba<T>& to)
218  {
219  RgbToRgb(from, to);
221  }
222  };
223 
224  template <class A, class T>
225  struct RgbishToRgbish<A, Argb<T>>
226  {
227  static inline void convert(const A& from, Argb<T>& to)
228  {
229  RgbToRgb(from, to);
231  }
232  };
233 
234  template <class S, class T>
235  struct RgbishToRgbish<Rgba<S>, Rgba<T>>
236  {
237  static inline void convert(const Rgba<S>& from, Rgba<T>& to)
238  {
239  RgbToRgb(from, to);
240  to.alpha = scalar_convert<T, S>(from.alpha);
241  }
242  };
243 
244  template <class S, class T>
245  struct RgbishToRgbish<Argb<S>, Argb<T>>
246  {
247  static inline void convert(const Argb<S>& from, Argb<T>& to)
248  {
249  RgbToRgb(from, to);
250  to.alpha = scalar_convert<T, S>(from.alpha);
251  }
252  };
253 
254  // Default conversions
255 
256  template <class From, class To, int FN = Pixel::Component<From>::count, int TN = Pixel::Component<To>::count>
258  {
260  };
261 
262  // Scalar to X
263  template <class S, class T>
264  struct DefaultConversion<S, Rgb<T>, 1, 3>
265  {
266  typedef Replicate<S, Rgb<T>> type;
267  };
268  template <class S>
269  struct DefaultConversion<S, Rgb8, 1, 3>
270  {
271  typedef Replicate<S, Rgb8> type;
272  };
273  template <class S, class T>
274  struct DefaultConversion<S, Bgrx<T>, 1, 3>
275  {
276  typedef Replicate<S, Bgrx<T>> type;
277  };
278  template <class S, class T>
279  struct DefaultConversion<S, Rgba<T>, 1, 4>
280  {
281  typedef GreyToRgba<S, T> type;
282  };
283 
284  // Rgb<T> to X
285  template <class T, class S>
286  struct DefaultConversion<Rgb<T>, S, 3, 1>
287  {
288  typedef CIE<Rgb<T>, S> type;
289  };
290  template <class T>
291  struct DefaultConversion<Rgb<T>, Rgb8, 3, 3>
292  {
293  typedef RgbishToRgbish<Rgb<T>, Rgb8> type;
294  };
295  template <class T, class S>
296  struct DefaultConversion<Rgb<T>, Rgba<S>, 3, 4>
297  {
299  };
300  template <class T, class S>
301  struct DefaultConversion<Rgb<T>, Rgb<S>, 3, 3>
302  {
304  };
305  template <class T>
306  struct DefaultConversion<Rgb<T>, Rgb<T>, 3, 3>
307  {
309  };
310  template <class T>
311  struct DefaultConversion<Rgb<T>, Bgrx<T>, 3, 3>
312  {
314  };
315 
316  // Bgrx<T> to X
317  template <class T, class S>
318  struct DefaultConversion<Bgrx<T>, S, 3, 1>
319  {
320  typedef CIE<Bgrx<T>, S> type;
321  };
322  template <class T>
323  struct DefaultConversion<Bgrx<T>, Rgb8, 3, 3>
324  {
325  typedef RgbishToRgbish<Bgrx<T>, Rgb8> type;
326  };
327  template <class T, class S>
328  struct DefaultConversion<Bgrx<T>, Rgba<S>, 3, 4>
329  {
331  };
332  template <class T, class S>
333  struct DefaultConversion<Bgrx<T>, Rgb<S>, 3, 3>
334  {
336  };
337  template <class T>
338  struct DefaultConversion<Bgrx<T>, Rgb<T>, 3, 3>
339  {
341  };
342  template <class T>
343  struct DefaultConversion<Bgrx<T>, Bgrx<T>, 3, 3>
344  {
346  };
347 
348  // Rgb8 to X
349  template <class S>
350  struct DefaultConversion<Rgb8, S, 3, 1>
351  {
352  typedef CIE<Rgb8, S> type;
353  };
354  template <class S>
355  struct DefaultConversion<Rgb8, Rgb<S>, 3, 3>
356  {
358  };
359  template <class S>
360  struct DefaultConversion<Rgb8, Rgba<S>, 3, 4>
361  {
363  };
364  template <class S>
365  struct DefaultConversion<Rgb8, Bgrx<S>, 3, 4>
366  {
368  };
369  template <>
370  struct DefaultConversion<Rgb8, Rgb8, 3, 3>
371  {
373  };
374 
375  // Rgba<T> to X
376  template <class T, class S>
377  struct DefaultConversion<Rgba<T>, S, 4, 1>
378  {
379  typedef CIE<Rgba<T>, S> type;
380  };
381  template <class T, class S>
382  struct DefaultConversion<Rgba<T>, Rgb<S>, 4, 3>
383  {
385  };
386  template <class T, class S>
387  struct DefaultConversion<Rgba<T>, Bgrx<S>, 4, 3>
388  {
390  };
391  template <class T>
392  struct DefaultConversion<Rgba<T>, Rgb8, 4, 3>
393  {
394  typedef RgbishToRgbish<Rgba<T>, Rgb8> type;
395  };
396  template <class T, class S>
397  struct DefaultConversion<Rgba<T>, Rgba<S>, 4, 4>
398  {
400  };
401  template <class T, class S>
402  struct DefaultConversion<Rgba<T>, Argb<S>, 4, 4>
403  {
405  };
406  template <class T>
407  struct DefaultConversion<Rgba<T>, Rgba<T>, 4, 4>
408  {
410  };
411 
412  // Argb<T> to X
413  template <class T, class S>
414  struct DefaultConversion<Argb<T>, S, 4, 1>
415  {
416  typedef CIE<Argb<T>, S> type;
417  };
418  template <class T, class S>
419  struct DefaultConversion<Argb<T>, Rgb<S>, 4, 3>
420  {
422  };
423  template <class T>
424  struct DefaultConversion<Argb<T>, Rgb8, 4, 3>
425  {
426  typedef RgbishToRgbish<Argb<T>, Rgb8> type;
427  };
428  template <class T, class S>
429  struct DefaultConversion<Argb<T>, Rgba<S>, 4, 4>
430  {
432  };
433  template <class T>
434  struct DefaultConversion<Argb<T>, Argb<T>, 4, 4>
435  {
437  };
438 
439  template <class From, class To, class Conv = typename DefaultConversion<From, To>::type,
440  bool both_pod = std::is_trivially_copyable<From>::value&& std::is_trivially_copyable<To>::value>
442  {
443  static inline void convert(const From* from, To* to, size_t count)
444  {
445  for(size_t i = 0; i < count; i++)
446  Conv::convert(from[i], to[i]);
447  }
448  };
449 
450  template <class T>
451  struct ConvertPixels<T, T, GenericConversion<T, T>, true>
452  {
453  static inline void convert(const T* from, T* to, size_t count)
454  {
455  std::memcpy(to, from, count * sizeof(T));
456  }
457  };
458 
463  template <class C>
465  {
466  static const int is = std::numeric_limits<C>::is_specialized;
467  };
468 
469  template <class C>
471  {
472  static const int is = std::numeric_limits<C>::is_specialized;
473  };
474 
475  template <class C>
477  {
478  static const int is = std::numeric_limits<C>::is_specialized;
479  };
480 
481  template <class C>
483  {
484  static const int is = std::numeric_limits<C>::is_specialized;
485  };
486 
487  template <class C>
489  {
490  static const int is = std::numeric_limits<C>::is_specialized;
491  };
492 
493  template <>
495  {
496  static const int is = 1;
497  };
498 
499 }
500 }
501 #endif
T blue
The blue component.
Definition: rgba.h:47
A colour consisting of red, green and blue components.
Definition: rgb.h:25
All classes and functions are within the CVD namespace.
Definition: argb.h:6
Definition: convert_pixel_types.h:174
A colour consisting of red, green, blue and dummy components, in the order bgr dummy in memory...
Definition: bgrx.h:16
Definition: convert_pixel_types.h:22
A colour consisting of red, green, blue and alpha components.
Definition: argb.h:17
T alpha
The alpha component.
Definition: rgba.h:48
Definition: convert_pixel_types.h:257
A 32-bit colour.
Definition: rgb8.h:11
All pixel types which are DefaultConvertible can be converted freely from one to another.
Definition: convert_pixel_types.h:464
A colour consisting of red, green, blue and alpha components.
Definition: rgba.h:17
Definition: convert_pixel_types.h:110
Definition: convert_pixel_types.h:186
Definition: convert_pixel_types.h:123
Definition: convert_pixel_types.h:206
T green
The green component.
Definition: rgba.h:46
Definition: convert_pixel_types.h:441
Definition: convert_pixel_types.h:66
Definition: builtin_components.h:38
Definition: convert_pixel_types.h:157
T red
The red component.
Definition: rgba.h:45
Definition: pixel_traits.h:16
T alpha
The alpha component.
Definition: argb.h:45
Definition: convert_pixel_types.h:140