Skip to content

Instantly share code, notes, and snippets.

@panovr
Created June 28, 2012 11:37
Show Gist options
  • Save panovr/3010817 to your computer and use it in GitHub Desktop.
Save panovr/3010817 to your computer and use it in GitHub Desktop.
RGB colorspace to HSV colorspace conversion and vice versa
/**
* R: [0, 255]
* G: [0, 255]
* B: [0, 255]
*
* H: [0.0, 360.0)
* S: [0.0, 1.0]
* V: [0.0, 1.0]
*
* If output is RGB of ByteImage3, then R, G, B is scaled to [0, 255];
* If output is RGB of FloatImage3, then R, G, B is scaled to [0.0, 1.0].
*/
template<class DstColor>
struct HsvToRgb {
template<class SrcColor>
DstColor operator()(const SrcColor& src) const
{
using namespace cmlib::image;
typedef typename ColorTrait<SrcColor>::BaseType value_type;
typedef typename TypeTrait<value_type>::ExtendedType tmp_type;
typedef typename ColorTrait<SrcColor>::ExtendedColor tmp_color;
typedef typename TypeTrait<
typename ColorSelector<
typename TypeTrait<value_type>::channel_type,
typename TypeTrait<tmp_type>::channel_type
>::priority_type>::extended_type ratio_type;
const ratio_type ratio =
static_cast<ratio_type>(TypeTrait<tmp_type>::domain()) /
static_cast<ratio_type>(TypeTrait<value_type>::domain());
std::cout << "ratio = " << ratio << std::endl;
tmp_type h = src[0] * 360 * ratio;
tmp_type s = src[1] * ratio;
tmp_type v = src[2] * ratio;
h /= 60;
int hi = static_cast<int>(h);
tmp_type f = h - hi;
tmp_type p = v*( 1 - s );
tmp_type q = v*( 1 - f*s );
tmp_type t = v*( 1 - ( 1 - f )*s);
tmp_type r, g, b;
switch (hi)
{
case 0:
r = v; g = t; b = p;
break;
case 1:
r = q; g = v; b = p;
break;
case 2:
r = p ; g = v; b = t;
break;
case 3:
r = p ; g = q; b = v;
break ;
case 4:
r = t ; g = p ; b = v ;
break ;
case 5:
r = v ; g = p ; b = q ;
break;
}
return cmlib::image::DefaultConvert<DstColor>()(tmp_color(r, g, b));
}
};
/**
* R: [0, 255]
* G: [0, 255]
* B: [0, 255]
*
* H: [0.0, 360.0)
* S: [0.0, 1.0]
* V: [0.0, 1.0]
*
* If output is HSV of ByteImage3, then H, S, V is scaled to [0, 255];
* If output is HSV of FloatImage3, then H, S, V is scaled to [0.0, 1.0].
*/
template<class DstColor>
struct RgbToHsv { // {{{
template<class SrcColor>
DstColor operator()(const SrcColor& src) const
{
using namespace cmlib::image;
typedef typename ColorTrait<SrcColor>::BaseType value_type;
typedef typename TypeTrait<value_type>::ExtendedType tmp_type;
typedef typename ColorTrait<SrcColor>::ExtendedColor tmp_color;
tmp_color tmp = cmlib::image::DefaultConvert<tmp_color>()(src);
const value_type& r = src[0];
const value_type& g = src[1];
const value_type& b = src[2];
const tmp_type& fr = tmp[0];
const tmp_type& fg = tmp[1];
const tmp_type& fb = tmp[2];
value_type imax = std::max(std::max(r, g), b);
value_type imin = std::min(std::min(r, g), b);
typedef typename TypeTrait<
typename ColorSelector<
typename TypeTrait<value_type>::channel_type,
typename TypeTrait<tmp_type>::channel_type
>::priority_type>::extended_type ratio_type;
const ratio_type ratio =
static_cast<ratio_type>(TypeTrait<tmp_type>::domain()) /
static_cast<ratio_type>(TypeTrait<value_type>::domain());
std::cout << "ratio = " << ratio << std::endl;
tmp_type fmax = imax * ratio;
tmp_type fmin = imin * ratio;
tmp_type multiplier = (imin == imax) ? 0.0 : 60 / (fmax - fmin);
tmp_type h, s, v;
if (r == imax)
{
h = (multiplier * (fg - fb) + 360);
if (h >= 360) h -= 360;
}
else if (g == imax)
h = multiplier * (fb - fr) + 120;
else
h = multiplier * (fr - fg) + 240;
if (imax == 0)
s = 0;
else
s = 1 - (fmin / fmax);
v = fmax;
std::cout << "h = " << h << ", s = " << s << ", v = " << v << std::endl;
typedef typename ColorTrait<DstColor>::BaseType dst_type;
std::cout << "h = " << static_cast<int>(h+0.5) << ", s = " <<
static_cast<int>(s*100 + 0.5) << ", v = " <<
static_cast<int>(v*100 + 0.5) << std::endl;
return cmlib::image::DefaultConvert<DstColor>()(tmp_color(h / 360, s, v));
}
};
/**
* rgb of 64 46 120
* in gimp the hsv shows as 254 62 47
* in opencv the hsv shows as 127 157 120
* gimp ranges are:
* h 0 - 360
* s 0 - 100
* v 0 - 100
*
* opencv ranges seem to be
* h 0 - 180
* s 0 - 255
* v 0 - 255
*
* so working out
* 127/180 * 360 = 254
* 157/255 * 100 = 62
* 120/255 * 100 = 47
*
* My implementation will use h: [0, 360), s: [0.0, 10], v[0.0, 1.0],
* and convert them to [0, 255] of ByteImage3 or [0.0, 1.0] of FloatImage3.
*/
int main(int argc, char *argv[])
{
ByteImage3 src(3, 1);
src(0,0)[0] = 64; src(0,0)[1] = 46; src(0,0)[2] = 120;
src(1,0)[0] = 112; src(1,0)[1] = 172; src(1,0)[2] = 182;
src(2,0)[0] = 93; src(2,0)[1] = 188; src(2,0)[2] = 210;
std::cout << "src: " << src << std::endl;
std::cout << "rgb_to_hsv: ByteImage3 -> ByteImage3" << std::endl;
ByteImage3 bdst(3, 1);
rgb_to_hsv(src, bdst);
std::cout << "bdst: " << bdst << std::endl;
std::cout << "hsv_to_rgb: ByteImage3 -> ByteImage3" << std::endl;
ByteImage3 brgb(3, 1);
hsv_to_rgb(bdst, brgb);
std::cout << "brgb: " << brgb << std::endl;
std::cout << "rgb_to_hsv: ByteImage3 -> FloatImage3" << std::endl;
FloatImage3 fdst(3, 1);
rgb_to_hsv(src, fdst);
std::cout << "fdst: " << fdst << std::endl;
std::cout << "hsv_to_rgb: FloatImage3 -> ByteImage3" << std::endl;
hsv_to_rgb(fdst, brgb);
std::cout << "brgb: " << brgb << std::endl;
std::cout << "rgb_to_hsv: FloatImage3 -> ByteImage3" << std::endl;
FloatImage3 frgb(1, 1);
frgb(0,0)[0] = 0.25; frgb(0,0)[1] = 0.18; frgb(0,0)[2] = 0.47;
std::cout << "frgb: " << frgb << std::endl;
ByteImage3 bhsv(1, 1);
rgb_to_hsv(frgb, bhsv);
std::cout << "bhsv: " << bhsv << std::endl;
std::cout << "hsv_to_rgb: ByteImage3 -> FloatImage3" << std::endl;
brgb.resize(1,1);
hsv_to_rgb(bhsv, brgb);
std::cout << "ByteImage3 RGB: " << brgb << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment