Image Processing in p5.js



Making Filters Using p5.js!


Marilyn BW Marilyn BW Marilyn BW Marilyn

  1. Black & White
  2. Sepia
  3. Negative

Black & White

In the RGBA color system, we get greys whenever the red, green, and blue values are the same. Having that in mind, the most basic (but not exactly accurate) way of creating a greyscale filter, is to get the average rgb value of each pixel, and setting the variables r, g, and b to that number. Lets create a variable called bw and set it to the average of rgb:

var bw = ( r + g + b ) / 3;


    function draw(){
        image(img, 0, 0, img.width, img.height);
        
        loadPixels();
        for (var y = 0; y < height; y++) {
            for (var x = 0; x < width; x++) {
              var index = (x + y * width)*4;
              var r = pixels[index+0];
              var g = pixels[index+1];
              var b = pixels[index+2];
              var a = pixels[index+3];     
              
              var bw = (r + g + b)/3;
              
              pixels[index+0] = bw;
              pixels[index+1] = bw;
              pixels[index+2] = bw;
        }
      }
      updatePixels();
    }
Vertigo


Awesome, you did it! You made a black and white filter. But if my previous statement saying that this method is not very accurate sparked your curiosity, I'll ellaborate. The human eye does not process all colors the same way. It actually prioritizes some colors over others. To create an accurate "average" of rgb values, we need to follow the luma formula, which give us the weights red, green, and blue actually have.

var luma = r*0.299 + g*0.587 + b*0.0114;


    function draw(){
        image(img, 0, 0, img.width, img.height);
        
        loadPixels();
        for (var y = 0; y < height; y++) {
            for (var x = 0; x < width; x++) {
              var index = (x + y * width)*4;
              var r = pixels[index+0];
              var g = pixels[index+1];
              var b = pixels[index+2];
              var a = pixels[index+3];     
              
              var luma = r *.299 + g *.587 + b *.0114;
              
              pixels[index+0] = luma;
              pixels[index+1] = luma;
              pixels[index+2] = luma;
        }
      }
      updatePixels();
    }
Vertigo


Sepia

Just like different colors have different weights in order to create a black and white filter, we need to prioritize certain colors to create a Sepia filter. However, unlike the Black & White filter, we don't have one formula we can use for all three colors (r,g,b). We need three different formulas: one for red, one for green, and one for blue. Sepia is a reddish brown color and to get effect, these are the values Microsoft recomends:

var tr = (r * 0.393) + (g * 0.769) + (b * 0.189);

var tg = (r * 0.349) + (g * 0.686) + (b * 0.168);

var tb = (r * 0.272) + (g * 0.534) + (b * 0.131);

Now we need to set our canva's r, g, b values to the values we just calculated:

r = tr;

g = tg;

b = tb;


    function draw(){
        image(img, 0, 0, img.width, img.height);
        
        loadPixels();
        for (var y = 0; y < height; y++) {
            for (var x = 0; x < width; x++) {
              var index = (x + y * width)*4;
              var r = pixels[index+0];
              var g = pixels[index+1];
              var b = pixels[index+2];
              var a = pixels[index+3];     
              
              //sepia
              var tr = r *.393 + g *.769 + b *.189;
              var tr = r *.349 + g *.686 + b *.168;
              var tr = r *.272 + g *.534 + b *.131;
              
              pixels[index+0] = tr;
              pixels[index+1] = tg;
              pixels[index+2] = tb;
        }
      }
      updatePixels();
    }
Vertigo


Negative

Creating a negative filter is going to be the easiest one so far! All you have to do is subtract the pixels, r, g, b values from white to reverse it. This sounds harder than it actually is, so we'll just show it to you:


    function draw(){
        image(img, 0, 0, img.width, img.height);
        
        loadPixels();
        for (var y = 0; y < height; y++) {
            for (var x = 0; x < width; x++) {
              var index = (x + y * width)*4;
              var r = pixels[index+0];
              var g = pixels[index+1];
              var b = pixels[index+2];
              var a = pixels[index+3];     
              
              pixels[index+0] = 255 - r;
              pixels[index+1] = 255 - g;
              pixels[index+2] = 255 - b;
        }
      }
      updatePixels();
    }
Negative


Just by playing around with which colors you reserse, you can create a full set of filters! Here are a couple more of examples:


    function draw(){
        image(img, 0, 0, img.width, img.height);
        
        loadPixels();
        for (var y = 0; y < height; y++) {
            for (var x = 0; x < width; x++) {
              var index = (x + y * width)*4;
              var r = pixels[index+0];
              var g = pixels[index+1];
              var b = pixels[index+2];
              var a = pixels[index+3];     
              
              pixels[index+0] = 255 - r;
              pixels[index+1] = g;
              pixels[index+2] = b;
        }
      }
      updatePixels();
    }
Vertigo



    function draw(){
        image(img, 0, 0, img.width, img.height);
        
        loadPixels();
        for (var y = 0; y < height; y++) {
            for (var x = 0; x < width; x++) {
              var index = (x + y * width)*4;
              var r = pixels[index+0];
              var g = pixels[index+1];
              var b = pixels[index+2];
              var a = pixels[index+3];     
              
              pixels[index+0] = r;
              pixels[index+1] = 255 - g;
              pixels[index+2] = b;
        }
      }
      updatePixels();
    }
Penelope


Credit to Crystal Chen and Paolla Bruno Dutra. Thanks to R. DuBois Luke and Tega Brain at NYU for mentoring :)