1 // Copyright (C) 2006  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 #ifndef DLIB_PIXEl_
4 #define DLIB_PIXEl_
5 
6 #include <iostream>
7 #include "serialize.h"
8 #include <cmath>
9 #include "algs.h"
10 #include "uintn.h"
11 #include <limits>
12 #include <complex>
13 #include "enable_if.h"
14 
15 namespace dlib
16 {
17 
18 // ----------------------------------------------------------------------------------------
19 
20     /*!
21         This file contains definitions of pixel objects and related classes and
22         functionality.
23     !*/
24 
25 // ----------------------------------------------------------------------------------------
26 
27     template <typename T>
28     struct pixel_traits;
29     /*!
30         WHAT THIS OBJECT REPRESENTS
31             As the name implies, this is a traits class for pixel types.
32             It defines the properties of a pixel.
33 
34         This traits class will define the following public static members:
35             - bool grayscale
36             - bool rgb
37             - bool rgb_alpha
38             - bool hsi
39             - bool lab
40 
41             - bool has_alpha
42 
43             - long num
44 
45             - basic_pixel_type
46             - basic_pixel_type min()
47             - basic_pixel_type max()
48             - is_unsigned
49 
50         The above public constants are subject to the following constraints:
51             - only one of grayscale, rgb, rgb_alpha, hsi or lab is true
52             - if (rgb == true) then
53                 - The type T will be a struct with 3 public members of type
54                   unsigned char named "red" "green" and "blue".
55                 - This type of pixel represents the RGB color space.
56                 - num == 3
57                 - has_alpha == false
58                 - basic_pixel_type == unsigned char
59                 - min() == 0
60                 - max() == 255
61                 - is_unsigned == true
62             - if (rgb_alpha == true) then
63                 - The type T will be a struct with 4 public members of type
64                   unsigned char named "red" "green" "blue" and "alpha".
65                 - This type of pixel represents the RGB color space with
66                   an alpha channel where an alpha of 0 represents a pixel
67                   that is totally transparent and 255 represents a pixel
68                   with maximum opacity.
69                 - num == 4
70                 - has_alpha == true
71                 - basic_pixel_type == unsigned char
72                 - min() == 0
73                 - max() == 255
74                 - is_unsigned == true
75             - else if (hsi == true) then
76                 - The type T will be a struct with 3 public members of type
77                   unsigned char named "h" "s" and "i".
78                 - This type of pixel represents the HSI color space.
79                 - num == 3
80                 - has_alpha == false
81                 - basic_pixel_type == unsigned char
82                 - min() == 0
83                 - max() == 255
84                 - is_unsigned == true
85              - else if (lab == true) then
86                 - The type T will be a struct with 3 public members of type
87                   unsigned char named "l" "a" and "b".
88                 - This type of pixel represents the Lab color space.
89                 - num == 3
90                 - has_alpha == false
91                 - basic_pixel_type == unsigned char
92                 - min() == 0
93                 - max() == 255
94                 - is_unsigned == true
95             - else
96                 - grayscale == true
97                 - This type of pixel represents a grayscale color space.  T
98                   will be some kind of basic scalar type such as unsigned int.
99                 - num == 1
100                 - has_alpha == false
101                 - basic_pixel_type == T
102                 - min() == the minimum obtainable value of objects of type T
103                 - max() == the maximum obtainable value of objects of type T
104                 - is_unsigned is true if min() == 0 and false otherwise
105     !*/
106 
107 // ----------------------------------------------------------------------------------------
108 
109     struct rgb_pixel
110     {
111         /*!
112             WHAT THIS OBJECT REPRESENTS
113                 This is a simple struct that represents an RGB colored graphical pixel.
114         !*/
115 
rgb_pixelrgb_pixel116         rgb_pixel (
117         ) {}
118 
rgb_pixelrgb_pixel119         rgb_pixel (
120             unsigned char red_,
121             unsigned char green_,
122             unsigned char blue_
123         ) : red(red_), green(green_), blue(blue_) {}
124 
125         unsigned char red;
126         unsigned char green;
127         unsigned char blue;
128 
129         bool operator == (const rgb_pixel& that) const
130         {
131             return this->red   == that.red
132                 && this->green == that.green
133                 && this->blue  == that.blue;
134         }
135 
136         bool operator != (const rgb_pixel& that) const
137         {
138             return !(*this == that);
139         }
140 
141     };
142 
143 // ----------------------------------------------------------------------------------------
144 
145     struct bgr_pixel
146     {
147         /*!
148             WHAT THIS OBJECT REPRESENTS
149                 This is a simple struct that represents an BGR colored graphical pixel.
150                 (the reason it exists in addition to the rgb_pixel is so you can lay
151                 it down on top of a memory region that organizes its color data in the
152                 BGR format and still be able to read it)
153         !*/
154 
bgr_pixelbgr_pixel155         bgr_pixel (
156         ) {}
157 
bgr_pixelbgr_pixel158         bgr_pixel (
159             unsigned char blue_,
160             unsigned char green_,
161             unsigned char red_
162         ) : blue(blue_), green(green_), red(red_) {}
163 
164         unsigned char blue;
165         unsigned char green;
166         unsigned char red;
167 
168         bool operator == (const bgr_pixel& that) const
169         {
170             return this->blue  == that.blue
171                 && this->green == that.green
172                 && this->red   == that.red;
173         }
174 
175         bool operator != (const bgr_pixel& that) const
176         {
177             return !(*this == that);
178         }
179 
180     };
181 
182 // ----------------------------------------------------------------------------------------
183 
184     struct rgb_alpha_pixel
185     {
186         /*!
187             WHAT THIS OBJECT REPRESENTS
188                 This is a simple struct that represents an RGB colored graphical pixel
189                 with an alpha channel.
190         !*/
191 
rgb_alpha_pixelrgb_alpha_pixel192         rgb_alpha_pixel (
193         ) {}
194 
rgb_alpha_pixelrgb_alpha_pixel195         rgb_alpha_pixel (
196             unsigned char red_,
197             unsigned char green_,
198             unsigned char blue_,
199             unsigned char alpha_
200         ) : red(red_), green(green_), blue(blue_), alpha(alpha_) {}
201 
202         unsigned char red;
203         unsigned char green;
204         unsigned char blue;
205         unsigned char alpha;
206 
207         bool operator == (const rgb_alpha_pixel& that) const
208         {
209             return this->red   == that.red
210                 && this->green == that.green
211                 && this->blue  == that.blue
212                 && this->alpha == that.alpha;
213         }
214 
215         bool operator != (const rgb_alpha_pixel& that) const
216         {
217             return !(*this == that);
218         }
219 
220     };
221 
222 // ----------------------------------------------------------------------------------------
223 
224     struct hsi_pixel
225     {
226         /*!
227             WHAT THIS OBJECT REPRESENTS
228                 This is a simple struct that represents an HSI colored graphical pixel.
229         !*/
230 
hsi_pixelhsi_pixel231         hsi_pixel (
232         ) {}
233 
hsi_pixelhsi_pixel234         hsi_pixel (
235             unsigned char h_,
236             unsigned char s_,
237             unsigned char i_
238         ) : h(h_), s(s_), i(i_) {}
239 
240         unsigned char h;
241         unsigned char s;
242         unsigned char i;
243 
244         bool operator == (const hsi_pixel& that) const
245         {
246             return this->h == that.h
247                 && this->s == that.s
248                 && this->i == that.i;
249         }
250 
251         bool operator != (const hsi_pixel& that) const
252         {
253             return !(*this == that);
254         }
255 
256     };
257 
258     // ----------------------------------------------------------------------------------------
259 
260     struct lab_pixel
261     {
262         /*!
263             WHAT THIS OBJECT REPRESENTS
264                 This is a simple struct that represents an Lab colored graphical pixel.
265         !*/
266 
lab_pixellab_pixel267         lab_pixel (
268         ) {}
269 
lab_pixellab_pixel270         lab_pixel (
271                 unsigned char l_,
272                 unsigned char a_,
273                 unsigned char b_
274         ) : l(l_), a(a_), b(b_) {}
275 
276         unsigned char l;
277         unsigned char a;
278         unsigned char b;
279 
280         bool operator == (const lab_pixel& that) const
281         {
282             return this->l == that.l
283                 && this->a == that.a
284                 && this->b == that.b;
285         }
286 
287         bool operator != (const lab_pixel& that) const
288         {
289             return !(*this == that);
290         }
291 
292     };
293 
294 // ----------------------------------------------------------------------------------------
295 
296     template <
297         typename P1,
298         typename P2
299         >
300     inline void assign_pixel (
301         P1& dest,
302         const P2& src
303     );
304     /*!
305         requires
306             - pixel_traits<P1> must be defined
307             - pixel_traits<P2> must be defined
308         ensures
309             - if (P1 and P2 are the same type of pixel) then
310                 - simply copies the value of src into dest.  In other words,
311                   dest will be identical to src after this function returns.
312             - else if (P1 and P2 are not the same type of pixel) then
313                 - assigns pixel src to pixel dest and does any necessary color space
314                   conversions.
315                 - When converting from a grayscale color space with more than 255 values the
316                   pixel intensity is saturated at pixel_traits<P1>::max() or pixel_traits<P1>::min()
317                   as appropriate.
318                 - if (the dest pixel has an alpha channel and the src pixel doesn't) then
319                     - #dest.alpha == 255
320                 - else if (the src pixel has an alpha channel but the dest pixel doesn't) then
321                     - #dest == the original dest value blended with the src value according
322                       to the alpha channel in src.
323                       (i.e.  #dest == src*(alpha/255) + dest*(1-alpha/255))
324     !*/
325 
326 // ----------------------------------------------------------------------------------------
327 
328     template <
329         typename P
330         >
331     inline typename pixel_traits<P>::basic_pixel_type get_pixel_intensity (
332         const P& src
333     );
334     /*!
335         requires
336             - pixel_traits<P> must be defined
337         ensures
338             - if (pixel_traits<P>::grayscale == true) then
339                 - returns src
340             - else
341                 - converts src to grayscale and returns the resulting value.
342     !*/
343 
344 // ----------------------------------------------------------------------------------------
345 
346     template <
347         typename P,
348         typename T
349         >
350     inline void assign_pixel_intensity (
351         P& dest,
352         const T& new_intensity
353     );
354     /*!
355         requires
356             - pixel_traits<P> must be defined
357             - pixel_traits<T> must be defined
358         ensures
359             - This function changes the intensity of the dest pixel. So if the pixel in
360               question is a grayscale pixel then it simply assigns that pixel with the
361               value of get_pixel_intensity(new_intensity).  However, if the pixel is not
362               a grayscale pixel then it converts the pixel to the HSI color space and sets
363               the I channel to the given intensity and then converts this HSI value back to
364               the original pixel's color space.
365             - Note that we don't necessarily have #get_pixel_intensity(dest) == get_pixel_intensity(new_intensity)
366               due to vagaries of how converting to and from HSI works out.
367             - if (the dest pixel has an alpha channel) then
368                 - #dest.alpha == dest.alpha
369     !*/
370 
371 // ----------------------------------------------------------------------------------------
372 
373     inline void serialize (
374         const rgb_pixel& item,
375         std::ostream& out
376     );
377     /*!
378         provides serialization support for the rgb_pixel struct
379     !*/
380 
381 // ----------------------------------------------------------------------------------------
382 
383     inline void deserialize (
384         rgb_pixel& item,
385         std::istream& in
386     );
387     /*!
388         provides deserialization support for the rgb_pixel struct
389     !*/
390 
391 // ----------------------------------------------------------------------------------------
392 
393     inline void serialize (
394         const bgr_pixel& item,
395         std::ostream& out
396     );
397     /*!
398         provides serialization support for the bgr_pixel struct
399     !*/
400 
401 // ----------------------------------------------------------------------------------------
402 
403     inline void deserialize (
404         bgr_pixel& item,
405         std::istream& in
406     );
407     /*!
408         provides deserialization support for the bgr_pixel struct
409     !*/
410 
411 // ----------------------------------------------------------------------------------------
412 
413     inline void serialize (
414         const rgb_alpha_pixel& item,
415         std::ostream& out
416     );
417     /*!
418         provides serialization support for the rgb_alpha_pixel struct
419     !*/
420 
421 // ----------------------------------------------------------------------------------------
422 
423     inline void deserialize (
424         rgb_alpha_pixel& item,
425         std::istream& in
426     );
427     /*!
428         provides deserialization support for the rgb_alpha_pixel struct
429     !*/
430 
431 // ----------------------------------------------------------------------------------------
432 
433     inline void serialize (
434         const hsi_pixel& item,
435         std::ostream& out
436     );
437     /*!
438         provides serialization support for the hsi_pixel struct
439     !*/
440 
441 // ----------------------------------------------------------------------------------------
442 
443     inline void serialize (
444             const lab_pixel& item,
445             std::ostream& out
446     );
447     /*!
448         provides serialization support for the lab_pixel struct
449     !*/
450 
451 
452 // ----------------------------------------------------------------------------------------
453 
454     inline void deserialize (
455         hsi_pixel& item,
456         std::istream& in
457     );
458     /*!
459         provides deserialization support for the hsi_pixel struct
460     !*/
461 // ----------------------------------------------------------------------------------------
462 
463     inline void deserialize (
464             lab_pixel& item,
465             std::istream& in
466     );
467     /*!
468         provides deserialization support for the lab_pixel struct
469     !*/
470 
471 // ----------------------------------------------------------------------------------------
472 
473     template <>
474     struct pixel_traits<rgb_pixel>
475     {
476         constexpr static bool rgb  = true;
477         constexpr static bool rgb_alpha  = false;
478         constexpr static bool grayscale = false;
479         constexpr static bool hsi = false;
480         constexpr static bool lab = false;
481         enum { num = 3};
482         typedef unsigned char basic_pixel_type;
483         static basic_pixel_type min() { return 0;}
484         static basic_pixel_type max() { return 255;}
485         constexpr static bool is_unsigned = true;
486         constexpr static bool has_alpha = false;
487     };
488 
489 // ----------------------------------------------------------------------------------------
490 
491     template <>
492     struct pixel_traits<bgr_pixel>
493     {
494         constexpr static bool rgb  = true;
495         constexpr static bool rgb_alpha  = false;
496         constexpr static bool grayscale = false;
497         constexpr static bool hsi = false;
498         constexpr static bool lab = false;
499         constexpr static long num = 3;
500         typedef unsigned char basic_pixel_type;
501         static basic_pixel_type min() { return 0;}
502         static basic_pixel_type max() { return 255;}
503         constexpr static bool is_unsigned = true;
504         constexpr static bool has_alpha = false;
505     };
506 
507 // ----------------------------------------------------------------------------------------
508 
509     template <>
510     struct pixel_traits<rgb_alpha_pixel>
511     {
512         constexpr static bool rgb  = false;
513         constexpr static bool rgb_alpha  = true;
514         constexpr static bool grayscale = false;
515         constexpr static bool hsi = false;
516         constexpr static bool lab = false;
517         constexpr static long num = 4;
518         typedef unsigned char basic_pixel_type;
519         static basic_pixel_type min() { return 0;}
520         static basic_pixel_type max() { return 255;}
521         constexpr static bool is_unsigned = true;
522         constexpr static bool has_alpha = true;
523     };
524 
525 // ----------------------------------------------------------------------------------------
526 
527 
528     template <>
529     struct pixel_traits<hsi_pixel>
530     {
531         constexpr static bool rgb  = false;
532         constexpr static bool rgb_alpha  = false;
533         constexpr static bool grayscale = false;
534         constexpr static bool hsi = true;
535         constexpr static bool lab = false;
536         constexpr static long num = 3;
537         typedef unsigned char basic_pixel_type;
538         static basic_pixel_type min() { return 0;}
539         static basic_pixel_type max() { return 255;}
540         constexpr static bool is_unsigned = true;
541         constexpr static bool has_alpha = false;
542     };
543 
544 // ----------------------------------------------------------------------------------------
545 
546 
547     template <>
548     struct pixel_traits<lab_pixel>
549     {
550         constexpr static bool rgb  = false;
551         constexpr static bool rgb_alpha  = false;
552         constexpr static bool grayscale = false;
553         constexpr static bool hsi = false;
554         constexpr static bool lab = true;
555         constexpr static long num = 3;
556         typedef unsigned char basic_pixel_type;
557         static basic_pixel_type min() { return 0;}
558         static basic_pixel_type max() { return 255;}
559         constexpr static bool is_unsigned = true;
560         constexpr static bool has_alpha = false;
561     };
562 
563 // ----------------------------------------------------------------------------------------
564 
565     template <typename T>
566     struct grayscale_pixel_traits
567     {
568         constexpr static bool rgb  = false;
569         constexpr static bool rgb_alpha  = false;
570         constexpr static bool grayscale = true;
571         constexpr static bool hsi = false;
572         constexpr static bool lab = false;
573         constexpr static long num = 1;
574         constexpr static bool has_alpha = false;
575         typedef T basic_pixel_type;
576         static basic_pixel_type min() { return std::numeric_limits<T>::min();}
577         static basic_pixel_type max() { return std::numeric_limits<T>::max();}
578         constexpr static bool is_unsigned = is_unsigned_type<T>::value;
579     };
580 
581     template <> struct pixel_traits<unsigned char>  : public grayscale_pixel_traits<unsigned char> {};
582     template <> struct pixel_traits<unsigned short> : public grayscale_pixel_traits<unsigned short> {};
583     template <> struct pixel_traits<unsigned int>   : public grayscale_pixel_traits<unsigned int> {};
584     template <> struct pixel_traits<unsigned long>  : public grayscale_pixel_traits<unsigned long> {};
585 
586     template <> struct pixel_traits<char>           : public grayscale_pixel_traits<char> {};
587     template <> struct pixel_traits<signed char>    : public grayscale_pixel_traits<signed char> {};
588     template <> struct pixel_traits<short>          : public grayscale_pixel_traits<short> {};
589     template <> struct pixel_traits<int>            : public grayscale_pixel_traits<int> {};
590     template <> struct pixel_traits<long>           : public grayscale_pixel_traits<long> {};
591 
592     template <> struct pixel_traits<int64>          : public grayscale_pixel_traits<int64> {};
593     template <> struct pixel_traits<uint64>         : public grayscale_pixel_traits<uint64> {};
594 
595 // ----------------------------------------------------------------------------------------
596 
597     template <typename T>
598     struct float_grayscale_pixel_traits
599     {
600         constexpr static bool rgb  = false;
601         constexpr static bool rgb_alpha  = false;
602         constexpr static bool grayscale = true;
603         constexpr static bool hsi = false;
604         constexpr static bool lab = false;
605         constexpr static long num = 1;
606         constexpr static bool has_alpha = false;
607         typedef T basic_pixel_type;
608         static basic_pixel_type min() { return -std::numeric_limits<T>::max();}
609         static basic_pixel_type max() { return std::numeric_limits<T>::max();}
610         constexpr static bool is_unsigned = false;
611     };
612 
613     template <> struct pixel_traits<float>          : public float_grayscale_pixel_traits<float> {};
614     template <> struct pixel_traits<double>         : public float_grayscale_pixel_traits<double> {};
615     template <> struct pixel_traits<long double>    : public float_grayscale_pixel_traits<long double> {};
616 
617     // These are here mainly so you can easily copy images into complex arrays.  This is
618     // useful when you want to do a FFT on an image or some similar operation.
619     template <> struct pixel_traits<std::complex<float> > :       public float_grayscale_pixel_traits<float> {};
620     template <> struct pixel_traits<std::complex<double> > :      public float_grayscale_pixel_traits<double> {};
621     template <> struct pixel_traits<std::complex<long double> > : public float_grayscale_pixel_traits<long double> {};
622 
623 // ----------------------------------------------------------------------------------------
624 
625     // The following is a bunch of conversion stuff for the assign_pixel function.
626 
627     namespace assign_pixel_helpers
628     {
629 
630     // -----------------------------
631         // all the same kind
632 
633         template < typename P >
634         typename enable_if_c<pixel_traits<P>::grayscale>::type
635         assign(P& dest, const P& src)
636         {
637             dest = src;
638         }
639 
640     // -----------------------------
641 
642         template <typename T>
643         typename unsigned_type<T>::type make_unsigned (
644             const T& val
645         ) { return static_cast<typename unsigned_type<T>::type>(val); }
646 
647         inline float make_unsigned(const float& val) { return val; }
648         inline double make_unsigned(const double& val) { return val; }
649         inline long double make_unsigned(const long double& val) { return val; }
650 
651 
652         template <typename T, typename P>
653         typename enable_if_c<pixel_traits<T>::is_unsigned == pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max (
654             const P& p
655         )
656         /*!
657             ensures
658                 - returns true if p is <= max value of T
659         !*/
660         {
661             return p <= pixel_traits<T>::max();
662         }
663 
664         template <typename T, typename P>
665         typename enable_if_c<pixel_traits<T>::is_unsigned && !pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max (
666             const P& p
667         )
668         {
669             if (p <= 0)
670                 return true;
671             else if (make_unsigned(p) <= pixel_traits<T>::max())
672                 return true;
673             else
674                 return false;
675         }
676 
677         template <typename T, typename P>
678         typename enable_if_c<!pixel_traits<T>::is_unsigned && pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max (
679             const P& p
680         )
681         {
682             return p <= make_unsigned(pixel_traits<T>::max());
683         }
684 
685     // -----------------------------
686 
687         template <typename T, typename P>
688         typename enable_if_c<pixel_traits<P>::is_unsigned, bool >::type greater_or_equal_to_min (
689             const P&
690         ) { return true; }
691         /*!
692             ensures
693                 - returns true if p is >= min value of T
694         !*/
695 
696         template <typename T, typename P>
697         typename enable_if_c<!pixel_traits<P>::is_unsigned && pixel_traits<T>::is_unsigned, bool >::type greater_or_equal_to_min (
698             const P& p
699         )
700         {
701             return p >= 0;
702         }
703 
704         template <typename T, typename P>
705         typename enable_if_c<!pixel_traits<P>::is_unsigned && !pixel_traits<T>::is_unsigned, bool >::type greater_or_equal_to_min (
706             const P& p
707         )
708         {
709             return p >= pixel_traits<T>::min();
710         }
711     // -----------------------------
712 
713         template < typename P1, typename P2 >
714         typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::grayscale>::type
715         assign(P1& dest, const P2& src)
716         {
717             /*
718                 The reason for these weird comparison functions is to avoid getting compiler
719                 warnings about comparing signed types to unsigned and stuff like that.
720             */
721 
722             if (less_or_equal_to_max<P1>(src))
723                 if (greater_or_equal_to_min<P1>(src))
724                     dest = static_cast<P1>(src);
725                 else
726                     dest = pixel_traits<P1>::min();
727             else
728                 dest = pixel_traits<P1>::max();
729         }
730 
731     // -----------------------------
732     // -----------------------------
733     // -----------------------------
734 
735         template < typename P1, typename P2 >
736         typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::rgb>::type
737         assign(P1& dest, const P2& src)
738         {
739             dest.red = src.red;
740             dest.green = src.green;
741             dest.blue = src.blue;
742         }
743 
744         template < typename P1, typename P2 >
745         typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::rgb_alpha>::type
746         assign(P1& dest, const P2& src)
747         {
748             dest.red = src.red;
749             dest.green = src.green;
750             dest.blue = src.blue;
751             dest.alpha = src.alpha;
752         }
753 
754         template < typename P1, typename P2 >
755         typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::hsi>::type
756         assign(P1& dest, const P2& src)
757         {
758             dest.h = src.h;
759             dest.s = src.s;
760             dest.i = src.i;
761         }
762 
763         template < typename P1, typename P2 >
764         typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::lab>::type
765         assign(P1& dest, const P2& src)
766         {
767             dest.l = src.l;
768             dest.a = src.a;
769             dest.b = src.b;
770         }
771 
772     // -----------------------------
773         // dest is a grayscale
774 
775         template < typename P1, typename P2 >
776         typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::rgb>::type
777         assign(P1& dest, const P2& src)
778         {
779             const unsigned int temp = ((static_cast<unsigned int>(src.red) +
780                                         static_cast<unsigned int>(src.green) +
781                                         static_cast<unsigned int>(src.blue))/3);
782             assign_pixel(dest, temp);
783         }
784 
785         template < typename P1, typename P2 >
786         typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::rgb_alpha>::type
787         assign(P1& dest, const P2& src)
788         {
789 
790             const unsigned char avg = static_cast<unsigned char>((static_cast<unsigned int>(src.red) +
791                                                                   static_cast<unsigned int>(src.green) +
792                                                                   static_cast<unsigned int>(src.blue))/3);
793 
794             if (src.alpha == 255)
795             {
796                 assign_pixel(dest, avg);
797             }
798             else
799             {
800                 // perform this assignment using fixed point arithmetic:
801                 // dest = src*(alpha/255) + dest*(1 - alpha/255);
802                 // dest = src*(alpha/255) + dest*1 - dest*(alpha/255);
803                 // dest = dest*1 + src*(alpha/255) - dest*(alpha/255);
804                 // dest = dest*1 + (src - dest)*(alpha/255);
805                 // dest += (src - dest)*(alpha/255);
806 
807                 int temp = avg;
808                 // copy dest into dest_copy using assign_pixel to avoid potential
809                 // warnings about implicit float to int warnings.
810                 int dest_copy;
811                 assign_pixel(dest_copy, dest);
812 
813                 temp -= dest_copy;
814 
815                 temp *= src.alpha;
816 
817                 temp /= 255;
818 
819                 assign_pixel(dest, temp+dest_copy);
820             }
821         }
822 
823         template < typename P1, typename P2 >
824         typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::hsi>::type
825         assign(P1& dest, const P2& src)
826         {
827             assign_pixel(dest, src.i);
828         }
829 
830         template < typename P1, typename P2 >
831         typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::lab>::type
832         assign(P1& dest, const P2& src)
833         {
834             assign_pixel(dest, src.l);
835         }
836 
837 
838     // -----------------------------
839 
840         struct HSL
841         {
842             double h;
843             double s;
844             double l;
845         };
846 
847         struct COLOUR
848         {
849             double r;
850             double g;
851             double b;
852         };
853 
854         /*
855             I found this excellent bit of code for dealing with HSL spaces at
856             http://local.wasp.uwa.edu.au/~pbourke/colour/hsl/
857         */
858         /*
859             Calculate HSL from RGB
860             Hue is in degrees
861             Lightness is between 0 and 1
862             Saturation is between 0 and 1
863         */
864         inline HSL RGB2HSL(COLOUR c1)
865         {
866             double themin,themax,delta;
867             HSL c2;
868             using namespace std;
869 
870             themin = std::min(c1.r,std::min(c1.g,c1.b));
871             themax = std::max(c1.r,std::max(c1.g,c1.b));
872             delta = themax - themin;
873             c2.l = (themin + themax) / 2;
874             c2.s = 0;
875             if (c2.l > 0 && c2.l < 1)
876                 c2.s = delta / (c2.l < 0.5 ? (2*c2.l) : (2-2*c2.l));
877             c2.h = 0;
878             if (delta > 0) {
879                 if (themax == c1.r && themax != c1.g)
880                     c2.h += (c1.g - c1.b) / delta;
881                 if (themax == c1.g && themax != c1.b)
882                     c2.h += (2 + (c1.b - c1.r) / delta);
883                 if (themax == c1.b && themax != c1.r)
884                     c2.h += (4 + (c1.r - c1.g) / delta);
885                 c2.h *= 60;
886             }
887             return(c2);
888         }
889 
890         /*
891             Calculate RGB from HSL, reverse of RGB2HSL()
892             Hue is in degrees
893             Lightness is between 0 and 1
894             Saturation is between 0 and 1
895         */
896         inline COLOUR HSL2RGB(HSL c1)
897         {
898             COLOUR c2,sat,ctmp;
899             using namespace std;
900 
901             if (c1.h < 120) {
902                 sat.r = (120 - c1.h) / 60.0;
903                 sat.g = c1.h / 60.0;
904                 sat.b = 0;
905             } else if (c1.h < 240) {
906                 sat.r = 0;
907                 sat.g = (240 - c1.h) / 60.0;
908                 sat.b = (c1.h - 120) / 60.0;
909             } else {
910                 sat.r = (c1.h - 240) / 60.0;
911                 sat.g = 0;
912                 sat.b = (360 - c1.h) / 60.0;
913             }
914             sat.r = std::min(sat.r,1.0);
915             sat.g = std::min(sat.g,1.0);
916             sat.b = std::min(sat.b,1.0);
917 
918             ctmp.r = 2 * c1.s * sat.r + (1 - c1.s);
919             ctmp.g = 2 * c1.s * sat.g + (1 - c1.s);
920             ctmp.b = 2 * c1.s * sat.b + (1 - c1.s);
921 
922             if (c1.l < 0.5) {
923                 c2.r = c1.l * ctmp.r;
924                 c2.g = c1.l * ctmp.g;
925                 c2.b = c1.l * ctmp.b;
926             } else {
927                 c2.r = (1 - c1.l) * ctmp.r + 2 * c1.l - 1;
928                 c2.g = (1 - c1.l) * ctmp.g + 2 * c1.l - 1;
929                 c2.b = (1 - c1.l) * ctmp.b + 2 * c1.l - 1;
930             }
931 
932             return(c2);
933         }
934 
935         // -----------------------------
936 
937         struct Lab
938         {
939             double l;
940             double a;
941             double b;
942         };
943         /*
944             Calculate Lab from RGB
945             L is between 0 and 100
946             a is between -128 and 127
947             b is between -128 and 127
948             RGB is between 0.0 and 1.0
949         */
950         inline Lab RGB2Lab(COLOUR c1)
951         {
952             Lab c2;
953             using namespace std;
954 
955             double var_R = c1.r;
956             double var_G = c1.g;
957             double var_B = c1.b;
958 
959             if (var_R > 0.04045) {
960                 var_R = pow(((var_R + 0.055) / 1.055), 2.4);
961             } else {
962                 var_R = var_R / 12.92;
963             }
964 
965             if (var_G > 0.04045) {
966                 var_G = pow(((var_G + 0.055) / 1.055), 2.4);
967             } else {
968                 var_G = var_G / 12.92;
969             }
970 
971             if (var_B > 0.04045) {
972                 var_B = pow(((var_B + 0.055) / 1.055), 2.4);
973             } else {
974                 var_B = var_B / 12.92;
975             }
976 
977             var_R = var_R * 100;
978             var_G = var_G * 100;
979             var_B = var_B * 100;
980 
981 //Observer. = 2°, Illuminant = D65
982             double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805;
983             double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722;
984             double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505;
985 
986             double var_X = X / 95.047;
987             double var_Y = Y / 100.000;
988             double var_Z = Z / 108.883;
989 
990             if (var_X > 0.008856) {
991                 var_X = pow(var_X, (1.0 / 3));
992             }
993             else {
994                 var_X = (7.787 * var_X) + (16.0 / 116);
995             }
996 
997             if (var_Y > 0.008856) {
998                 var_Y = pow(var_Y, (1.0 / 3));
999             }
1000             else {
1001                 var_Y = (7.787 * var_Y) + (16.0 / 116);
1002             }
1003 
1004             if (var_Z > 0.008856) {
1005                 var_Z = pow(var_Z, (1.0 / 3));
1006             }
1007             else {
1008                 var_Z = (7.787 * var_Z) + (16.0 / 116);
1009             }
1010 
1011             //clamping
1012             c2.l = std::max(0.0, (116.0 * var_Y) - 16);
1013             c2.a = std::max(-128.0, std::min(127.0, 500.0 * (var_X - var_Y)));
1014             c2.b = std::max(-128.0, std::min(127.0, 200.0 * (var_Y - var_Z)));
1015 
1016             return c2;
1017         }
1018 
1019         /*
1020             Calculate RGB from Lab, reverse of RGB2LAb()
1021             L is between 0 and 100
1022             a is between -128 and 127
1023             b is between -128 and 127
1024             RGB is between 0.0 and 1.0
1025         */
1026         inline COLOUR Lab2RGB(Lab c1) {
1027             COLOUR c2;
1028             using namespace std;
1029 
1030             double var_Y = (c1.l + 16) / 116.0;
1031             double var_X = (c1.a / 500.0) + var_Y;
1032             double var_Z = var_Y - (c1.b / 200);
1033 
1034             if (pow(var_Y, 3) > 0.008856) {
1035                 var_Y = pow(var_Y, 3);
1036             } else {
1037                 var_Y = (var_Y - 16.0 / 116) / 7.787;
1038             }
1039 
1040             if (pow(var_X, 3) > 0.008856) {
1041                 var_X = pow(var_X, 3);
1042             } else {
1043                 var_X = (var_X - 16.0 / 116) / 7.787;
1044             }
1045 
1046             if (pow(var_Z, 3) > 0.008856) {
1047                 var_Z = pow(var_Z, 3);
1048             } else {
1049                 var_Z = (var_Z - 16.0 / 116) / 7.787;
1050             }
1051 
1052             double X = var_X * 95.047;
1053             double Y = var_Y * 100.000;
1054             double Z = var_Z * 108.883;
1055 
1056             var_X = X / 100.0;
1057             var_Y = Y / 100.0;
1058             var_Z = Z / 100.0;
1059 
1060             double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986;
1061             double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415;
1062             double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570;
1063 
1064             if (var_R > 0.0031308) {
1065                 var_R = 1.055 * pow(var_R, (1 / 2.4)) - 0.055;
1066             } else {
1067                 var_R = 12.92 * var_R;
1068             }
1069 
1070             if (var_G > 0.0031308) {
1071                 var_G = 1.055 * pow(var_G, (1 / 2.4)) - 0.055;
1072             } else {
1073                 var_G = 12.92 * var_G;
1074             }
1075 
1076             if (var_B > 0.0031308) {
1077                 var_B = 1.055 * pow(var_B, (1 / 2.4)) - 0.055;
1078             } else {
1079                 var_B = 12.92 * var_B;
1080             }
1081 
1082             // clamping
1083             c2.r = std::max(0.0, std::min(1.0, var_R));
1084             c2.g = std::max(0.0, std::min(1.0, var_G));
1085             c2.b = std::max(0.0, std::min(1.0, var_B));
1086 
1087             return (c2);
1088         }
1089 
1090 
1091     // -----------------------------
1092         // dest is a color rgb_pixel
1093 
1094         template < typename P1 >
1095         typename enable_if_c<pixel_traits<P1>::rgb>::type
1096         assign(P1& dest, const unsigned char& src)
1097         {
1098             dest.red = src;
1099             dest.green = src;
1100             dest.blue = src;
1101         }
1102 
1103         template < typename P1, typename P2 >
1104         typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::grayscale>::type
1105         assign(P1& dest, const P2& src)
1106         {
1107             unsigned char p;
1108             assign_pixel(p, src);
1109             dest.red = p;
1110             dest.green = p;
1111             dest.blue = p;
1112         }
1113 
1114         template < typename P1, typename P2 >
1115         typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::rgb_alpha>::type
1116         assign(P1& dest, const P2& src)
1117         {
1118             if (src.alpha == 255)
1119             {
1120                 dest.red = src.red;
1121                 dest.green = src.green;
1122                 dest.blue = src.blue;
1123             }
1124             else
1125             {
1126                 // perform this assignment using fixed point arithmetic:
1127                 // dest = src*(alpha/255) + dest*(1 - alpha/255);
1128                 // dest = src*(alpha/255) + dest*1 - dest*(alpha/255);
1129                 // dest = dest*1 + src*(alpha/255) - dest*(alpha/255);
1130                 // dest = dest*1 + (src - dest)*(alpha/255);
1131                 // dest += (src - dest)*(alpha/255);
1132 
1133                 unsigned int temp_r = src.red;
1134                 unsigned int temp_g = src.green;
1135                 unsigned int temp_b = src.blue;
1136 
1137                 temp_r -= dest.red;
1138                 temp_g -= dest.green;
1139                 temp_b -= dest.blue;
1140 
1141                 temp_r *= src.alpha;
1142                 temp_g *= src.alpha;
1143                 temp_b *= src.alpha;
1144 
1145                 temp_r >>= 8;
1146                 temp_g >>= 8;
1147                 temp_b >>= 8;
1148 
1149                 dest.red += static_cast<unsigned char>(temp_r&0xFF);
1150                 dest.green += static_cast<unsigned char>(temp_g&0xFF);
1151                 dest.blue += static_cast<unsigned char>(temp_b&0xFF);
1152             }
1153         }
1154 
1155         template < typename P1, typename P2 >
1156         typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::hsi>::type
1157         assign(P1& dest, const P2& src)
1158         {
1159             COLOUR c;
1160             HSL h;
1161             h.h = src.h;
1162             h.h = h.h/255.0*360;
1163             h.s = src.s/255.0;
1164             h.l = src.i/255.0;
1165             c = HSL2RGB(h);
1166 
1167             dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5);
1168             dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5);
1169             dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5);
1170         }
1171 
1172         template < typename P1, typename P2 >
1173         typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::lab>::type
1174         assign(P1& dest, const P2& src)
1175         {
1176             COLOUR c;
1177             Lab l;
1178             l.l = (src.l/255.0)*100;
1179             l.a = (src.a-128.0);
1180             l.b = (src.b-128.0);
1181             c = Lab2RGB(l);
1182 
1183             dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5);
1184             dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5);
1185             dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5);
1186         }
1187 
1188 
1189     // -----------------------------
1190     // dest is a color rgb_alpha_pixel
1191 
1192         template < typename P1 >
1193         typename enable_if_c<pixel_traits<P1>::rgb_alpha>::type
1194         assign(P1& dest, const unsigned char& src)
1195         {
1196             dest.red = src;
1197             dest.green = src;
1198             dest.blue = src;
1199             dest.alpha = 255;
1200         }
1201 
1202 
1203         template < typename P1, typename P2 >
1204         typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::grayscale>::type
1205         assign(P1& dest, const P2& src)
1206         {
1207             unsigned char p;
1208             assign_pixel(p, src);
1209 
1210             dest.red = p;
1211             dest.green = p;
1212             dest.blue = p;
1213             dest.alpha = 255;
1214         }
1215 
1216         template < typename P1, typename P2 >
1217         typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::rgb>::type
1218         assign(P1& dest, const P2& src)
1219         {
1220             dest.red = src.red;
1221             dest.green = src.green;
1222             dest.blue = src.blue;
1223             dest.alpha = 255;
1224         }
1225 
1226         template < typename P1, typename P2 >
1227         typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::hsi>::type
1228         assign(P1& dest, const P2& src)
1229         {
1230             COLOUR c;
1231             HSL h;
1232             h.h = src.h;
1233             h.h = h.h/255.0*360;
1234             h.s = src.s/255.0;
1235             h.l = src.i/255.0;
1236             c = HSL2RGB(h);
1237 
1238             dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5);
1239             dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5);
1240             dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5);
1241             dest.alpha = 255;
1242         }
1243 
1244         template < typename P1, typename P2 >
1245         typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::lab>::type
1246         assign(P1& dest, const P2& src)
1247         {
1248             COLOUR c;
1249             Lab l;
1250             l.l = (src.l/255.0)*100;
1251             l.a = (src.a-128.0);
1252             l.b = (src.b-128.0);
1253             c = Lab2RGB(l);
1254 
1255             dest.red = static_cast<unsigned char>(c.r * 255 + 0.5);
1256             dest.green = static_cast<unsigned char>(c.g * 255 + 0.5);
1257             dest.blue = static_cast<unsigned char>(c.b * 255 + 0.5);
1258             dest.alpha = 255;
1259         }
1260     // -----------------------------
1261         // dest is an hsi pixel
1262 
1263         template < typename P1>
1264         typename enable_if_c<pixel_traits<P1>::hsi>::type
1265         assign(P1& dest, const unsigned char& src)
1266         {
1267             dest.h = 0;
1268             dest.s = 0;
1269             dest.i = src;
1270         }
1271 
1272 
1273         template < typename P1, typename P2 >
1274         typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::grayscale>::type
1275         assign(P1& dest, const P2& src)
1276         {
1277             dest.h = 0;
1278             dest.s = 0;
1279             assign_pixel(dest.i, src);
1280         }
1281 
1282         template < typename P1, typename P2 >
1283         typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::rgb>::type
1284         assign(P1& dest, const P2& src)
1285         {
1286             COLOUR c1;
1287             HSL c2;
1288             c1.r = src.red/255.0;
1289             c1.g = src.green/255.0;
1290             c1.b = src.blue/255.0;
1291             c2 = RGB2HSL(c1);
1292 
1293             dest.h = static_cast<unsigned char>(c2.h/360.0*255.0 + 0.5);
1294             dest.s = static_cast<unsigned char>(c2.s*255.0 + 0.5);
1295             dest.i = static_cast<unsigned char>(c2.l*255.0 + 0.5);
1296         }
1297 
1298         template < typename P1, typename P2 >
1299         typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::rgb_alpha>::type
1300         assign(P1& dest, const P2& src)
1301         {
1302             rgb_pixel temp;
1303             // convert target hsi pixel to rgb
1304             assign_pixel_helpers::assign(temp,dest);
1305 
1306             // now assign the rgb_alpha value to our temp rgb pixel
1307             assign_pixel_helpers::assign(temp,src);
1308 
1309             // now we can just go assign the new rgb value to the
1310             // hsi pixel
1311             assign_pixel_helpers::assign(dest,temp);
1312         }
1313 
1314         template < typename P1, typename P2 >
1315         typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::lab>::type
1316         assign(P1& dest, const P2& src)
1317         {
1318             rgb_pixel temp;
1319             // convert lab value to our temp rgb pixel
1320             assign_pixel_helpers::assign(temp,src);
1321             // now we can just go assign the new rgb value to the
1322             // hsi pixel
1323             assign_pixel_helpers::assign(dest,temp);
1324         }
1325 
1326     // -----------------------------
1327         // dest is an lab pixel
1328         template < typename P1>
1329         typename enable_if_c<pixel_traits<P1>::lab>::type
1330         assign(P1& dest, const unsigned char& src)
1331         {
1332             dest.a = 128;
1333             dest.b = 128;
1334             dest.l = src;
1335         }
1336 
1337 
1338         template < typename P1, typename P2 >
1339         typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::grayscale>::type
1340         assign(P1& dest, const P2& src)
1341         {
1342             dest.a = 128;
1343             dest.b = 128;
1344             assign_pixel(dest.l, src);
1345         }
1346 
1347         template < typename P1, typename P2 >
1348         typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::rgb>::type
1349         assign(P1& dest, const P2& src)
1350         {
1351             COLOUR c1;
1352             Lab c2;
1353             c1.r = src.red / 255.0;
1354             c1.g = src.green / 255.0;
1355             c1.b = src.blue / 255.0;
1356             c2 = RGB2Lab(c1);
1357 
1358             dest.l = static_cast<unsigned char>((c2.l / 100) * 255 + 0.5);
1359             dest.a = static_cast<unsigned char>(c2.a + 128 + 0.5);
1360             dest.b = static_cast<unsigned char>(c2.b + 128 + 0.5);
1361         }
1362 
1363         template < typename P1, typename P2 >
1364         typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::rgb_alpha>::type
1365         assign(P1& dest, const P2& src)
1366         {
1367             rgb_pixel temp;
1368             // convert target lab pixel to rgb
1369             assign_pixel_helpers::assign(temp,dest);
1370 
1371             // now assign the rgb_alpha value to our temp rgb pixel
1372             assign_pixel_helpers::assign(temp,src);
1373 
1374             // now we can just go assign the new rgb value to the
1375             // lab pixel
1376             assign_pixel_helpers::assign(dest,temp);
1377         }
1378 
1379         template < typename P1, typename P2 >
1380         typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::hsi>::type
1381         assign(P1& dest, const P2& src)
1382         {
1383             rgb_pixel temp;
1384 
1385             // convert hsi value to our temp rgb pixel
1386             assign_pixel_helpers::assign(temp,src);
1387 
1388             // now we can just go assign the new rgb value to the
1389             // lab pixel
1390             assign_pixel_helpers::assign(dest,temp);
1391         }
1392     }
1393 
1394     // -----------------------------
1395 
1396     template < typename P1, typename P2 >
1397     inline void assign_pixel (
1398         P1& dest,
1399         const P2& src
1400     ) { assign_pixel_helpers::assign(dest,src); }
1401 
1402 // ----------------------------------------------------------------------------------------
1403 
1404     template <
1405         typename P,
1406         typename T
1407         >
1408     inline typename enable_if_c<pixel_traits<P>::grayscale>::type assign_pixel_intensity_helper (
1409         P& dest,
1410         const T& new_intensity
1411     )
1412     {
1413         assign_pixel(dest, new_intensity);
1414     }
1415 
1416     template <
1417         typename P,
1418         typename T
1419         >
1420     inline typename enable_if_c<pixel_traits<P>::grayscale == false &&
1421                                 pixel_traits<P>::has_alpha>::type assign_pixel_intensity_helper (
1422         P& dest,
1423         const T& new_intensity
1424     )
1425     {
1426         hsi_pixel p;
1427         const unsigned long old_alpha = dest.alpha;
1428         dest.alpha = 255;
1429         rgb_pixel temp;
1430         assign_pixel(temp, dest); // put dest into an rgb_pixel to avoid the somewhat complicated assign_pixel(hsi,rgb_alpha).
1431         assign_pixel(p,temp);
1432         assign_pixel(p.i, new_intensity);
1433         assign_pixel(dest,p);
1434         dest.alpha = old_alpha;
1435     }
1436 
1437     template <
1438         typename P,
1439         typename T
1440         >
1441     inline typename enable_if_c<pixel_traits<P>::grayscale == false &&
1442                                 pixel_traits<P>::has_alpha == false>::type assign_pixel_intensity_helper (
1443         P& dest,
1444         const T& new_intensity
1445     )
1446     {
1447         hsi_pixel p;
1448         assign_pixel(p,dest);
1449         assign_pixel(p.i, new_intensity);
1450         assign_pixel(dest,p);
1451     }
1452 
1453     template <
1454         typename P,
1455         typename T
1456         >
1457     inline void assign_pixel_intensity (
1458         P& dest,
1459         const T& new_intensity
1460     )
1461     {
1462         assign_pixel_intensity_helper(dest, new_intensity);
1463     }
1464 
1465 // ----------------------------------------------------------------------------------------
1466 
1467     template <
1468         typename P
1469         >
1470     inline typename enable_if_c<pixel_traits<P>::grayscale, P>::type get_pixel_intensity_helper (
1471         const P& src
1472     )
1473     {
1474         return src;
1475     }
1476 
1477     template <
1478         typename P
1479         >
1480     inline typename enable_if_c<pixel_traits<P>::grayscale == false&&
1481                                 pixel_traits<P>::has_alpha,
1482                                 typename pixel_traits<P>::basic_pixel_type>::type get_pixel_intensity_helper (
1483         const P& src
1484     )
1485     {
1486         P temp = src;
1487         temp.alpha = 255;
1488         typename pixel_traits<P>::basic_pixel_type p;
1489         assign_pixel(p,temp);
1490         return p;
1491     }
1492 
1493     template <
1494         typename P
1495         >
1496     inline typename enable_if_c<pixel_traits<P>::grayscale == false&&
1497                                 pixel_traits<P>::has_alpha == false,
1498                                 typename pixel_traits<P>::basic_pixel_type>::type get_pixel_intensity_helper (
1499         const P& src
1500     )
1501     {
1502         typename pixel_traits<P>::basic_pixel_type p;
1503         assign_pixel(p,src);
1504         return p;
1505     }
1506 
1507     template <
1508         typename P
1509         >
1510     inline typename pixel_traits<P>::basic_pixel_type get_pixel_intensity (
1511         const P& src
1512     )
1513     {
1514         return get_pixel_intensity_helper(src);
1515     }
1516 
1517 // ----------------------------------------------------------------------------------------
1518 // ----------------------------------------------------------------------------------------
1519 // ----------------------------------------------------------------------------------------
1520 
1521     inline void serialize (
1522         const rgb_alpha_pixel& item,
1523         std::ostream& out
1524     )
1525     {
1526         try
1527         {
1528             serialize(item.red,out);
1529             serialize(item.green,out);
1530             serialize(item.blue,out);
1531             serialize(item.alpha,out);
1532         }
1533         catch (serialization_error& e)
1534         {
1535             throw serialization_error(e.info + "\n   while serializing object of type rgb_alpha_pixel");
1536         }
1537     }
1538 
1539 // ----------------------------------------------------------------------------------------
1540 
1541     inline void deserialize (
1542         rgb_alpha_pixel& item,
1543         std::istream& in
1544     )
1545     {
1546         try
1547         {
1548             deserialize(item.red,in);
1549             deserialize(item.green,in);
1550             deserialize(item.blue,in);
1551             deserialize(item.alpha,in);
1552         }
1553         catch (serialization_error& e)
1554         {
1555             throw serialization_error(e.info + "\n   while deserializing object of type rgb_alpha_pixel");
1556         }
1557     }
1558 
1559 // ----------------------------------------------------------------------------------------
1560 
1561     inline void serialize (
1562         const rgb_pixel& item,
1563         std::ostream& out
1564     )
1565     {
1566         try
1567         {
1568             serialize(item.red,out);
1569             serialize(item.green,out);
1570             serialize(item.blue,out);
1571         }
1572         catch (serialization_error& e)
1573         {
1574             throw serialization_error(e.info + "\n   while serializing object of type rgb_pixel");
1575         }
1576     }
1577 
1578 // ----------------------------------------------------------------------------------------
1579 
1580     inline void deserialize (
1581         rgb_pixel& item,
1582         std::istream& in
1583     )
1584     {
1585         try
1586         {
1587             deserialize(item.red,in);
1588             deserialize(item.green,in);
1589             deserialize(item.blue,in);
1590         }
1591         catch (serialization_error& e)
1592         {
1593             throw serialization_error(e.info + "\n   while deserializing object of type rgb_pixel");
1594         }
1595     }
1596 
1597 // ----------------------------------------------------------------------------------------
1598 
1599     inline void serialize (
1600         const bgr_pixel& item,
1601         std::ostream& out
1602     )
1603     {
1604         try
1605         {
1606             serialize(item.blue,out);
1607             serialize(item.green,out);
1608             serialize(item.red,out);
1609         }
1610         catch (serialization_error& e)
1611         {
1612             throw serialization_error(e.info + "\n   while serializing object of type bgr_pixel");
1613         }
1614     }
1615 
1616 // ----------------------------------------------------------------------------------------
1617 
1618     inline void deserialize (
1619         bgr_pixel& item,
1620         std::istream& in
1621     )
1622     {
1623         try
1624         {
1625             deserialize(item.blue,in);
1626             deserialize(item.green,in);
1627             deserialize(item.red,in);
1628         }
1629         catch (serialization_error& e)
1630         {
1631             throw serialization_error(e.info + "\n   while deserializing object of type bgr_pixel");
1632         }
1633     }
1634 
1635 // ----------------------------------------------------------------------------------------
1636 
1637     inline void serialize (
1638         const hsi_pixel& item,
1639         std::ostream& out
1640     )
1641     {
1642         try
1643         {
1644             serialize(item.h,out);
1645             serialize(item.s,out);
1646             serialize(item.i,out);
1647         }
1648         catch (serialization_error& e)
1649         {
1650             throw serialization_error(e.info + "\n   while serializing object of type hsi_pixel");
1651         }
1652     }
1653 
1654 // ----------------------------------------------------------------------------------------
1655 
1656     inline void deserialize (
1657         hsi_pixel& item,
1658         std::istream& in
1659     )
1660     {
1661         try
1662         {
1663             deserialize(item.h,in);
1664             deserialize(item.s,in);
1665             deserialize(item.i,in);
1666         }
1667         catch (serialization_error& e)
1668         {
1669             throw serialization_error(e.info + "\n   while deserializing object of type hsi_pixel");
1670         }
1671     }
1672 
1673 // ----------------------------------------------------------------------------------------
1674 
1675     inline void serialize (
1676             const lab_pixel& item,
1677             std::ostream& out
1678     )
1679     {
1680         try
1681         {
1682             serialize(item.l,out);
1683             serialize(item.a,out);
1684             serialize(item.b,out);
1685         }
1686         catch (serialization_error& e)
1687         {
1688             throw serialization_error(e.info + "\n   while serializing object of type lab_pixel");
1689         }
1690     }
1691 
1692 // ----------------------------------------------------------------------------------------
1693 
1694     inline void deserialize (
1695             lab_pixel& item,
1696             std::istream& in
1697     )
1698     {
1699         try
1700         {
1701             deserialize(item.l,in);
1702             deserialize(item.a,in);
1703             deserialize(item.b,in);
1704         }
1705         catch (serialization_error& e)
1706         {
1707             throw serialization_error(e.info + "\n   while deserializing object of type lab_pixel");
1708         }
1709     }
1710 
1711 // ----------------------------------------------------------------------------------------
1712 
1713 }
1714 
1715 #endif // DLIB_PIXEl_
1716 
1717