Pixel array manipulation in HSB color mode

I’ve made a sketch that gradually reveals a picture by starting with all black, then gradually increasing the red value of each pixel up to the desired level, then doing the same for green, then blue (or any other order I choose). It works fine, creating a nice effect. I am trying to do the exact same same thing with the HSB color mode, and failing, and can’t figure out why.

Here is an excerpt from the code that works for RGB:


void colorByColor() {  // called by draw() code that starts seqColorCtr at 0 and 
                                   // increments it with each call
  
    if(seqColorCtr < 255) { // do 255 levels of red first  
      incrColor(‘r’); // bump red level by 1 where needed for all of darkPicture, 
      }
    else if(seqColorCtr < 511) { // then 255 levels of green
      incrColor(‘g’);
      }
    else if(seqColorCtr < 767) { // then 255 levels of blue
      incrColor(‘b’);
      }
    else { // go to next picture
      picStatus = 0;
    }

void incrColor(char _colorToDo) { 
  int ctr;
  
  darkPicture.loadPixels(); 
  currentPicture.loadPixels();

  if(_colorToDo == 'r') {// red
    for(ctr = 0 ; ctr < currentPicture.width * currentPicture.height ; ctr++) {
      if(red(currentPicture.pixels[ctr]) > (darkPicture.pixels[ctr] >> 16 & 0xFF)) {
         darkPicture.pixels[ctr] += 0x010000;
      } // end if red
    } // end for ctr.  Bumped up red by 1 tick after this pass
  } // end if colorToTdo==r

  if(_colorToDo == 'g') {// green
    for(ctr = 0 ; ctr < currentPicture.width * currentPicture.height ; ctr++) {
      if(green(currentPicture.pixels[ctr]) > (darkPicture.pixels[ctr] >> 8 & 0xFF)) {
         darkPicture.pixels[ctr] += 0x100;
        } // end if green
    } // end for ctr. Bumped up green by 1 tick after this pass
  } // end if colorToTdo==g
  
  if(_colorToDo == 'b') {// blue
    for(ctr = 0 ; ctr < currentPicture.width * currentPicture.height ; ctr++) {
      if(blue(currentPicture.pixels[ctr]) > (darkPicture.pixels[ctr] & 0xFF)) {
         darkPicture.pixels[ctr] += 0x1;
        } // end if blue
    } // end for ctr. Bumped up blue by 1 tick after this pass
  } // end if colorToTdo==b

} // end incrColor

I use bit-shifting to find the r, g, and b elements of each pixel, and I add a hex value to increment each of them by 1 when necessary. It works fine.

When I do the same thing in the HSB mode, it doesn’t work. I get results that are just weird, and never end up making darkPicture look the same a currentPicture as it is supposed to. It really seems like it is incrementing a single color first, which it shouldn’t be doing.

In HSB mode, are H, S, and B stored in the same two-bytes-each way as R, G, and B are stored in RGB mode? I am beginning to think they are not, and that HSB mode stores values as RGB, then converts them on the fly, maybe by some kind of lookup table. Is this how it works?

Closely related question: When I create darkPicture, I use an HSB argument:

darkPicture = createImage(currentPicture.width, currentPicture.height, HSB);

The reference page doesn’t say I can do this. I don’t see any error message when I do it, but is it accomplishing anything? Is the pixel color still being stored in the pixel array with R in two bytes, G in two bytes, and B in two bytes? It certainly doesn’t feel right to use an RGB argument if what I want is HSB.

I suppose I could use get() and set() to increment the H, S and B values rather than directly writing to the pixel array. But that would be less efficient, and I hate to give up if I don’t have to. Thanks for any light you can shed on this.

Upon further investigation, I have concluded that trying to manipulate the pixels array in HSB mode just doesn’t work correctly.

First example, in RGB mode:

void setup() {
size(300,300);
colorMode(RGB);
}

void draw() {
background(180, 200, 200);
loadPixels();
println(“First Red is”, red(pixels[45000]));
pixels[45000]=color(120,40,40);
updatePixels();
loadPixels();
println(“Second Red is”, red(pixels[45000]));
exit();
}

Output:
First Red is 180.0
Second Red is 120.0

This creates a simple screen with a background color, and when I ask for the red value of the middle pixel I get the correct answer. Then I change the color value of that pixel, ask again what the red value is, and again get the correct answer of the changed color.

Now I try the exact same code, but in HSB mode:

void setup() {
size(300,300);
colorMode(HSB);
}

void draw() {
background(180, 200, 200);
loadPixels();
println(“First Hue is”, hue(pixels[45000]));
pixels[45000]=color(120,40,40);
updatePixels();
loadPixels();
println(“Second Hue is”, hue(pixels[45000]));
exit();
}

This time, output is:

First Hue is 180.01591
Second Hue is 115.35714

I have no idea where it’s getting the 115.35714 result from. There must be an anomaly in the program somewhere. I think the documentation for colorMode, pixels array, or both ought to be changed to warn users not to use pixels array manipulation in HSB mode. I spent an awful lot of hours feeling stupid before I realized the weird results I was getting were not my fault.

(Also, it appears I can’t use get() and set() with HSB mode either. Oh well.)

Hi

This May help

https://funprogramming.org/90-Change-pixel-hue-saturation-and-brightness.html

void setup() {
size(300,300);
colorMode(HSB);
}

void draw() {
background(180, 200, 200);
loadPixels();
for (int i = 0; i < pixels.length; i++) {
float b = brightness(pixels[i]);
float s = saturation(pixels[i]);
float h = hue(pixels[i]);

pixels[i] = color(h, s, b);
}
updatePixels();
println( blue(pixels[45000]));
println( red(pixels[45000]));
println( green(pixels[45000]));
println( hue(pixels[45000]));
println( brightness (pixels[45000]));
println(saturation(pixels[45000]));

}

Thanks very much for your response. I’m not sure this accomplishes what I want, but I will give it a try.