Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / extension / toolbox / color_spaces / hsv.hpp
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 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>
54    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>
126    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( 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