Creators – Pixels

543px-Liquid_Crystal_Display_Macro_Example_zoom

This week we looked at pixels. Your screen is made up of thousands of them; the picture on it is created by setting each one to the correct colour. We may ask P5 for an ellipse(), but ultimately some piece of code is deciding which pixels to change to the currently selected fill() colour (for the centre) and which to set to the currently selected stroke() colour (for the edges).

Working with Pixels in P5

P5 contains two main functions for working with pixels. The first is loadPixels(). By default it reads all the pixels from the canvas and copies the information into a huge array (or list) called pixels[].

If we then make a change to pixels[], all we have to do is call updatePixels() to copy this information back to the canvas again.

Sound easy? It almost is, but the content of pixels[] isn’t immediately obvious.

Structure of the pixels[] Array

The pixel[] array is one long list of numbers. It is arranged such all the information for the first row on the canvas is first, followed by the information for the second and so on until the bottom of the canvas.

For each pixel there are four numbers representing the red (R), green (G), blue (B) and alpha/transparency (A) value of the pixel. By the time the pixel has reached the  screen, alpha has no more meaning, so we will ignore it and concentrate on the RGB values.

This diagram represents what we’ve been talking about:

pixel diagram

Getting and Setting a Pixel

To make it easy to get and change the value of a specific pixel we can write two functions:

  • getPixel(x, y) which returns an array containing [r, g, b] values
  • setPixel(x, y, colour) where colour is an array containing [r, g, b] values

Both these functions rely on knowing where in pixels[] the data for the pixel at (x, y) is.

We can work out this as:

  1. Location of R: 4 * ((y * width) + x)
  2. Location of G; Location of R + 1
  3. Location of B: Location of R + 2

Knowing this, the functions can be written as:

function getPixel(x, y){
  let loc = 4 * ((y * width) + x);

  return [pixels[loc + 0],
          pixels[loc + 1],
          pixels[loc + 2]];
}

function setPixel(x, y, c){
  let loc = 4 * ((y * width) + x);
  
  pixels[loc + 0] = c[0];
  pixels[loc + 1] = c[1];
  pixels[loc + 2] = c[2];
}

FIlters
We wrote three filters, all very similar. Each used loops to go over each pixel in turn, retrieve the current colour, change it in some way and set it back.
The first was fade(amount) which took a number between 0 -> 1 for amount. It multiplied each of the original RGB values from the pixel with this value. The closer to zero amount was, the more it faded the image to black.
The second was invert(). It subtracted each RGB value from 255. This has the effect of inverting all colours in the image.
The final one was vignette(). This is like fade() but fades pixels depending on how close to the edge of the picture they are.
Animating Fade
Finally, we also animated fade() so that the picture started black and got brighter over a number of frames.
Putting all the filters together:

Download

The files for this week can be found on our GitHub repository.

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s