We are about to switch to a new forum software. Until then we have removed the registration on this forum.
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:
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:
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:
fill()
?Thank you, George
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:
This solves one problem.
Would you happen to have any hints on why the dimmed brightness values go above the maximum value ?
Because your dimmed array sometime contains negative values, which get interpreted as RGB/ARGB colors instead of greyscale values.
Simply replace:
...with:
...or (just like bckmnn wrote):
...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.