00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifndef OLENA_CONVERT_RGBHSV_HH
00031 # define OLENA_CONVERT_RGBHSV_HH
00032
00033 # include <oln/basics.hh>
00034 # include <oln/convert/abstract/colorconv.hh>
00035 # include <oln/convert/float_cmp.hh>
00036
00037 # include <ntg/basics.hh>
00038 # include <ntg/color/rgb.hh>
00039 # include <ntg/color/hsv.hh>
00040
00041 # include <mlc/contract.hh>
00042
00043 # include <sstream>
00044
00049 namespace oln {
00050
00051 using namespace ntg;
00052
00053 namespace convert {
00054
00059 template<unsigned inbits, unsigned outbits>
00060 struct f_rgb_to_hsv
00061 : public abstract::color_conversion<3, inbits, rgb_traits,
00062 3, outbits, hsv_traits, f_rgb_to_hsv<inbits, outbits> >
00063 {
00064 color<3, outbits, hsv_traits>
00065 doit(const color<3, inbits, rgb_traits>& v) const
00066 {
00067 vec<3, float> in = v.to_float();
00068 vec<3, float> out;
00069 float max_in = std::max(in[rgb_R], std::max(in[rgb_B], in[rgb_G]));
00070 float min_in = std::min(in[rgb_R], std::min(in[rgb_B], in[rgb_G]));
00071 float delta = max_in - min_in;
00072
00073
00074 out[hsv_V] = max_in;
00075
00076 if (approx_neq(max_in, 0))
00077 out[hsv_S] = delta / max_in;
00078 else
00079 out[hsv_S] = 0;
00080
00081 if (approx_eq(out[hsv_S], 0))
00082 out[hsv_H] = -1;
00083 else {
00084 if (approx_eq(in[rgb_R], max_in))
00085 out[hsv_H] = (in[rgb_G] - in[rgb_B]) / delta;
00086 else if (approx_eq(in[rgb_G], max_in))
00087 out[hsv_H] = 2 + (in[rgb_B] - in[rgb_R]) / delta;
00088 else
00089 out[hsv_H] = 4 + (in[rgb_R] - in[rgb_G]) / delta;
00090 out[hsv_H] *= 60;
00091 if (out[hsv_H] < 0)
00092 out[hsv_H] += 360;
00093 }
00094
00095 return out;
00096 }
00097
00098 static std::string
00099 name()
00100 {
00101 std::ostringstream s;
00102 s << "f_rgb_to_hsv<" << inbits << ", " << outbits << '>';
00103 return s.str();
00104 }
00105 };
00106
00111 template <unsigned inbits, unsigned outbits>
00112 color<3, outbits, hsv_traits>
00113 rgb_to_hsv(const color<3, inbits, rgb_traits>& v)
00114 {
00115 f_rgb_to_hsv<inbits, outbits> f;
00116 return f(v);
00117 }
00118
00123 template<unsigned inbits, unsigned outbits>
00124 struct f_hsv_to_rgb
00125 : public abstract::color_conversion<3, inbits, hsv_traits,
00126 3, outbits, rgb_traits, f_hsv_to_rgb<inbits, outbits> >
00127 {
00128 color<3, outbits, rgb_traits>
00129 doit(const color<3, inbits, hsv_traits>& v) const
00130 {
00131 vec<3, float> in = v.to_float();
00132 vec<3, float> out;
00133
00134 if(approx_eq(in[hsv_S], 0))
00135 out[rgb_G] = out[rgb_B] = out[rgb_R] = in[hsv_V];
00136 else
00137 {
00138 in[hsv_H] /= 60;
00139 int i = (int)floor (in[hsv_H]);
00140 float f = in[hsv_H] - i;
00141 float p = in[hsv_V] * (1 - in[hsv_S]);
00142 float q = in[hsv_V] * (1 - in[hsv_S] * f);
00143 float t = in[hsv_V] * (1 - in[hsv_S] * (1 - f));
00144
00145 switch (i){
00146 case 0:
00147 case 6:
00148 out[rgb_R] = in[hsv_V];
00149 out[rgb_G] = t;
00150 out[rgb_B] = p;
00151 break;
00152 case 1:
00153 out[rgb_R] = q;
00154 out[rgb_G] = in[hsv_V];
00155 out[rgb_B] = p;
00156 break;
00157 case 2:
00158 out[rgb_R] = p;
00159 out[rgb_G] = in[hsv_V];
00160 out[rgb_B] = t;
00161 break;
00162 case 3:
00163 out[rgb_R] = p;
00164 out[rgb_G] = q;
00165 out[rgb_B] = in[hsv_V];
00166 break;
00167 case 4:
00168 out[rgb_R] = t;
00169 out[rgb_G] = p;
00170 out[rgb_B] = in[hsv_V];
00171 break;
00172 default:
00173 out[rgb_R] = in[hsv_V];
00174 out[rgb_G] = p;
00175 out[rgb_B] = q;
00176 break;
00177 }
00178 }
00179 return out;
00180 }
00181
00182 static std::string
00183 name()
00184 {
00185 std::ostringstream s;
00186 s << "f_hsv_to_rgb<" << inbits << ", " << outbits << '>';
00187 return s.str();
00188 }
00189 };
00190
00195 template <unsigned inbits, unsigned outbits>
00196 color<3, outbits, rgb_traits>
00197 hsv_to_rgb(const color<3, inbits, hsv_traits>& v)
00198 {
00199 f_hsv_to_rgb<inbits, outbits> f;
00200 return f(v);
00201 }
00202
00203 }
00204 }
00205
00206 #endif // OLENA_CONVERT_RGBHSV_HH