RGB and HSB - how do they relate?

I've spent far too long whittling down a problem to this:

color bg;


colorMode(RGB, 255, 255, 255); //default
bg = color( 0, 169, 255 );
background(bg);
println(hue(bg) +", "+ saturation(bg) +", "+ brightness(bg)); //outputs 141.83333, 255.0, 255.0
println(red(bg) +", "+ green(bg) +", "+ blue(bg)); //outputs 0.0, 169.0, 255.0


colorMode(HSB, 360, 100, 100);
bg = color( 200, 100, 100 );
background(bg);
println(hue(bg) +", "+ saturation(bg) +", "+ brightness(bg)); //outputs 200.23529, 100.0, 100.0
println(red(bg) +", "+ green(bg) +", "+ blue(bg)); //outputs 0.0, 66.27451, 100.0

It can be boiled down to:

colorMode(HSB, _anything_, 100, 100);
println(hue(color(200, 100, 100))); //outputs 200.23529

According to my colour picker, (R0, G169, B255) = (H200, S100, B100), so why don't they output the same values?

I'm manipulating the hue of various colours and am finding this inaccuracy, er, challenging.

Answers

  • Answer ✓

    The relationship is complicated and it is very common for RGB to HSB back to RGB to give different values from the original (Same for HSB > RGB > HSB).

    A bit of googling will highlight this, also look at the source code in the Java Color class for the transformations they use.

  • edited November 2017 Answer ✓

    One short answer is "because the underlying color information is stored in floats, and you are asking for a fraction of a float, which often is not clean."

    int[] hues = {360, 256, 255, 100};
    
    for(int h : hues){
      println("---");
      println("Hue = ", h);
      colorMode(HSB, h, 100, 100);
      println( hue ( color(h/4, 100, 100)));
      println( hue ( color(h/2, 100, 100)));
      println( hue ( color(h, 100, 100)));
    }
    

    Output:

    ---
    Hue =  360
    90.117645
    180.0
    0.0
    ---
    Hue =  256
    64.08366
    128.0
    0.0
    ---
    Hue =  100
    25.032679
    50.0
    0.0
    

    Note that you can round or cast to int if you want round numbers:

    println( (int) hue ( color(h, 100, 100)));
    

    and:

    ---
    Hue =  360
    90
    180
    0
    ---
    Hue =  256
    64
    128
    0
    ---
    Hue =  100
    25
    50
    0
    

    However, this may lose meaningful precision, depending on your mapping:

    colorMode(HSB, 100, 100, 100);
    println( (int) hue ( color(10.5, 100, 100))); // output 10
    
  • Thanks quark and jeremydouglass - it's much as I suspected: that's the way it's written and it's to do with manipulating floats. I don't have it in me to look at the java source so will change my code to specify the hue, sat and bright each as separate variables rather than combined into one colo(u)r. Good ol' search and replace!

Sign In or Register to comment.