1 // 2 // Copyright 2012 Christian Henning 3 // 4 // Distributed under the Boost Software License, Version 1.0 5 // See accompanying file LICENSE_1_0.txt or copy at 6 // http://www.boost.org/LICENSE_1_0.txt 7 // 8 #ifndef BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_HSV_HPP 9 #define BOOST_GIL_EXTENSION_TOOLBOX_COLOR_SPACES_HSV_HPP 10 11 #include <boost/numeric/conversion/cast.hpp> 12 13 #include <boost/gil/color_convert.hpp> 14 #include <boost/gil/typedefs.hpp> 15 #include <boost/gil/detail/mp11.hpp> 16 17 #include <algorithm> 18 #include <cmath> 19 20 namespace boost{ namespace gil { 21 22 /// \addtogroup ColorNameModel 23 /// \{ 24 namespace hsv_color_space 25 { 26 /// \brief Hue 27 struct hue_t {}; 28 /// \brief Saturation 29 struct saturation_t{}; 30 /// \brief Value 31 struct value_t {}; 32 } 33 /// \} 34 35 /// \ingroup ColorSpaceModel 36 using hsv_t = mp11::mp_list 37 < 38 hsv_color_space::hue_t, 39 hsv_color_space::saturation_t, 40 hsv_color_space::value_t 41 >; 42 43 /// \ingroup LayoutModel 44 using hsv_layout_t = layout<hsv_t>; 45 46 BOOST_GIL_DEFINE_ALL_TYPEDEFS(32f, float32_t, hsv) 47 48 /// \ingroup ColorConvert 49 /// \brief RGB to HSV 50 template <> 51 struct default_color_converter_impl< rgb_t, hsv_t > 52 { 53 template <typename P1, typename P2> operator ()boost::gil::default_color_converter_impl54 void operator()( const P1& src, P2& dst ) const 55 { 56 using namespace hsv_color_space; 57 58 // only float32_t for hsv is supported 59 float32_t temp_red = channel_convert<float32_t>( get_color( src, red_t() )); 60 float32_t temp_green = channel_convert<float32_t>( get_color( src, green_t() )); 61 float32_t temp_blue = channel_convert<float32_t>( get_color( src, blue_t() )); 62 63 float32_t hue, saturation, value; 64 65 float32_t min_color = (std::min)( temp_red, (std::min)( temp_green, temp_blue )); 66 float32_t max_color = (std::max)( temp_red, (std::max)( temp_green, temp_blue )); 67 68 value = max_color; 69 70 float32_t diff = max_color - min_color; 71 72 if( max_color < 0.0001f ) 73 { 74 saturation = 0.f; 75 } 76 else 77 { 78 saturation = diff / max_color; 79 } 80 81 82 if( saturation < 0.0001f ) 83 { 84 //it doesn't matter what value it has 85 hue = 0.f; 86 } 87 else 88 { 89 if( (std::abs)( boost::numeric_cast<float32_t>(temp_red - max_color) ) < 0.0001f ) 90 { 91 hue = ( temp_green - temp_blue ) 92 / diff; 93 } 94 else if( temp_green >= max_color ) // means == but >= avoids compiler warning; color is never greater than max 95 { 96 hue = 2.f + ( temp_blue - temp_red ) 97 / diff; 98 } 99 else 100 { 101 hue = 4.f + ( temp_red - temp_green ) 102 / diff; 103 } 104 105 //to bring it to a number between 0 and 1 106 hue /= 6.f; 107 108 if( hue < 0.f ) 109 { 110 hue++; 111 } 112 } 113 114 get_color( dst, hue_t() ) = hue; 115 get_color( dst, saturation_t() ) = saturation; 116 get_color( dst, value_t() ) = value; 117 } 118 }; 119 120 /// \ingroup ColorConvert 121 /// \brief HSV to RGB 122 template <> 123 struct default_color_converter_impl<hsv_t,rgb_t> 124 { 125 template <typename P1, typename P2> operator ()boost::gil::default_color_converter_impl126 void operator()( const P1& src, P2& dst) const 127 { 128 using namespace hsv_color_space; 129 130 float32_t red, green, blue; 131 132 //If saturation is 0, the color is a shade of gray 133 if (std::abs(get_color(src, saturation_t())) < 0.0001f) 134 { 135 // If saturation is 0, the color is a shade of gray 136 red = get_color( src, value_t() ); 137 green = get_color( src, value_t() ); 138 blue = get_color( src, value_t() ); 139 } 140 else 141 { 142 float32_t frac, p, q, t, h; 143 uint32_t i; 144 145 //to bring hue to a number between 0 and 6, better for the calculations 146 h = get_color( src, hue_t() ); 147 h *= 6.f; 148 149 i = static_cast<uint32_t>(floor(h)); 150 151 frac = h - i; 152 153 p = get_color( src, value_t() ) 154 * ( 1.f - get_color( src, saturation_t() )); 155 156 q = get_color( src, value_t() ) 157 * ( 1.f - ( get_color( src, saturation_t() ) * frac )); 158 159 t = get_color( src, value_t() ) 160 * ( 1.f - ( get_color( src, saturation_t() ) * ( 1.f - frac ))); 161 162 switch( i ) 163 { 164 case 0: 165 { 166 red = get_color( src, value_t() ); 167 green = t; 168 blue = p; 169 170 break; 171 } 172 173 case 1: 174 { 175 red = q; 176 green = get_color( src, value_t() ); 177 blue = p; 178 179 break; 180 } 181 182 case 2: 183 { 184 red = p; 185 green = get_color( src, value_t() ); 186 blue = t; 187 188 break; 189 } 190 191 case 3: 192 { 193 red = p; 194 green = q; 195 blue = get_color( src, value_t() ); 196 197 break; 198 } 199 200 case 4: 201 { 202 red = t; 203 green = p; 204 blue = get_color( src, value_t() ); 205 206 break; 207 } 208 209 case 5: 210 { 211 red = get_color( src, value_t() ); 212 green = p; 213 blue = q; 214 215 break; 216 } 217 218 } 219 } 220 221 get_color(dst,red_t()) = 222 channel_convert<typename color_element_type< P2, red_t >::type>( red ); 223 get_color(dst,green_t())= 224 channel_convert<typename color_element_type< P2, green_t >::type>( green ); 225 get_color(dst,blue_t()) = 226 channel_convert<typename color_element_type< P2, blue_t >::type>( blue ); 227 } 228 }; 229 230 } // namespace gil 231 } // namespace boost 232 233 #endif 234