Search code examples
processingpixelnoise

Processing: Make only some random pixels change colour


I have created some white noise, which I would like to decrease over time (change starting after 2 secs, intensifying after 10 secs etc), slowly tending towards a black screen.

What I can't figure out is, how can I make only some (say, 50% of all pixels) random pixels change colour, while the rest is just black, within the same frame?

So far, I could only make ALL of them change randomly, or ALL of them stay black. Any help would be much appreciated, thank you!!

void setup() {
  size(1000, 800);
}

void draw() {
  if (millis() < 2000) {
    loadPixels();
    for ( int i=0; i<pixels.length; i++)
      pixels[i] = color(random(255));
    updatePixels();
  }

  if (millis() > 2000) {
    loadPixels();
    if (random(1) >= 0.5) {
      for ( int i=0; i<pixels.length; i++)
        pixels[i] = color(random(255));
      updatePixels();
    } else {
      loadPixels();
      for ( int i=0; i<pixels.length; i++)
        pixels[i] = color(0);
      updatePixels();
    }
  }

  if (millis() > 10000) {
    loadPixels();
    for ( int i=0; i<pixels.length; i++)
      pixels[i] = color(random(255));
    updatePixels();
  }
}

Solution

  • A simple way would be to take into account that random() returns a random value within a range. If you give it a low value, you'll have a low random value. If you use that value as a colour, the lower the value, the closer to black you are which might work well in your case.

    If you have a randomness to 255, you increase the changes of having bright pixels, otherwise(with low random values), pixels will be dark:

    //noise image
    PImage noise;
    //amount of noise image image 0 = 0%, 255 = 100%
    int noiseAmt = 255;
    
    void setup(){
      noise = createImage(width,height,RGB);
    }
    void draw(){
      //decrease noise over time
      noiseAmt--;
      if(noiseAmt < 0) noiseAmt = 255;
    
      //apply noise based on noise amount
      noiseImage();
      //render image
      image(noise,0,0);
    }
    
    void noiseImage(){
      int numPixels = noise.pixels.length;
      for(int i = 0 ; i < numPixels; i++){
        //random(noiseAmt) is the key - low values = darker pixels
        noise.pixels[i] = color(random(noiseAmt));
      }
      noise.updatePixels();
    }
    

    To get a hang of this, here's a slightly modified version of the code which uses the UP/DOWN arrow keys to control noise:

    //noise image
    PImage noise;
    //amount of noise image image 0 = 0%, 255 = 100%
    int noiseAmt = 127;
    
    void setup() {
      noise = createImage(width, height, RGB);
    }
    void draw() {
      //apply noise based on noise amount
      noiseImage();
      //render image
      image(noise, 0, 0);
    }
    
    void noiseImage() {
      int numPixels = noise.pixels.length;
      for (int i = 0; i < numPixels; i++) {
        //random(noiseAmt) is the key - low values = darker pixels
        noise.pixels[i] = color(random(noiseAmt));
      }
      noise.updatePixels();
    }
    void keyPressed(){
      if(keyCode == UP)   noiseAmt += 5;
      if(keyCode == DOWN) noiseAmt -= 5;
      noiseAmt = constrain(noiseAmt,0,255);
      println("noiseAmt: " + noiseAmt);
    }
    

    Back to the matter of time, you can have a look this answer which covers tracking time using millis(). The only extra part is mapping the fade time to the noise amount, which would be some ratio. It might be easier if we map the time passed as a normalised value (from 0.0 to 1.0) which can easily scale to 0.0 to 255.0 simply by multiplying by 255:

    //noise image
    PImage noise;
    //amount of noise image image 0 = 0%, 255 = 100%
    int noiseAmt = 255;
    
    int timestamp,fadeTime = 10000;//fade to black in 10s
    
    void setup(){
      noise = createImage(width,height,RGB);
      timestamp = millis();
    }
    void draw(){
      //decrease noise over time
      int now = millis();
      //if the difference between an initial timestamp and the current time is less than 10s
      if(now - timestamp <= fadeTime){
        //compute the ratio between the time difference and total fadeTime which will be from 0.0 to 1.0
        //subtract this difference from 1.0 to flip the ratio direction from 0.0 -> 1.0 to 1.0 -> 0.0 
        float fadeRatio = 1.0 - ((float)(now-timestamp)/fadeTime);
        //this ratio multiplied to 255 will be
        noiseAmt = (int)(fadeRatio * 255);
      } 
    
      //apply noise based on noise amount
      noiseImage();
      //render image
      image(noise,0,0);
    }
    
    void noiseImage(){
      int numPixels = noise.pixels.length;
      for(int i = 0 ; i < numPixels; i++){
        //random(noiseAmt) is the key - low values = darker pixels
        noise.pixels[i] = color(random(noiseAmt));
      }
      noise.updatePixels();
    }
    

    Processing has some nice functions for dealing with mapping and constraining number ranges:

    //noise image
    PImage noise;
    //amount of noise image image 0 = 0%, 255 = 100%
    int noiseAmt = 255;
    int timestamp,fadeTime = 10000;//fade to black in 10s
    
    void setup(){
      noise = createImage(width,height,RGB);
      timestamp = millis();
    }
    void draw(){
      //decrease noise over time
      int now = millis();
      //if the difference between an initial timestamp and the current time is less than 10s
      noiseAmt = (int)map(now - timestamp,0,fadeTime,255,0);
      noiseAmt = constrain(noiseAmt,0,255); 
    
      //apply noise based on noise amount
      int numPixels = noise.pixels.length;
      for(int i = 0 ; i < numPixels; i++){
        //random(noiseAmt) is the key - low values = darker pixels
        noise.pixels[i] = color(random(noiseAmt));
      }
      noise.updatePixels();
    
      //render image
      image(noise,0,0);
    }
    

    Note the fadeTime is set to 10s (10000 milliseconds). Feel free to tinker with the fadeTime value.