hsv.hpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. #include <boost/numeric/conversion/cast.hpp>
  11. #include <boost/gil/color_convert.hpp>
  12. #include <boost/gil/typedefs.hpp>
  13. #include <boost/gil/detail/mp11.hpp>
  14. #include <algorithm>
  15. #include <cmath>
  16. namespace boost{ namespace gil {
  17. /// \addtogroup ColorNameModel
  18. /// \{
  19. namespace hsv_color_space
  20. {
  21. /// \brief Hue
  22. struct hue_t {};
  23. /// \brief Saturation
  24. struct saturation_t{};
  25. /// \brief Value
  26. struct value_t {};
  27. }
  28. /// \}
  29. /// \ingroup ColorSpaceModel
  30. using hsv_t = mp11::mp_list
  31. <
  32. hsv_color_space::hue_t,
  33. hsv_color_space::saturation_t,
  34. hsv_color_space::value_t
  35. >;
  36. /// \ingroup LayoutModel
  37. using hsv_layout_t = layout<hsv_t>;
  38. GIL_DEFINE_ALL_TYPEDEFS(32f, float32_t, hsv)
  39. /// \ingroup ColorConvert
  40. /// \brief RGB to HSV
  41. template <>
  42. struct default_color_converter_impl< rgb_t, hsv_t >
  43. {
  44. template <typename P1, typename P2>
  45. void operator()( const P1& src, P2& dst ) const
  46. {
  47. using namespace hsv_color_space;
  48. // only float32_t for hsv is supported
  49. float32_t temp_red = channel_convert<float32_t>( get_color( src, red_t() ));
  50. float32_t temp_green = channel_convert<float32_t>( get_color( src, green_t() ));
  51. float32_t temp_blue = channel_convert<float32_t>( get_color( src, blue_t() ));
  52. float32_t hue, saturation, value;
  53. float32_t min_color = (std::min)( temp_red, (std::min)( temp_green, temp_blue ));
  54. float32_t max_color = (std::max)( temp_red, (std::max)( temp_green, temp_blue ));
  55. value = max_color;
  56. float32_t diff = max_color - min_color;
  57. if( max_color < 0.0001f )
  58. {
  59. saturation = 0.f;
  60. }
  61. else
  62. {
  63. saturation = diff / max_color;
  64. }
  65. if( saturation < 0.0001f )
  66. {
  67. //it doesn't matter what value it has
  68. hue = 0.f;
  69. }
  70. else
  71. {
  72. if( (std::abs)( boost::numeric_cast<float32_t>(temp_red - max_color) ) < 0.0001f )
  73. {
  74. hue = ( temp_green - temp_blue )
  75. / diff;
  76. }
  77. else if( temp_green >= max_color ) // means == but >= avoids compiler warning; color is never greater than max
  78. {
  79. hue = 2.f + ( temp_blue - temp_red )
  80. / diff;
  81. }
  82. else
  83. {
  84. hue = 4.f + ( temp_red - temp_green )
  85. / diff;
  86. }
  87. //to bring it to a number between 0 and 1
  88. hue /= 6.f;
  89. if( hue < 0.f )
  90. {
  91. hue++;
  92. }
  93. }
  94. get_color( dst, hue_t() ) = hue;
  95. get_color( dst, saturation_t() ) = saturation;
  96. get_color( dst, value_t() ) = value;
  97. }
  98. };
  99. /// \ingroup ColorConvert
  100. /// \brief HSV to RGB
  101. template <>
  102. struct default_color_converter_impl<hsv_t,rgb_t>
  103. {
  104. template <typename P1, typename P2>
  105. void operator()( const P1& src, P2& dst) const
  106. {
  107. using namespace hsv_color_space;
  108. float32_t red, green, blue;
  109. //If saturation is 0, the color is a shade of gray
  110. if( abs( get_color( src, saturation_t() )) < 0.0001f )
  111. {
  112. // If saturation is 0, the color is a shade of gray
  113. red = get_color( src, value_t() );
  114. green = get_color( src, value_t() );
  115. blue = get_color( src, value_t() );
  116. }
  117. else
  118. {
  119. float32_t frac, p, q, t, h;
  120. uint32_t i;
  121. //to bring hue to a number between 0 and 6, better for the calculations
  122. h = get_color( src, hue_t() );
  123. h *= 6.f;
  124. i = static_cast<uint32_t>(floor(h));
  125. frac = h - i;
  126. p = get_color( src, value_t() )
  127. * ( 1.f - get_color( src, saturation_t() ));
  128. q = get_color( src, value_t() )
  129. * ( 1.f - ( get_color( src, saturation_t() ) * frac ));
  130. t = get_color( src, value_t() )
  131. * ( 1.f - ( get_color( src, saturation_t() ) * ( 1.f - frac )));
  132. switch( i )
  133. {
  134. case 0:
  135. {
  136. red = get_color( src, value_t() );
  137. green = t;
  138. blue = p;
  139. break;
  140. }
  141. case 1:
  142. {
  143. red = q;
  144. green = get_color( src, value_t() );
  145. blue = p;
  146. break;
  147. }
  148. case 2:
  149. {
  150. red = p;
  151. green = get_color( src, value_t() );
  152. blue = t;
  153. break;
  154. }
  155. case 3:
  156. {
  157. red = p;
  158. green = q;
  159. blue = get_color( src, value_t() );
  160. break;
  161. }
  162. case 4:
  163. {
  164. red = t;
  165. green = p;
  166. blue = get_color( src, value_t() );
  167. break;
  168. }
  169. case 5:
  170. {
  171. red = get_color( src, value_t() );
  172. green = p;
  173. blue = q;
  174. break;
  175. }
  176. }
  177. }
  178. get_color(dst,red_t()) =
  179. channel_convert<typename color_element_type< P2, red_t >::type>( red );
  180. get_color(dst,green_t())=
  181. channel_convert<typename color_element_type< P2, green_t >::type>( green );
  182. get_color(dst,blue_t()) =
  183. channel_convert<typename color_element_type< P2, blue_t >::type>( blue );
  184. }
  185. };
  186. } // namespace gil
  187. } // namespace boost
  188. #endif