264 lines
6.6 KiB
C++
264 lines
6.6 KiB
C++
|
// Copyright 2007 Christian Henning.
|
||
|
// Distributed under the Boost Software License, Version 1.0. (See
|
||
|
// accompanying file LICENSE_1_0.txt or copy at
|
||
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||
|
|
||
|
/*************************************************************************************************/
|
||
|
|
||
|
#ifndef GIL_HSL_H
|
||
|
#define GIL_HSL_H
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||
|
/// \file
|
||
|
/// \brief Support for HSL color space
|
||
|
/// \author Christian Henning \n
|
||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include <boost/gil/gil_all.hpp>
|
||
|
|
||
|
namespace boost { namespace gil {
|
||
|
|
||
|
/// \addtogroup ColorNameModel
|
||
|
/// \{
|
||
|
namespace hsl_color_space
|
||
|
{
|
||
|
/// \brief Hue
|
||
|
struct hue_t {};
|
||
|
/// \brief Saturation
|
||
|
struct saturation_t {};
|
||
|
/// \brief Lightness
|
||
|
struct lightness_t {};
|
||
|
}
|
||
|
/// \}
|
||
|
|
||
|
/// \ingroup ColorSpaceModel
|
||
|
typedef mpl::vector3< hsl_color_space::hue_t
|
||
|
, hsl_color_space::saturation_t
|
||
|
, hsl_color_space::lightness_t
|
||
|
> hsl_t;
|
||
|
|
||
|
/// \ingroup LayoutModel
|
||
|
typedef layout<hsl_t> hsl_layout_t;
|
||
|
|
||
|
|
||
|
GIL_DEFINE_ALL_TYPEDEFS( 32f, hsl );
|
||
|
|
||
|
/// \ingroup ColorConvert
|
||
|
/// \brief RGB to HSL
|
||
|
template <>
|
||
|
struct default_color_converter_impl< rgb_t, hsl_t >
|
||
|
{
|
||
|
template <typename P1, typename P2>
|
||
|
void operator()( const P1& src, P2& dst ) const
|
||
|
{
|
||
|
using namespace hsl_color_space;
|
||
|
|
||
|
// only bits32f for hsl is supported
|
||
|
bits32f temp_red = channel_convert<bits32f>( get_color( src, red_t() ));
|
||
|
bits32f temp_green = channel_convert<bits32f>( get_color( src, green_t() ));
|
||
|
bits32f temp_blue = channel_convert<bits32f>( get_color( src, blue_t() ));
|
||
|
|
||
|
bits32f hue, saturation, lightness;
|
||
|
|
||
|
bits32f min_color = std::min( temp_red, std::min( temp_green, temp_blue ));
|
||
|
bits32f max_color = std::max( temp_red, std::max( temp_green, temp_blue ));
|
||
|
|
||
|
if ( max_color - min_color < 0.001 )
|
||
|
{
|
||
|
// rgb color is gray
|
||
|
|
||
|
hue = 0.f;
|
||
|
saturation = 0.f;
|
||
|
|
||
|
// doesn't matter which rgb channel we use.
|
||
|
lightness = temp_red;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
bits32f diff = max_color - min_color;
|
||
|
|
||
|
// lightness calculation
|
||
|
|
||
|
lightness = ( min_color + max_color ) / 2.f;
|
||
|
|
||
|
// saturation calculation
|
||
|
|
||
|
if( lightness < 0.5f )
|
||
|
{
|
||
|
saturation = diff
|
||
|
/ ( min_color + max_color );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
saturation = ( max_color - min_color )
|
||
|
/ ( 2.f - diff );
|
||
|
|
||
|
}
|
||
|
|
||
|
// hue calculation
|
||
|
if( std::abs( max_color - temp_red ) < 0.0001f )
|
||
|
{
|
||
|
// max_color is red
|
||
|
hue = ( temp_green - temp_blue )
|
||
|
/ diff;
|
||
|
|
||
|
}
|
||
|
else if( std::abs( max_color - temp_green) < 0.0001f )
|
||
|
{
|
||
|
// max_color is green
|
||
|
// 2.0 + (b - r) / (maxColor - minColor)
|
||
|
hue = 2.f
|
||
|
+ ( temp_blue - temp_red )
|
||
|
/ diff;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// max_color is blue
|
||
|
// 4.0 + (r - g) / (maxColor - minColor)
|
||
|
hue = 4.f
|
||
|
+ ( temp_red - temp_green )
|
||
|
/ diff;
|
||
|
}
|
||
|
|
||
|
hue /= 6.f;
|
||
|
|
||
|
if( hue < 0.f )
|
||
|
{
|
||
|
hue += 1.f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
get_color( dst,hue_t() ) = hue;
|
||
|
get_color( dst,saturation_t() ) = saturation;
|
||
|
get_color( dst,lightness_t() ) = lightness;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/// \ingroup ColorConvert
|
||
|
/// \brief HSL to RGB
|
||
|
template <>
|
||
|
struct default_color_converter_impl<hsl_t,rgb_t>
|
||
|
{
|
||
|
template <typename P1, typename P2>
|
||
|
void operator()( const P1& src, P2& dst) const
|
||
|
{
|
||
|
using namespace hsl_color_space;
|
||
|
|
||
|
bits32f red, green, blue;
|
||
|
|
||
|
if( std::abs( get_color( src, saturation_t() )) < 0.0001 )
|
||
|
{
|
||
|
// If saturation is 0, the color is a shade of gray
|
||
|
red = get_color( src, lightness_t() );
|
||
|
green = get_color( src, lightness_t() );
|
||
|
blue = get_color( src, lightness_t() );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
float temp1, temp2;
|
||
|
float tempr, tempg, tempb;
|
||
|
|
||
|
//Set the temporary values
|
||
|
if( get_color( src, lightness_t() ) < 0.5 )
|
||
|
{
|
||
|
temp2 = get_color( src, lightness_t() )
|
||
|
* ( 1.f + get_color( src, saturation_t() ) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
temp2 = ( get_color( src, lightness_t() ) + get_color( src, saturation_t() ))
|
||
|
- ( get_color( src, lightness_t() ) * get_color( src, saturation_t() ));
|
||
|
}
|
||
|
|
||
|
temp1 = 2.f
|
||
|
* get_color( src, lightness_t() )
|
||
|
- temp2;
|
||
|
|
||
|
tempr = get_color( src, hue_t() ) + 1.f / 3.f;
|
||
|
|
||
|
if( tempr > 1.f )
|
||
|
{
|
||
|
tempr--;
|
||
|
}
|
||
|
|
||
|
tempg = get_color( src, hue_t() );
|
||
|
tempb = get_color( src, hue_t() ) - 1.f / 3.f;
|
||
|
|
||
|
if( tempb < 0.f )
|
||
|
{
|
||
|
tempb++;
|
||
|
}
|
||
|
|
||
|
//Red
|
||
|
if( tempr < 1.f / 6.f )
|
||
|
{
|
||
|
red = temp1 + ( temp2 - temp1 ) * 6.f * tempr;
|
||
|
}
|
||
|
else if( tempr < 0.5f )
|
||
|
{
|
||
|
red = temp2;
|
||
|
}
|
||
|
else if( tempr < 2.f / 3.f )
|
||
|
{
|
||
|
red = temp1 + (temp2 - temp1)
|
||
|
* (( 2.f / 3.f ) - tempr) * 6.f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
red = temp1;
|
||
|
}
|
||
|
|
||
|
//Green
|
||
|
if( tempg < 1.f / 6.f )
|
||
|
{
|
||
|
green = temp1 + ( temp2 - temp1 ) * 6.f * tempg;
|
||
|
}
|
||
|
else if( tempg < 0.5f )
|
||
|
{
|
||
|
green = temp2;
|
||
|
}
|
||
|
else if( tempg < 2.f / 3.f )
|
||
|
{
|
||
|
green = temp1 + ( temp2 - temp1 )
|
||
|
* (( 2.f / 3.f ) - tempg) * 6.f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
green = temp1;
|
||
|
}
|
||
|
|
||
|
//Blue
|
||
|
if( tempb < 1.f / 6.f )
|
||
|
{
|
||
|
blue = temp1 + (temp2 - temp1) * 6.f * tempb;
|
||
|
}
|
||
|
else if( tempb < 0.5f )
|
||
|
{
|
||
|
blue = temp2;
|
||
|
}
|
||
|
else if( tempb < 2.f / 3.f )
|
||
|
{
|
||
|
blue = temp1 + (temp2 - temp1)
|
||
|
* (( 2.f / 3.f ) - tempb) * 6.f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
blue = temp1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
get_color(dst,red_t()) =
|
||
|
channel_convert<typename color_element_type< P2, red_t >::type>( red );
|
||
|
get_color(dst,green_t())=
|
||
|
channel_convert<typename color_element_type< P2, green_t >::type>( green );
|
||
|
get_color(dst,blue_t()) =
|
||
|
channel_convert<typename color_element_type< P2, blue_t >::type>( blue );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
} } // namespace boost::gil
|
||
|
|
||
|
#endif // GIL_HSL_H
|