diff options
Diffstat (limited to 'ml/dlib/dlib/pixel.h')
-rw-r--r-- | ml/dlib/dlib/pixel.h | 1649 |
1 files changed, 1649 insertions, 0 deletions
diff --git a/ml/dlib/dlib/pixel.h b/ml/dlib/dlib/pixel.h new file mode 100644 index 00000000..50ead2c3 --- /dev/null +++ b/ml/dlib/dlib/pixel.h @@ -0,0 +1,1649 @@ +// Copyright (C) 2006 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_PIXEl_ +#define DLIB_PIXEl_ + +#include <iostream> +#include "serialize.h" +#include <cmath> +#include "algs.h" +#include "uintn.h" +#include <limits> +#include <complex> +#include "enable_if.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + /*! + This file contains definitions of pixel objects and related classes and + functionality. + !*/ + +// ---------------------------------------------------------------------------------------- + + template <typename T> + struct pixel_traits; + /*! + WHAT THIS OBJECT REPRESENTS + As the name implies, this is a traits class for pixel types. + It defines the properties of a pixel. + + This traits class will define the following public static members: + - bool grayscale + - bool rgb + - bool rgb_alpha + - bool hsi + - bool lab + + - bool has_alpha + + - long num + + - basic_pixel_type + - basic_pixel_type min() + - basic_pixel_type max() + - is_unsigned + + The above public constants are subject to the following constraints: + - only one of grayscale, rgb, rgb_alpha, hsi or lab is true + - if (rgb == true) then + - The type T will be a struct with 3 public members of type + unsigned char named "red" "green" and "blue". + - This type of pixel represents the RGB color space. + - num == 3 + - has_alpha == false + - basic_pixel_type == unsigned char + - min() == 0 + - max() == 255 + - is_unsigned == true + - if (rgb_alpha == true) then + - The type T will be a struct with 4 public members of type + unsigned char named "red" "green" "blue" and "alpha". + - This type of pixel represents the RGB color space with + an alpha channel where an alpha of 0 represents a pixel + that is totally transparent and 255 represents a pixel + with maximum opacity. + - num == 4 + - has_alpha == true + - basic_pixel_type == unsigned char + - min() == 0 + - max() == 255 + - is_unsigned == true + - else if (hsi == true) then + - The type T will be a struct with 3 public members of type + unsigned char named "h" "s" and "i". + - This type of pixel represents the HSI color space. + - num == 3 + - has_alpha == false + - basic_pixel_type == unsigned char + - min() == 0 + - max() == 255 + - is_unsigned == true + - else if (lab == true) then + - The type T will be a struct with 3 public members of type + unsigned char named "l" "a" and "b". + - This type of pixel represents the Lab color space. + - num == 3 + - has_alpha == false + - basic_pixel_type == unsigned char + - min() == 0 + - max() == 255 + - is_unsigned == true + - else + - grayscale == true + - This type of pixel represents a grayscale color space. T + will be some kind of basic scalar type such as unsigned int. + - num == 1 + - has_alpha == false + - basic_pixel_type == T + - min() == the minimum obtainable value of objects of type T + - max() == the maximum obtainable value of objects of type T + - is_unsigned is true if min() == 0 and false otherwise + !*/ + +// ---------------------------------------------------------------------------------------- + + struct rgb_pixel + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple struct that represents an RGB colored graphical pixel. + !*/ + + rgb_pixel ( + ) {} + + rgb_pixel ( + unsigned char red_, + unsigned char green_, + unsigned char blue_ + ) : red(red_), green(green_), blue(blue_) {} + + unsigned char red; + unsigned char green; + unsigned char blue; + }; + +// ---------------------------------------------------------------------------------------- + + struct bgr_pixel + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple struct that represents an BGR colored graphical pixel. + (the reason it exists in addition to the rgb_pixel is so you can lay + it down on top of a memory region that organizes its color data in the + BGR format and still be able to read it) + !*/ + + bgr_pixel ( + ) {} + + bgr_pixel ( + unsigned char blue_, + unsigned char green_, + unsigned char red_ + ) : blue(blue_), green(green_), red(red_) {} + + unsigned char blue; + unsigned char green; + unsigned char red; + }; + +// ---------------------------------------------------------------------------------------- + + struct rgb_alpha_pixel + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple struct that represents an RGB colored graphical pixel + with an alpha channel. + !*/ + + rgb_alpha_pixel ( + ) {} + + rgb_alpha_pixel ( + unsigned char red_, + unsigned char green_, + unsigned char blue_, + unsigned char alpha_ + ) : red(red_), green(green_), blue(blue_), alpha(alpha_) {} + + unsigned char red; + unsigned char green; + unsigned char blue; + unsigned char alpha; + }; + +// ---------------------------------------------------------------------------------------- + + struct hsi_pixel + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple struct that represents an HSI colored graphical pixel. + !*/ + + hsi_pixel ( + ) {} + + hsi_pixel ( + unsigned char h_, + unsigned char s_, + unsigned char i_ + ) : h(h_), s(s_), i(i_) {} + + unsigned char h; + unsigned char s; + unsigned char i; + }; + // ---------------------------------------------------------------------------------------- + + struct lab_pixel + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple struct that represents an Lab colored graphical pixel. + !*/ + + lab_pixel ( + ) {} + + lab_pixel ( + unsigned char l_, + unsigned char a_, + unsigned char b_ + ) : l(l_), a(a_), b(b_) {} + + unsigned char l; + unsigned char a; + unsigned char b; + }; + +// ---------------------------------------------------------------------------------------- + + template < + typename P1, + typename P2 + > + inline void assign_pixel ( + P1& dest, + const P2& src + ); + /*! + requires + - pixel_traits<P1> must be defined + - pixel_traits<P2> must be defined + ensures + - if (P1 and P2 are the same type of pixel) then + - simply copies the value of src into dest. In other words, + dest will be identical to src after this function returns. + - else if (P1 and P2 are not the same type of pixel) then + - assigns pixel src to pixel dest and does any necessary color space + conversions. + - When converting from a grayscale color space with more than 255 values the + pixel intensity is saturated at pixel_traits<P1>::max() or pixel_traits<P1>::min() + as appropriate. + - if (the dest pixel has an alpha channel and the src pixel doesn't) then + - #dest.alpha == 255 + - else if (the src pixel has an alpha channel but the dest pixel doesn't) then + - #dest == the original dest value blended with the src value according + to the alpha channel in src. + (i.e. #dest == src*(alpha/255) + dest*(1-alpha/255)) + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename P + > + inline typename pixel_traits<P>::basic_pixel_type get_pixel_intensity ( + const P& src + ); + /*! + requires + - pixel_traits<P> must be defined + ensures + - if (pixel_traits<P>::grayscale == true) then + - returns src + - else + - converts src to grayscale and returns the resulting value. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename P, + typename T + > + inline void assign_pixel_intensity ( + P& dest, + const T& new_intensity + ); + /*! + requires + - pixel_traits<P> must be defined + - pixel_traits<T> must be defined + ensures + - This function changes the intensity of the dest pixel. So if the pixel in + question is a grayscale pixel then it simply assigns that pixel with the + value of get_pixel_intensity(new_intensity). However, if the pixel is not + a grayscale pixel then it converts the pixel to the HSI color space and sets + the I channel to the given intensity and then converts this HSI value back to + the original pixel's color space. + - Note that we don't necessarily have #get_pixel_intensity(dest) == get_pixel_intensity(new_intensity) + due to vagaries of how converting to and from HSI works out. + - if (the dest pixel has an alpha channel) then + - #dest.alpha == dest.alpha + !*/ + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const rgb_pixel& item, + std::ostream& out + ); + /*! + provides serialization support for the rgb_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + rgb_pixel& item, + std::istream& in + ); + /*! + provides deserialization support for the rgb_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const bgr_pixel& item, + std::ostream& out + ); + /*! + provides serialization support for the bgr_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + bgr_pixel& item, + std::istream& in + ); + /*! + provides deserialization support for the bgr_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const rgb_alpha_pixel& item, + std::ostream& out + ); + /*! + provides serialization support for the rgb_alpha_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + rgb_alpha_pixel& item, + std::istream& in + ); + /*! + provides deserialization support for the rgb_alpha_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const hsi_pixel& item, + std::ostream& out + ); + /*! + provides serialization support for the hsi_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const lab_pixel& item, + std::ostream& out + ); + /*! + provides serialization support for the lab_pixel struct + !*/ + + +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + hsi_pixel& item, + std::istream& in + ); + /*! + provides deserialization support for the hsi_pixel struct + !*/ +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + lab_pixel& item, + std::istream& in + ); + /*! + provides deserialization support for the lab_pixel struct + !*/ + +// ---------------------------------------------------------------------------------------- + + template <> + struct pixel_traits<rgb_pixel> + { + constexpr static bool rgb = true; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = false; + constexpr static bool hsi = false; + constexpr static bool lab = false; + enum { num = 3}; + typedef unsigned char basic_pixel_type; + static basic_pixel_type min() { return 0;} + static basic_pixel_type max() { return 255;} + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = false; + }; + +// ---------------------------------------------------------------------------------------- + + template <> + struct pixel_traits<bgr_pixel> + { + constexpr static bool rgb = true; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = false; + constexpr static bool hsi = false; + constexpr static bool lab = false; + constexpr static long num = 3; + typedef unsigned char basic_pixel_type; + static basic_pixel_type min() { return 0;} + static basic_pixel_type max() { return 255;} + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = false; + }; + +// ---------------------------------------------------------------------------------------- + + template <> + struct pixel_traits<rgb_alpha_pixel> + { + constexpr static bool rgb = false; + constexpr static bool rgb_alpha = true; + constexpr static bool grayscale = false; + constexpr static bool hsi = false; + constexpr static bool lab = false; + constexpr static long num = 4; + typedef unsigned char basic_pixel_type; + static basic_pixel_type min() { return 0;} + static basic_pixel_type max() { return 255;} + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = true; + }; + +// ---------------------------------------------------------------------------------------- + + + template <> + struct pixel_traits<hsi_pixel> + { + constexpr static bool rgb = false; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = false; + constexpr static bool hsi = true; + constexpr static bool lab = false; + constexpr static long num = 3; + typedef unsigned char basic_pixel_type; + static basic_pixel_type min() { return 0;} + static basic_pixel_type max() { return 255;} + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = false; + }; + +// ---------------------------------------------------------------------------------------- + + + template <> + struct pixel_traits<lab_pixel> + { + constexpr static bool rgb = false; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = false; + constexpr static bool hsi = false; + constexpr static bool lab = true; + constexpr static long num = 3; + typedef unsigned char basic_pixel_type; + static basic_pixel_type min() { return 0;} + static basic_pixel_type max() { return 255;} + constexpr static bool is_unsigned = true; + constexpr static bool has_alpha = false; + }; + +// ---------------------------------------------------------------------------------------- + + template <typename T> + struct grayscale_pixel_traits + { + constexpr static bool rgb = false; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = true; + constexpr static bool hsi = false; + constexpr static bool lab = false; + constexpr static long num = 1; + constexpr static bool has_alpha = false; + typedef T basic_pixel_type; + static basic_pixel_type min() { return std::numeric_limits<T>::min();} + static basic_pixel_type max() { return std::numeric_limits<T>::max();} + constexpr static bool is_unsigned = is_unsigned_type<T>::value; + }; + + template <> struct pixel_traits<unsigned char> : public grayscale_pixel_traits<unsigned char> {}; + template <> struct pixel_traits<unsigned short> : public grayscale_pixel_traits<unsigned short> {}; + template <> struct pixel_traits<unsigned int> : public grayscale_pixel_traits<unsigned int> {}; + template <> struct pixel_traits<unsigned long> : public grayscale_pixel_traits<unsigned long> {}; + + template <> struct pixel_traits<char> : public grayscale_pixel_traits<char> {}; + template <> struct pixel_traits<signed char> : public grayscale_pixel_traits<signed char> {}; + template <> struct pixel_traits<short> : public grayscale_pixel_traits<short> {}; + template <> struct pixel_traits<int> : public grayscale_pixel_traits<int> {}; + template <> struct pixel_traits<long> : public grayscale_pixel_traits<long> {}; + + template <> struct pixel_traits<int64> : public grayscale_pixel_traits<int64> {}; + template <> struct pixel_traits<uint64> : public grayscale_pixel_traits<uint64> {}; + +// ---------------------------------------------------------------------------------------- + + template <typename T> + struct float_grayscale_pixel_traits + { + constexpr static bool rgb = false; + constexpr static bool rgb_alpha = false; + constexpr static bool grayscale = true; + constexpr static bool hsi = false; + constexpr static bool lab = false; + constexpr static long num = 1; + constexpr static bool has_alpha = false; + typedef T basic_pixel_type; + static basic_pixel_type min() { return -std::numeric_limits<T>::max();} + static basic_pixel_type max() { return std::numeric_limits<T>::max();} + constexpr static bool is_unsigned = false; + }; + + template <> struct pixel_traits<float> : public float_grayscale_pixel_traits<float> {}; + template <> struct pixel_traits<double> : public float_grayscale_pixel_traits<double> {}; + template <> struct pixel_traits<long double> : public float_grayscale_pixel_traits<long double> {}; + + // These are here mainly so you can easily copy images into complex arrays. This is + // useful when you want to do a FFT on an image or some similar operation. + template <> struct pixel_traits<std::complex<float> > : public float_grayscale_pixel_traits<float> {}; + template <> struct pixel_traits<std::complex<double> > : public float_grayscale_pixel_traits<double> {}; + template <> struct pixel_traits<std::complex<long double> > : public float_grayscale_pixel_traits<long double> {}; + +// ---------------------------------------------------------------------------------------- + + // The following is a bunch of conversion stuff for the assign_pixel function. + + namespace assign_pixel_helpers + { + + // ----------------------------- + // all the same kind + + template < typename P > + typename enable_if_c<pixel_traits<P>::grayscale>::type + assign(P& dest, const P& src) + { + dest = src; + } + + // ----------------------------- + + template <typename T> + typename unsigned_type<T>::type make_unsigned ( + const T& val + ) { return static_cast<typename unsigned_type<T>::type>(val); } + + inline float make_unsigned(const float& val) { return val; } + inline double make_unsigned(const double& val) { return val; } + inline long double make_unsigned(const long double& val) { return val; } + + + template <typename T, typename P> + typename enable_if_c<pixel_traits<T>::is_unsigned == pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max ( + const P& p + ) + /*! + ensures + - returns true if p is <= max value of T + !*/ + { + return p <= pixel_traits<T>::max(); + } + + template <typename T, typename P> + typename enable_if_c<pixel_traits<T>::is_unsigned && !pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max ( + const P& p + ) + { + if (p <= 0) + return true; + else if (make_unsigned(p) <= pixel_traits<T>::max()) + return true; + else + return false; + } + + template <typename T, typename P> + typename enable_if_c<!pixel_traits<T>::is_unsigned && pixel_traits<P>::is_unsigned, bool>::type less_or_equal_to_max ( + const P& p + ) + { + return p <= make_unsigned(pixel_traits<T>::max()); + } + + // ----------------------------- + + template <typename T, typename P> + typename enable_if_c<pixel_traits<P>::is_unsigned, bool >::type greater_or_equal_to_min ( + const P& + ) { return true; } + /*! + ensures + - returns true if p is >= min value of T + !*/ + + template <typename T, typename P> + typename enable_if_c<!pixel_traits<P>::is_unsigned && pixel_traits<T>::is_unsigned, bool >::type greater_or_equal_to_min ( + const P& p + ) + { + return p >= 0; + } + + template <typename T, typename P> + typename enable_if_c<!pixel_traits<P>::is_unsigned && !pixel_traits<T>::is_unsigned, bool >::type greater_or_equal_to_min ( + const P& p + ) + { + return p >= pixel_traits<T>::min(); + } + // ----------------------------- + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::grayscale>::type + assign(P1& dest, const P2& src) + { + /* + The reason for these weird comparison functions is to avoid getting compiler + warnings about comparing signed types to unsigned and stuff like that. + */ + + if (less_or_equal_to_max<P1>(src)) + if (greater_or_equal_to_min<P1>(src)) + dest = static_cast<P1>(src); + else + dest = pixel_traits<P1>::min(); + else + dest = pixel_traits<P1>::max(); + } + + // ----------------------------- + // ----------------------------- + // ----------------------------- + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::rgb>::type + assign(P1& dest, const P2& src) + { + dest.red = src.red; + dest.green = src.green; + dest.blue = src.blue; + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::rgb_alpha>::type + assign(P1& dest, const P2& src) + { + dest.red = src.red; + dest.green = src.green; + dest.blue = src.blue; + dest.alpha = src.alpha; + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::hsi>::type + assign(P1& dest, const P2& src) + { + dest.h = src.h; + dest.s = src.s; + dest.i = src.i; + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::lab>::type + assign(P1& dest, const P2& src) + { + dest.l = src.l; + dest.a = src.a; + dest.b = src.b; + } + + // ----------------------------- + // dest is a grayscale + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::rgb>::type + assign(P1& dest, const P2& src) + { + const unsigned int temp = ((static_cast<unsigned int>(src.red) + + static_cast<unsigned int>(src.green) + + static_cast<unsigned int>(src.blue))/3); + assign_pixel(dest, temp); + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::rgb_alpha>::type + assign(P1& dest, const P2& src) + { + + const unsigned char avg = static_cast<unsigned char>((static_cast<unsigned int>(src.red) + + static_cast<unsigned int>(src.green) + + static_cast<unsigned int>(src.blue))/3); + + if (src.alpha == 255) + { + assign_pixel(dest, avg); + } + else + { + // perform this assignment using fixed point arithmetic: + // dest = src*(alpha/255) + dest*(1 - alpha/255); + // dest = src*(alpha/255) + dest*1 - dest*(alpha/255); + // dest = dest*1 + src*(alpha/255) - dest*(alpha/255); + // dest = dest*1 + (src - dest)*(alpha/255); + // dest += (src - dest)*(alpha/255); + + int temp = avg; + // copy dest into dest_copy using assign_pixel to avoid potential + // warnings about implicit float to int warnings. + int dest_copy; + assign_pixel(dest_copy, dest); + + temp -= dest_copy; + + temp *= src.alpha; + + temp /= 255; + + assign_pixel(dest, temp+dest_copy); + } + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::hsi>::type + assign(P1& dest, const P2& src) + { + assign_pixel(dest, src.i); + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::grayscale && pixel_traits<P2>::lab>::type + assign(P1& dest, const P2& src) + { + assign_pixel(dest, src.l); + } + + + // ----------------------------- + + struct HSL + { + double h; + double s; + double l; + }; + + struct COLOUR + { + double r; + double g; + double b; + }; + + /* + I found this excellent bit of code for dealing with HSL spaces at + http://local.wasp.uwa.edu.au/~pbourke/colour/hsl/ + */ + /* + Calculate HSL from RGB + Hue is in degrees + Lightness is between 0 and 1 + Saturation is between 0 and 1 + */ + inline HSL RGB2HSL(COLOUR c1) + { + double themin,themax,delta; + HSL c2; + using namespace std; + + themin = std::min(c1.r,std::min(c1.g,c1.b)); + themax = std::max(c1.r,std::max(c1.g,c1.b)); + delta = themax - themin; + c2.l = (themin + themax) / 2; + c2.s = 0; + if (c2.l > 0 && c2.l < 1) + c2.s = delta / (c2.l < 0.5 ? (2*c2.l) : (2-2*c2.l)); + c2.h = 0; + if (delta > 0) { + if (themax == c1.r && themax != c1.g) + c2.h += (c1.g - c1.b) / delta; + if (themax == c1.g && themax != c1.b) + c2.h += (2 + (c1.b - c1.r) / delta); + if (themax == c1.b && themax != c1.r) + c2.h += (4 + (c1.r - c1.g) / delta); + c2.h *= 60; + } + return(c2); + } + + /* + Calculate RGB from HSL, reverse of RGB2HSL() + Hue is in degrees + Lightness is between 0 and 1 + Saturation is between 0 and 1 + */ + inline COLOUR HSL2RGB(HSL c1) + { + COLOUR c2,sat,ctmp; + using namespace std; + + if (c1.h < 120) { + sat.r = (120 - c1.h) / 60.0; + sat.g = c1.h / 60.0; + sat.b = 0; + } else if (c1.h < 240) { + sat.r = 0; + sat.g = (240 - c1.h) / 60.0; + sat.b = (c1.h - 120) / 60.0; + } else { + sat.r = (c1.h - 240) / 60.0; + sat.g = 0; + sat.b = (360 - c1.h) / 60.0; + } + sat.r = std::min(sat.r,1.0); + sat.g = std::min(sat.g,1.0); + sat.b = std::min(sat.b,1.0); + + ctmp.r = 2 * c1.s * sat.r + (1 - c1.s); + ctmp.g = 2 * c1.s * sat.g + (1 - c1.s); + ctmp.b = 2 * c1.s * sat.b + (1 - c1.s); + + if (c1.l < 0.5) { + c2.r = c1.l * ctmp.r; + c2.g = c1.l * ctmp.g; + c2.b = c1.l * ctmp.b; + } else { + c2.r = (1 - c1.l) * ctmp.r + 2 * c1.l - 1; + c2.g = (1 - c1.l) * ctmp.g + 2 * c1.l - 1; + c2.b = (1 - c1.l) * ctmp.b + 2 * c1.l - 1; + } + + return(c2); + } + + // ----------------------------- + + struct Lab + { + double l; + double a; + double b; + }; + /* + Calculate Lab from RGB + L is between 0 and 100 + a is between -128 and 127 + b is between -128 and 127 + RGB is between 0.0 and 1.0 + */ + inline Lab RGB2Lab(COLOUR c1) + { + Lab c2; + using namespace std; + + double var_R = c1.r; + double var_G = c1.g; + double var_B = c1.b; + + if (var_R > 0.04045) { + var_R = pow(((var_R + 0.055) / 1.055), 2.4); + } else { + var_R = var_R / 12.92; + } + + if (var_G > 0.04045) { + var_G = pow(((var_G + 0.055) / 1.055), 2.4); + } else { + var_G = var_G / 12.92; + } + + if (var_B > 0.04045) { + var_B = pow(((var_B + 0.055) / 1.055), 2.4); + } else { + var_B = var_B / 12.92; + } + + var_R = var_R * 100; + var_G = var_G * 100; + var_B = var_B * 100; + +//Observer. = 2°, Illuminant = D65 + double X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805; + double Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722; + double Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505; + + double var_X = X / 95.047; + double var_Y = Y / 100.000; + double var_Z = Z / 108.883; + + if (var_X > 0.008856) { + var_X = pow(var_X, (1.0 / 3)); + } + else { + var_X = (7.787 * var_X) + (16.0 / 116); + } + + if (var_Y > 0.008856) { + var_Y = pow(var_Y, (1.0 / 3)); + } + else { + var_Y = (7.787 * var_Y) + (16.0 / 116); + } + + if (var_Z > 0.008856) { + var_Z = pow(var_Z, (1.0 / 3)); + } + else { + var_Z = (7.787 * var_Z) + (16.0 / 116); + } + + //clamping + c2.l = max(0.0, (116.0 * var_Y) - 16); + c2.a = max(-128.0, min(127.0, 500.0 * (var_X - var_Y))); + c2.b = max(-128.0, min(127.0, 200.0 * (var_Y - var_Z))); + + return c2; + } + + /* + Calculate RGB from Lab, reverse of RGB2LAb() + L is between 0 and 100 + a is between -128 and 127 + b is between -128 and 127 + RGB is between 0.0 and 1.0 + */ + inline COLOUR Lab2RGB(Lab c1) { + COLOUR c2; + using namespace std; + + double var_Y = (c1.l + 16) / 116.0; + double var_X = (c1.a / 500.0) + var_Y; + double var_Z = var_Y - (c1.b / 200); + + if (pow(var_Y, 3) > 0.008856) { + var_Y = pow(var_Y, 3); + } else { + var_Y = (var_Y - 16.0 / 116) / 7.787; + } + + if (pow(var_X, 3) > 0.008856) { + var_X = pow(var_X, 3); + } else { + var_X = (var_X - 16.0 / 116) / 7.787; + } + + if (pow(var_Z, 3) > 0.008856) { + var_Z = pow(var_Z, 3); + } else { + var_Z = (var_Z - 16.0 / 116) / 7.787; + } + + double X = var_X * 95.047; + double Y = var_Y * 100.000; + double Z = var_Z * 108.883; + + var_X = X / 100.0; + var_Y = Y / 100.0; + var_Z = Z / 100.0; + + double var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986; + double var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415; + double var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570; + + if (var_R > 0.0031308) { + var_R = 1.055 * pow(var_R, (1 / 2.4)) - 0.055; + } else { + var_R = 12.92 * var_R; + } + + if (var_G > 0.0031308) { + var_G = 1.055 * pow(var_G, (1 / 2.4)) - 0.055; + } else { + var_G = 12.92 * var_G; + } + + if (var_B > 0.0031308) { + var_B = 1.055 * pow(var_B, (1 / 2.4)) - 0.055; + } else { + var_B = 12.92 * var_B; + } + + // clamping + c2.r = max(0.0, min(1.0, var_R)); + c2.g = max(0.0, min(1.0, var_G)); + c2.b = max(0.0, min(1.0, var_B)); + + return (c2); + } + + + // ----------------------------- + // dest is a color rgb_pixel + + template < typename P1 > + typename enable_if_c<pixel_traits<P1>::rgb>::type + assign(P1& dest, const unsigned char& src) + { + dest.red = src; + dest.green = src; + dest.blue = src; + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::grayscale>::type + assign(P1& dest, const P2& src) + { + unsigned char p; + assign_pixel(p, src); + dest.red = p; + dest.green = p; + dest.blue = p; + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::rgb_alpha>::type + assign(P1& dest, const P2& src) + { + if (src.alpha == 255) + { + dest.red = src.red; + dest.green = src.green; + dest.blue = src.blue; + } + else + { + // perform this assignment using fixed point arithmetic: + // dest = src*(alpha/255) + dest*(1 - alpha/255); + // dest = src*(alpha/255) + dest*1 - dest*(alpha/255); + // dest = dest*1 + src*(alpha/255) - dest*(alpha/255); + // dest = dest*1 + (src - dest)*(alpha/255); + // dest += (src - dest)*(alpha/255); + + unsigned int temp_r = src.red; + unsigned int temp_g = src.green; + unsigned int temp_b = src.blue; + + temp_r -= dest.red; + temp_g -= dest.green; + temp_b -= dest.blue; + + temp_r *= src.alpha; + temp_g *= src.alpha; + temp_b *= src.alpha; + + temp_r >>= 8; + temp_g >>= 8; + temp_b >>= 8; + + dest.red += static_cast<unsigned char>(temp_r&0xFF); + dest.green += static_cast<unsigned char>(temp_g&0xFF); + dest.blue += static_cast<unsigned char>(temp_b&0xFF); + } + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::hsi>::type + assign(P1& dest, const P2& src) + { + COLOUR c; + HSL h; + h.h = src.h; + h.h = h.h/255.0*360; + h.s = src.s/255.0; + h.l = src.i/255.0; + c = HSL2RGB(h); + + dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5); + dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5); + dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5); + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::rgb && pixel_traits<P2>::lab>::type + assign(P1& dest, const P2& src) + { + COLOUR c; + Lab l; + l.l = (src.l/255.0)*100; + l.a = (src.a-128.0); + l.b = (src.b-128.0); + c = Lab2RGB(l); + + dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5); + dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5); + dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5); + } + + + // ----------------------------- + // dest is a color rgb_alpha_pixel + + template < typename P1 > + typename enable_if_c<pixel_traits<P1>::rgb_alpha>::type + assign(P1& dest, const unsigned char& src) + { + dest.red = src; + dest.green = src; + dest.blue = src; + dest.alpha = 255; + } + + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::grayscale>::type + assign(P1& dest, const P2& src) + { + unsigned char p; + assign_pixel(p, src); + + dest.red = p; + dest.green = p; + dest.blue = p; + dest.alpha = 255; + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::rgb>::type + assign(P1& dest, const P2& src) + { + dest.red = src.red; + dest.green = src.green; + dest.blue = src.blue; + dest.alpha = 255; + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::hsi>::type + assign(P1& dest, const P2& src) + { + COLOUR c; + HSL h; + h.h = src.h; + h.h = h.h/255.0*360; + h.s = src.s/255.0; + h.l = src.i/255.0; + c = HSL2RGB(h); + + dest.red = static_cast<unsigned char>(c.r*255.0 + 0.5); + dest.green = static_cast<unsigned char>(c.g*255.0 + 0.5); + dest.blue = static_cast<unsigned char>(c.b*255.0 + 0.5); + dest.alpha = 255; + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::rgb_alpha && pixel_traits<P2>::lab>::type + assign(P1& dest, const P2& src) + { + COLOUR c; + Lab l; + l.l = (src.l/255.0)*100; + l.a = (src.a-128.0); + l.b = (src.b-128.0); + c = Lab2RGB(l); + + dest.red = static_cast<unsigned char>(c.r * 255 + 0.5); + dest.green = static_cast<unsigned char>(c.g * 255 + 0.5); + dest.blue = static_cast<unsigned char>(c.b * 255 + 0.5); + dest.alpha = 255; + } + // ----------------------------- + // dest is an hsi pixel + + template < typename P1> + typename enable_if_c<pixel_traits<P1>::hsi>::type + assign(P1& dest, const unsigned char& src) + { + dest.h = 0; + dest.s = 0; + dest.i = src; + } + + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::grayscale>::type + assign(P1& dest, const P2& src) + { + dest.h = 0; + dest.s = 0; + assign_pixel(dest.i, src); + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::rgb>::type + assign(P1& dest, const P2& src) + { + COLOUR c1; + HSL c2; + c1.r = src.red/255.0; + c1.g = src.green/255.0; + c1.b = src.blue/255.0; + c2 = RGB2HSL(c1); + + dest.h = static_cast<unsigned char>(c2.h/360.0*255.0 + 0.5); + dest.s = static_cast<unsigned char>(c2.s*255.0 + 0.5); + dest.i = static_cast<unsigned char>(c2.l*255.0 + 0.5); + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::rgb_alpha>::type + assign(P1& dest, const P2& src) + { + rgb_pixel temp; + // convert target hsi pixel to rgb + assign_pixel_helpers::assign(temp,dest); + + // now assign the rgb_alpha value to our temp rgb pixel + assign_pixel_helpers::assign(temp,src); + + // now we can just go assign the new rgb value to the + // hsi pixel + assign_pixel_helpers::assign(dest,temp); + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::hsi && pixel_traits<P2>::lab>::type + assign(P1& dest, const P2& src) + { + rgb_pixel temp; + // convert lab value to our temp rgb pixel + assign_pixel_helpers::assign(temp,src); + // now we can just go assign the new rgb value to the + // hsi pixel + assign_pixel_helpers::assign(dest,temp); + } + + // ----------------------------- + // dest is an lab pixel + template < typename P1> + typename enable_if_c<pixel_traits<P1>::lab>::type + assign(P1& dest, const unsigned char& src) + { + dest.a = 128; + dest.b = 128; + dest.l = src; + } + + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::grayscale>::type + assign(P1& dest, const P2& src) + { + dest.a = 128; + dest.b = 128; + assign_pixel(dest.l, src); + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::rgb>::type + assign(P1& dest, const P2& src) + { + COLOUR c1; + Lab c2; + c1.r = src.red / 255.0; + c1.g = src.green / 255.0; + c1.b = src.blue / 255.0; + c2 = RGB2Lab(c1); + + dest.l = static_cast<unsigned char>((c2.l / 100) * 255 + 0.5); + dest.a = static_cast<unsigned char>(c2.a + 128 + 0.5); + dest.b = static_cast<unsigned char>(c2.b + 128 + 0.5); + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::rgb_alpha>::type + assign(P1& dest, const P2& src) + { + rgb_pixel temp; + // convert target lab pixel to rgb + assign_pixel_helpers::assign(temp,dest); + + // now assign the rgb_alpha value to our temp rgb pixel + assign_pixel_helpers::assign(temp,src); + + // now we can just go assign the new rgb value to the + // lab pixel + assign_pixel_helpers::assign(dest,temp); + } + + template < typename P1, typename P2 > + typename enable_if_c<pixel_traits<P1>::lab && pixel_traits<P2>::hsi>::type + assign(P1& dest, const P2& src) + { + rgb_pixel temp; + + // convert hsi value to our temp rgb pixel + assign_pixel_helpers::assign(temp,src); + + // now we can just go assign the new rgb value to the + // lab pixel + assign_pixel_helpers::assign(dest,temp); + } + } + + // ----------------------------- + + template < typename P1, typename P2 > + inline void assign_pixel ( + P1& dest, + const P2& src + ) { assign_pixel_helpers::assign(dest,src); } + +// ---------------------------------------------------------------------------------------- + + template < + typename P, + typename T + > + inline typename enable_if_c<pixel_traits<P>::grayscale>::type assign_pixel_intensity_helper ( + P& dest, + const T& new_intensity + ) + { + assign_pixel(dest, new_intensity); + } + + template < + typename P, + typename T + > + inline typename enable_if_c<pixel_traits<P>::grayscale == false && + pixel_traits<P>::has_alpha>::type assign_pixel_intensity_helper ( + P& dest, + const T& new_intensity + ) + { + hsi_pixel p; + const unsigned long old_alpha = dest.alpha; + dest.alpha = 255; + rgb_pixel temp; + assign_pixel(temp, dest); // put dest into an rgb_pixel to avoid the somewhat complicated assign_pixel(hsi,rgb_alpha). + assign_pixel(p,temp); + assign_pixel(p.i, new_intensity); + assign_pixel(dest,p); + dest.alpha = old_alpha; + } + + template < + typename P, + typename T + > + inline typename enable_if_c<pixel_traits<P>::grayscale == false && + pixel_traits<P>::has_alpha == false>::type assign_pixel_intensity_helper ( + P& dest, + const T& new_intensity + ) + { + hsi_pixel p; + assign_pixel(p,dest); + assign_pixel(p.i, new_intensity); + assign_pixel(dest,p); + } + + template < + typename P, + typename T + > + inline void assign_pixel_intensity ( + P& dest, + const T& new_intensity + ) + { + assign_pixel_intensity_helper(dest, new_intensity); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename P + > + inline typename enable_if_c<pixel_traits<P>::grayscale, P>::type get_pixel_intensity_helper ( + const P& src + ) + { + return src; + } + + template < + typename P + > + inline typename enable_if_c<pixel_traits<P>::grayscale == false&& + pixel_traits<P>::has_alpha, + typename pixel_traits<P>::basic_pixel_type>::type get_pixel_intensity_helper ( + const P& src + ) + { + P temp = src; + temp.alpha = 255; + typename pixel_traits<P>::basic_pixel_type p; + assign_pixel(p,temp); + return p; + } + + template < + typename P + > + inline typename enable_if_c<pixel_traits<P>::grayscale == false&& + pixel_traits<P>::has_alpha == false, + typename pixel_traits<P>::basic_pixel_type>::type get_pixel_intensity_helper ( + const P& src + ) + { + typename pixel_traits<P>::basic_pixel_type p; + assign_pixel(p,src); + return p; + } + + template < + typename P + > + inline typename pixel_traits<P>::basic_pixel_type get_pixel_intensity ( + const P& src + ) + { + return get_pixel_intensity_helper(src); + } + +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const rgb_alpha_pixel& item, + std::ostream& out + ) + { + try + { + serialize(item.red,out); + serialize(item.green,out); + serialize(item.blue,out); + serialize(item.alpha,out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type rgb_alpha_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + rgb_alpha_pixel& item, + std::istream& in + ) + { + try + { + deserialize(item.red,in); + deserialize(item.green,in); + deserialize(item.blue,in); + deserialize(item.alpha,in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type rgb_alpha_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const rgb_pixel& item, + std::ostream& out + ) + { + try + { + serialize(item.red,out); + serialize(item.green,out); + serialize(item.blue,out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type rgb_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + rgb_pixel& item, + std::istream& in + ) + { + try + { + deserialize(item.red,in); + deserialize(item.green,in); + deserialize(item.blue,in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type rgb_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const bgr_pixel& item, + std::ostream& out + ) + { + try + { + serialize(item.blue,out); + serialize(item.green,out); + serialize(item.red,out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type bgr_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + bgr_pixel& item, + std::istream& in + ) + { + try + { + deserialize(item.blue,in); + deserialize(item.green,in); + deserialize(item.red,in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type bgr_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const hsi_pixel& item, + std::ostream& out + ) + { + try + { + serialize(item.h,out); + serialize(item.s,out); + serialize(item.i,out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type hsi_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + hsi_pixel& item, + std::istream& in + ) + { + try + { + deserialize(item.h,in); + deserialize(item.s,in); + deserialize(item.i,in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type hsi_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline void serialize ( + const lab_pixel& item, + std::ostream& out + ) + { + try + { + serialize(item.l,out); + serialize(item.a,out); + serialize(item.b,out); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while serializing object of type lab_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + + inline void deserialize ( + lab_pixel& item, + std::istream& in + ) + { + try + { + deserialize(item.l,in); + deserialize(item.a,in); + deserialize(item.b,in); + } + catch (serialization_error& e) + { + throw serialization_error(e.info + "\n while deserializing object of type lab_pixel"); + } + } + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_PIXEl_ + |