Created
June 28, 2012 11:37
-
-
Save panovr/3010817 to your computer and use it in GitHub Desktop.
RGB colorspace to HSV colorspace conversion and vice versa
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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)); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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)); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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