Color - changing RGB values when in HSB colorMode

Yes, hehe,. I change between 3 different languages all the time, and often forget to switch the keyboard idioms. But I fixed it.

1 Like

Since jeremydouglass already took care of the big question, so iā€˜m gonna go with the small one :sweat_smile:

Itā€˜s probably better to work in RGB, since the values are set directly, without many calculations/conversions, while HSB would always convert values back and forthā€¦

For example :

color c = color(255,255,255,255); //32-bit

// Iā€˜ll write down an abstract version of the red()/hue() functions, to show what i mean. 

float red = red(c);
float hue = hue(c);

float red(color col) {
float r = col.getBits(col, 0, 7).toFloat(); //just pseudo code, to show that the first 8 Bits represent red
return r;
}

// on the other hand hue would be like this...

float hue(color col) {

float r = col.getBits(col, 0, 7).toFloat();
float g = col.getBits(col, 0, 7).toFloat();
float b = col.getBits(col, 0, 7).toFloat();

float h = (r/255)*((g/255)*255)*((b/255)*255*255); //if that really works... idk, but the actual formula is probably at least as complicated as this one
//it has to take in the r, g and b values at the very least. 

return h; //return the hue
}

So getting a color is pretty straight fortward, but an HSB value is a lot of hidden Math that affects performance (not much, but still).

1 Like

The way I look at it, is dividing the 360Ā° scale in 6, 60Ā° parts.
6 primary & secondary colors.
For the moment without bit shifting I get:

void setup() {

  // just random color
  float r = 34;
  float g = 185;
  float b = 109;
  float h = 0;
  color c = color(34, 185, 109);

  r /= 255;
  g /= 255;
  b /= 255;
  
  if (r >= g && g >= b)   h = 60 * ((g-b)/(r-b));
  if (g > r && r >= b)   h = 60 * (2-(r-b)/(g-b));
  if (g >= b && b > r)  h = 60 * (2+(b-r)/(g-r));
  if (b > g && g > r)  h = 60 * (4-(g-r)/(b-r));
  if (b > r && r >= g)   h = 60 * (4+(r-g)/(b-g));
  if (r >= b && b > g)   h = 60 * (6-(b-g)/(r-g));

  println(h);
  colorMode(HSB, 360, 100, 100);
  println(hue(c));
} 

Excellent. Thank you! Thatā€™s
what Iā€™ll do then.

Paul

QED!

Thatā€™s a pretty convincing demonstration of the maths behind hue().

Is it even better if we add chue()?

void setup() {

  // just random color
  float r = 34;
  float g = 185;
  float b = 109;
  float h = 0;
  color c = color(34, 185, 109);



  r /= 255;
  g /= 255;
  b /= 255;

  float chue = (hue(c)/255)*360;

  if (r >= g && g >= b)   h = 60 * ((g-b)/(r-b));
  if (g > r && r >= b)   h = 60 * (2-(r-b)/(g-b));
  if (g >= b && b > r)  h = 60 * (2+(b-r)/(g-r));
  if (b > g && g > r)  h = 60 * (4-(g-r)/(b-r));
  if (b > r && r >= g)   h = 60 * (4+(r-g)/(b-g));
  if (r >= b && b > g)   h = 60 * (6-(b-g)/(r-g));

  println(h);
  println(chue);
  colorMode(HSB, 360, 100, 100);
  println(hue(c));
}

ā€“149.80132
ā€“149.80133
ā€“149.80133

Actually I also had some coincidents when applying some random numbers, given aproximating good results But itā€™s not the right formula. Now Iā€™m gooing to google. I want to know the real formula.

Thank you for the colorspace library (Chroma). I had only looked in https://processing.org/reference/libraries/. You say there are several. Is there a library of libraries so I can find others in the future?

Your question. I am trying to make a tool and I am learning some Processing as I do. I am happy to use red(), brightness(), etc. I had avoided push and pop style because I want to do all my readings at the same time, but I will keep that door open.

If the methods already exist I have no desire to reinvent them and speed is not an issue. My overriding aim is to use Processing to present the information about a preselected colour in an easily accessible way so it can lead to knowledge and understanding.

Ignoring the relationships between two or more colours (this is already well-covered) I want to put some ā€˜goodā€™ colours into my simple tool and then see the underlying values and qualities of the colour. Of course at first the values will be numbers but I want to use visualisation techniques so the data is more immediately understood.

You donā€™t need to read this next bit as it is outside Processing.
As you probably know, competent listeners get increasingly skilled at categorisation. They can recognise phonemes even when distorted by dialect, accent, etc. Whereas competent visual artists get increasingly skilled at discrimination. At first we talk about red, blue and yellow and then artists and other experts see a larger and larger number of colours (reddish orange, salmon pink, etc.). This is what I mean by ā€˜goodā€™ colours.

1 Like

Noel, right formula for what? If it is hue(), then Jeremy has provided:

Iā€™ve read many times that HSB is very close to HSV That, was I was thinking of with the code above, but it isnā€™t. Wikipedia has a formula thatā€™s something like

 if (r >= g && g >= b) h = 60 * ((g-b)/(r-b)); 
 if (g > r && r >= b) h = 60 * (2-(r-b)/(g-b)); 
 if (g >= b && b > r) h = 60 * (2+(b-r)/(g-r)); 
 if (b > g && g > r) h = 60 * (4-(g-r)/(b-r)); 
 if (b > r && r >= g) h = 60 * (4+(r-g)/(b-g)); 
 if (r >= b && b > g) h = 60 * (6-(b-g)/(r-g));

But that doesnā€™t mach at all with HSB.
So Processing has itā€™s own method, but I like it.
Yes the method was linked above by jeremydouglass

float[] colors;
void setup() { // just random color

  int r = 24; 
  int g = 18; 
  int b = 110; 
  color c = color(r, g, b);
 
  colors = new float[3];  
  colorMode(HSB,360,100,100);
  println(hue(c));
  println(saturation(c));
  println(brightness(c));
  RGBtoHSB(r, g, b, colors);
  println("hue = "+colors[0]*360);
  println("saturation = "+colors[1]*100);
  println("brightness = "+colors[2]*100);
}

float[] RGBtoHSB(int r, int g, int b, float[] hsbvals) {
  float hue, saturation, brightness;
  if (hsbvals == null) {
    hsbvals = new float[3];
  }
  int cmax = (r > g) ? r : g;
  if (b > cmax) cmax = b;
  int cmin = (r < g) ? r : g;
  if (b < cmin) cmin = b;

  brightness = ((float) cmax) / 255.0f;
  if (cmax != 0)
    saturation = ((float) (cmax - cmin)) / ((float) cmax);
  else
    saturation = 0;
  if (saturation == 0)
    hue = 0;
  else {
    float redc = ((float) (cmax - r)) / ((float) (cmax - cmin));
    float greenc = ((float) (cmax - g)) / ((float) (cmax - cmin));
    float bluec = ((float) (cmax - b)) / ((float) (cmax - cmin));
    if (r == cmax)
      hue = bluec - greenc;
    else if (g == cmax)
      hue = 2.0f + redc - bluec;
    else
      hue = 4.0f + greenc - redc;
    hue = hue / 6.0f;
    if (hue < 0)
      hue = hue + 1.0f;
  }
  hsbvals[0] = hue;
  hsbvals[1] = saturation;
  hsbvals[2] = brightness;
  return hsbvals;
}

Itā€™s not actually the color space, but rather the positioning.
With this code I get the bars below.
Anyone can tell me where Iā€™m going wrong?

void setup() { 
  size(360, 130);
  float h = 0;
  colorMode(HSB, 360, 100, 100);
  for (int i = 1; i <= 360; i++) { 
    color c = color(i, 100, 100); 
    stroke(c);
    line(i, 10, i, 60);
  }
  for (int i = 1; i <= 360; i++) { 
    color c = color(i, 100, 100);
    float r = red(c)/255;
    float g = green(c)/255; 
    float b = blue(c)/255;
    if (r >= g && g >= b) h = 60 * ((g-b)/(r-b)); 
    if (g > r && r >= b) h = 60 * (2-(r-b)/(g-b)); 
    if (g >= b && b > r) h = 60 * (2+(b-r)/(g-r)); 
    if (b > g && g > r) h = 60 * (4-(g-r)/(b-r)); 
    if (b > r && r >= g) h = 60 * (4+(r-g)/(b-g)); 
    if (r >= b && b > g) h = 60 * (6-(b-g)/(r-g));
    stroke(h, 100, 100);
    line(i, 70, i, 120);
  }

Screenshot_2019-11-13-11-08-54

1 Like

You are using float r = red(c)/255; after setting colorMode(HSB, 360, 100, 100). You canā€™t do that. red() scales its output to the current colorMode ā€“ dividing by 255 doesnā€™t make sense, as that presumes a 255 source range, and that isnā€™t what red is returning.

Try this instead:

  for (int i = 1; i <= 360; i++) { 
    color c = color(i, 100, 100);
    float r = (c >> 16) & 0xff;
    float g = (c >> 8) & 0xff; 
    float b = c & 0xff;

Note that this still presumes a colorMode hue range of 360 while building your colors with color() ā€“ if you change the colorMode HSB range, that will break. You could make your second loop general-purpose by using g.colorModeX to map the spectrum to display across any numerical range ā€“ e.g. 0-1.0, or 0-100, et cetera.

HSBrange

4 Likes

So I spend hours not figuring this out, and you come along and see this in a blink of an eye.
I would like to have you skills.
Thanks a lot!

Here are the ways to access the ranges of the different colors/their respective field in HSB (red = hue, green = saturation, blue = brightness).

So setting hue to a range of 360 means setting red to a range of 360.
Setting saturation to 100 also sets green to 100.

Although this saves some space for extra variables, iā€˜d actually prefer different variables, instead of this colormodeX that dictates both red and hue at the same timeā€¦ Well, nothing i can do about itā€¦

2 Likes

Honestly, when I first looked at it I was confused. I tried altering the second loop size and then a tried resetting colorMode just before the second loop ā€“ just to see what would happen. I anticipated a fix, but the output was simply broken in different ways.

Then I re-read the second loop again more slowly. One line at a time, think about what each did. At that point, I saw red()/255, and finally thought ā€œahaā€. But if I hadnā€™t recently been explaining what red did (in this thread) I might still have missed it ā€“ and at that point I would have needed to add some testing / println() statements to quickly inspect what was happening and break it down a bit further.

2 Likes

Yes, but then again; I see you folks, and I wonā€™t say names, to not forget someone,- like those chess masters, who walk around within a table ring and make a move with a short glance, where then, that poor opponent, takes a century to make the counter move.

1 Like