Understanding colours in Processing

edited December 2013 in Questions about Code

I'm trying to do something I hope is simple: change the overall brightness in a resulting image if the overall brightness of the source image is past a certain threshold value.

My logic so far is fairly simple:

  • get the difference between the target max. brightness and the source image overall brightness
  • normalize the difference
  • if the difference is greater than 0 then use the normalized brightness difference to 'dimm'/subtract brightness on the resulting pixel

My first attempt looks like this:

PImage normal,dimmed;

int s  = 40;//preview scale factor
int w  = 8;//pixels width
int h  = 8;//pixels height
int np = w*h;//total number of pixels 
int b = 255;//current pixel brush brightness
float nb = 0;//normal image brightness
float mb = 64;//max brightness
float db = 0;//dimmed image brightness

void setup(){
  noSmooth();fill(127);
  size(w*s*2,h*s);
  normal = createImage(w,h,RGB);
  dimmed = createImage(w,h,RGB);
}
void draw(){
  image(normal,0,0,w*s,h*s);
  image(dimmed,w*s,0,w*s,h*s);
  text("original brightness: "+nb+" max: " + mb +"\ndimmed brightness: " + db,10,15);
}
void mouseDragged(){
  if(mouseX < w*s){
    normal.set(mouseX/s,mouseY/s,color(b));
    //average brightness
    nb = getBrightness(normal);
    //dimm if needed
    float bd   = (nb-mb)/255.0;//normalized brightness difference
    println(nb-mb+"/"+bd);
    for(int i = 0 ; i < np; i++)
      dimmed.pixels[i] = color(brightness(normal.pixels[i]) - (bd > 0 ? bd * 255.0 : 0));//copy brightness and subtract
    dimmed.updatePixels();
    //done dimming, compare
    db = getBrightness(dimmed);
  }
}
void keyPressed(){
  if(key == '-' && b > 0) b--;
  if(key == '=' && b < 255) b++; 
  if(key == ' ') {java.util.Arrays.fill(normal.pixels,0);normal.updatePixels();}
}
float getBrightness(PImage img){
  float ab = 0;
  for(int i = 0 ; i < np; i++) ab += brightness(img.pixels[i]);
  return (ab/np);
}

In this version I still see brightness values in the resulting image higher than the maximum brightness I'm aiming for. This is where I started going down the rabbit whole. First I though there is something with the image format. In the documentation I see PImage has RGB,ARGB and ALPHA modes. I've done a simple test with ALPHA mode assuming this will be a grayscale image:

PImage i = new PImage(100,100,ALPHA);
java.util.Arrays.fill(i.pixels,color(255,127,0));
i.updatePixels();
image(i,0,0);

When I run the snippet above I see an orange image. I am aware I am passing RGB value, but does that automatically convert an grayscale/ALPHA image to a colour/RGB one ?

So my first question is: What is the correct way of using(initializing,reading,writing) grayscale PImages ?

Back to original idea, I also did a version using a 2D array of int values:

int s  = 40;//preview scale factor
int w  = 8;//pixels width
int h  = 8;//pixels height
int np = w*h;//total number of pixels 
int b = 255;//current pixel brush brightness
float nb = 0;//normal image brightness
float mb = 64;//max brightness
float db = 0;//dimmed image brightness

int[][] normal,dimmed;

void setup(){
  noSmooth();fill(127);
  size(w*s*2,h*s);
  normal = new int[w][h];
  dimmed = new int[w][h];
}
void draw(){
  background(0);//clear
  for(int y = 0; y  < h ; y++){
    for(int x = 0; x < w ; x++){
      fill(normal[x][y]);
      rect(x*s,y*s,s,s);//draw a scaled pixel representation
      fill(dimmed[x][y]);
      rect((x*s)+(w*s),y*s,s,s);
    }
  }
  fill(127);text("original brightness: "+nb+" max: " + mb +"\ndimmed brightness: " + db,10,15);
}
void mouseDragged(){
  if((mouseX > 0 && mouseX < w*s)&&(mouseY > 0 && mouseY < h*s)){
    normal[mouseX/s][mouseY/s] = b;
    //average brightness
    nb = getBrightness(normal);
    //dimm if needed
    float bd   = (nb-mb)/255.0;//normalized brightness difference
    println(nb-mb+"/"+bd);

    for(int y = 0; y  < h ; y++)
      for(int x = 0; x < w ; x++)
        dimmed[x][y] = normal[x][y] - (int)(bd > 0 ? bd * 255.0 : 0);
    //done dimming, compare
    db = getBrightness(dimmed);
  }
}
void keyPressed(){
  if(key == '-' && b > 0) b--;
  if(key == '=' && b < 255) b++; 
  if(key == ' ') {
    for(int y = 0; y  < h ; y++)
      for(int x = 0; x < w ; x++)
        normal[x][y] = 0;
  }
}
float getBrightness(int[][] img){
  float ab = 0;
  for(int y = 0; y  < h ; y++)
    for(int x = 0; x < w ; x++)
      ab += img[x][y];
  return (ab/np);
}

The numbers look better with this approach. However, sometimes I see the colour yellow when there should be no hue visible.Here's what I mean:

brightness issue

So my second question is: Why does that happen ? How can I avoid it ? Am I correctly using colours in this case ? If not, why?

In short:

  • what's the correct way of working with grey scale values (0-255) and PImage ?
  • why is does Processing sometimes render grey scale values as yellow when using fill() ?

Thank you, George

Tagged:

Answers

  • Looks like you have an error in your calculations. getting strange hues is almost always because of some values are not in the correct range.

    add follwing code after line 25: fill(127);text(dimmed[x][y],(x*s)+(w*s),y*s + 10);

    the yellow pixels are because of negative color values

  • @bckmnn Thank's for the reply. That's a helpful visualization of the issue. Now in the drag event I make sure I constrain the values:

    for(int y = 0; y  < h ; y++){
          for(int x = 0; x < w ; x++){
            dimmed[x][y] = normal[x][y] - (int)(bd > 0 ? bd * 255.0 : 0);
            dimmed[x][y] = constrain(dimmed[x][y],0,255);
          }
        }
    

    This solves one problem.

    Would you happen to have any hints on why the dimmed brightness values go above the maximum value ?

  • edited December 2013 Answer ✓

    Because your dimmed array sometime contains negative values, which get interpreted as RGB/ARGB colors instead of greyscale values.

    Simply replace:

    fill(dimmed[x][y]);

    ...with:

    fill(abs(dimmed[x][y]));

    ...or (just like bckmnn wrote):

    constrain(dimmed[x][y],0,255);

    ...to fix this issue.

    You are generating negative values because: Even if the average brightness is greater than the max brightness, there are still pixels left with a brightness value smaller than the difference between the average and the max brightness (all black pixels for example) - these pixels will get yellow.

Sign In or Register to comment.