Adjusting pixel brightness value of an image

Ok, I’ve exhausted myself trying to adjust the brightness of pixels from a loaded image using p5.js.I’ve looked online and multiple forums with no solution. It seems like color and colorMode work very differently in p5.js compared to Processing using java. To better understand the issue I’ve broken the problem down to a simple sketch. The target or goal is to recreate the Processing sketch below to p5.js.

// I loaded an image in setup and set the 
// color mode to colorMode(HSB, 360, 100, 100, 100)
void draw() {
  background(0, 0, 100);
  
  // display original image. 
  image(img, 0, 0);
  
  // adjust brightness based on mouseX position
  float brightnessAdj = map(mouseX, 0, width, -10, 10);
  
  // loop through each pixel in image and adjust brightness
  for(int y = 0; y < img.height; y++) {
    for(int x = 0; x < img.width; x++) {
      int index = x + y * img.width;     
      float hue = hue(img.pixels[index]);
      float sat = saturation(img.pixels[index]);
      float bri = constrain(brightness(img.pixels[index]) + brightnessAdj, 0, 100);
      
      // display new image using points
      stroke(hue, sat, bri);
      point(x + 300, y);
    }
  }
}

The above code works perfectly. It is near exact recreation of the original image but becomes darker or brighter as I move the mouse across the sketch window.

In p5.js I can’t just set the color mode to colorMode(HSB, 360, 100, 100, 100) in the setup. The output result doe not work. From what I understand in p5.js color objects are stored solely as RGBA values. Additionally getting color values from an image using the pixel array or the get() method also only returns values in the RGBA format. Trying to get the hue, saturation, brightness values from the RGBA values given the built in methods doesn’t allow me to adjust the brightness and create the points with the new color. The colors are all wrong. The closest I can get is the following code (again I’ve loaded an image, loaded the pixels, and done all the same setup in the preload and setup functions):

function draw() {
    background(0, 0, 100)

    // display original image
    image(img, 0, 0)

    // adjust brightness based on mouseX position
    let brightnessAdj = map(mouseX, 0, width, -10, 10); 

    // loop through each pixel in image and adjust brightness
    for (let y = 0; y < img.height; y++) {
        for (let x = 0; x < img.width; x++) {
            // get color values using pixels array
            // let index = (x + y * img.width) * 4; // index

            // let r = img.pixels[index + 0];
            // let g = img.pixels[index + 1];
            // let b = img.pixels[index + 2];
            // colorMode(RGB, 255, 255, 255)
            // let originalColor = color(r, g, b);

            // get color values using get()
            colorMode(RGB, 255, 255, 255)
            let originalColor = color(img.get(x, y));
            let hueValue = hue(originalColor);
            let satValue = saturation(originalColor);
            let briValue = constrain(brightness(originalColor) + brightnessAdj, 0, 100);

            // display new image using points
            colorMode(HSB, 360, 100, 100)
            stroke(hueValue, satValue, briValue);
            point(x + 300, y);
        }
    } 
}

I can display the original image and it looks great. However the image being created using points looks a bit pixelated. I assumed this had to do with the multiple conversion going on for each pixel color value that allow me to change the brightness value. I logged some values it does seem like some of the HSB values aren’t exactly as the should be. Sometimes the saturation or brightness functions return the HSL values not the HSB as I play around and try to find solutions. All of this seems like such a sloppy approach to what is rather easily done in Processing.

I don’t understand what I am missing about working with HSB values for images. I am at my wits end. I am willing to accept this cumbersome approach if it pixelation can be improved as in my actual use case I only need to adjust the values in a limited capacity. However, I would appreciate any insights or feedback to resolving this and/or doing it the proper p5.js way.

p5.js output
p5.js-output-example

You can see on the right side of the p5.js output example that there is a bunch of pixelation going on in the white background. The general sharpness is degraded across the image and I assume this is also for the same conversion reasons.

Thank you in advance

Hello @glosoli3,

A related topic:

:)

Thanks for the response. I came across this thread previously. I saw that the issues were from 2016 and 2020 respectively. Is this just an issue that has never been addressed? Do you recommend I look into using TinyColor? This just seems like such a foundational thing I can’t imagine there is no solution within the p5.js framework but I could be mistaken.

1 Like

Hello,

The issue seemed familiar and I shared what I could.

I can’t comment any further on this topic.

This user got TinyColor to work with some effort:

:)

Thanks again, I do appreciate it. I will keep exploring options.

1 Like

Another related topic:

:)

Hello @glosoli3 ,

See this topic:

I adjusted the strokeWeight in your code to 1.2 (gradually increased from 1.0) which seemed to remove the washed out look.

Before with strokeWeight(1) and background bleeding through:

image

After with strokeWeight(1.2):

Some modifications to your code:

let img;

function preload()
  {
  img = loadImage('http://learningprocessing.com/code/assets/sunflower.jpg');
  }

function setup()
  {
  createCanvas(400, 300);
  strokeWeight(1.2); // This got rid of washed out look!
  //noSmooth();
  }

function draw() {
  colorMode(RGB, 255, 255, 255);
  background(255, 0, 0, 255)
  // display original image
  image(img, 0, 0)

  // adjust brightness based on mouseX position
  let brightnessAdj = map(mouseX, 0, width, -10, 10);
  brightnessAdj = 0;

  // loop through each pixel in image and adjust brightness
  for (let y = 0; y < img.height; y++) {
    for (let x = 0; x < img.width; x++) {
      // get color values using get()
      colorMode(RGB, 255, 255, 255)
      let originalColor = color(img.get(x, y));
      let hueValue = hue(originalColor);
      let satValue = saturation(originalColor);
      let briValue = constrain(brightness(originalColor) + brightnessAdj, 0, 100);

      // display new image using points
      colorMode(HSB, 360, 100, 100);
      let col = color(hueValue, satValue, briValue);
      stroke(col);
      point(x + img.width, y);
    }
  }
}

I used latest p5.js Mode1.6 with the Processing 4.2 IDE on W10 with Google Chrome.

I also have scaling on my display:
image

Just a quick exploration of this… I am sure there is more to this than meets the eye.

:)