Today’s Groups

GroupMembers
ATalia, Jane
BDorothy, Sachi
CJonathan, Bateel
DAmber, Sanie
EJennifer, Danielle
FKim, Gabriel

Thoughts

Study Tips (from me)

Studty Tips (from you)

Homework Review

  1. 😍 🤓 😂
  2. Look at the work you and your partner created this week. Choose 1 sketch of your partner’s that is interesting and deserves more polish.
    1. Write down the primary strength of the piece. Be specific.
    2. Write down the primary weakness of the piece. Be specific.
    3. Write down 5 suggestions for how to polish the sketch. Be specific and clear.

Be prepared to present your assessment and suggestions to the class. You will have 30 seconds.

Pixel Processing Examples

Pixel Processing Examples

Today’s Learning Objectives

Reading

Assignment

Sketch! Explore working with images pixels.

Post at least one sketch for each of the following:

This week, most of your posts should be still images. You might also consider creating animations. Since p5 pixel access is slow, this technique will pair well with pre-rendering.

Optional Challenge: Ouroboros

Create code that processes an image. Feed the result back into your code. Repeat. What happens after several generations? Post your source image, the result after one generation, and the result after several generations. Alternately, capture 90 generations as frames and post as a video.

Writing Pixel Data

A Basic Example

Let’s look at the example above in depth:

Line 8 uses createImage() to create a new, empty image in memory. We can draw this image just like an image lowed from a .jpg or .gif.

Line 9 uses loadPixels() to tell p5 that we want to access the pixels of the image for reading or writing. You must call loadPixels() before using set(), get(), or the pixels[] array.

Lines 11 + 12 sets up a nested loop. The inner content of the loop will be run once for every pixel.

Line 13 uses the color() function to create a color value, which is assigned to c. Color values hold the R, G, B, and A values of a color. The color function takes into account the current colorMode().

Line 14 uses set() to set the color of the pixel at x, y.

Line 18 uses updatePixels() to tell p5 we are done accessing the pixels of the image.

Line 20 uses noSmooth() to tells p5 not to try to smooth the image when we scale it. This is like telling photoshop to use ‘nearest neighbor’ when scaling an image.

Line 21 draws the image, filling the canvas so we can clearly see each pixel.

A Gradient Example

This example has the same structure as the first one, but draws a gradient pixel-by-pixel.

A Third Example

The first two examples use a nested loop to set a value for every pixel in the image. This pattern often used in pixel generating and processing scripts, but not always. This example places red pixels at random places on the image.

In-class Challenge

Explore using p5’s pixel manipulation functions by modifying the scripts above. Work through the following challenges in order. Don’t skip any.

TimeComment
< 13 in 20 MinutesYou need to put in some extra work to strengthen your programming understanding.
13 in 20 MinutesGood.
All in 20 MinutesGreat.
All in 15 MinutesHot Dang!

Modify the Basic Example

  1. Change the image resolution to 20x20
  2. Change the image resolution to 500x500
  3. Change the image resolution back to 10x10
  4. Make each pixel a random shade of blue.
  5. Make each pixel a random shade of gray.

Modify the Gradient Example

  1. Make a horizontal black to blue gradient.
  2. Make a vertical green to black gradient.
  3. Make a horizontal white to blue gradient.
  4. Make a vertical rainbow gradient. Tip: colorMode()
  5. Create an inset square with a gradient, surrounded by randomly colored pixels.

Modify the Third Example

  1. Change the image resolution to 50x50, adjust scatter to fill.
  2. Instead of drawing single pixels, draw little + marks at random locations.
  3. Make each + a random color.

Challenging Challenges

  1. Color each pixel with noise() to visualize its values.
  2. Make a radial gradient from black to red. Tip: dist()
  3. Create a diagonal gradient.
  4. Use sin() to create a repeating black to red to black color wave.
  5. Create a 128x128 image and set the blue value of each pixel to (y&x) * 16

Reading Pixel Data

Read Pixels Example 1

Let’s look at the example above in depth:

First we need to load an image to read pixel data from.

Line 3 declares a variable to hold our image.

Line 5 begins the preload() function. Use this function to load assets.

Line 6 loads the image.

With our image in hand we can process the pixels.

Lines 18 + 19 sets up a loop like in the writing examples above.

Line 20 uses get() to load the color data of the current pixel. get() returns an array like [255, 0, 0, 255]. That would be a red, fully alpha’d color.

Lines 22, 23, 24 accesses the red, blue, and green parts of the color.

Line 25 codereates the new color for the pixel by multiplying the current color values with a random 0-1 value.

Line 27 updates the pixel in the image data.

Line 28 uses updatePixels() to tell the image there has been an update. We didn’t need to do this in every pass through the loop when we were just setting pixels, but here we mix set and get and it appears this is now needed. This might be a bug in p5.js.

Read Pixels Example 2

Image as Input Example

In-class Challenge 2

Explore using p5’s pixel manipulation functions by modifying the scripts above. Work through the following challenges in order. Don’t skip any.

TimeComment
< 10 in 20 MinutesYou need to put in some extra work to strengthen your programming understanding.
10 in 20 MinutesGood.
All in 20 MinutesGreat.
All in 15 MinutesHot Dang!

Modify Example 1

  1. Colorize the white pixels with a vertical black to red gradient.
  2. Colorize the black pixels with a vertical black to green gradient.
  3. Feed the program you made above a grayscale or color image (under 100x100). You’ll have to do this in your own editor, you’ll need a local server.

Modify Example 2

  1. Change the color comparison to >.
  2. Change the color comparison to !=.
  3. Change out_color to an average of the two color samples.
  4. Feed the program you made above the grayscale earth image above.

Modify Example 3

  1. Invert the drawing, so that circles appear where the input pixels are black.
  2. Feed the program you made above the grayscale earth image above.
  3. Use lightness to drive the circle sizes.

Challenging Challenges

  1. Start with the original Example 2 code, without your changes. Set out_color to the average of this_color and below_color.
  2. Change worldImage.set(x, y, out_color); to worldImage.set(x, y+1, out_color);.
  3. Remove the conditional statement (keep its contents).

The Canvas + Pixel Density

When accessing the pixel data of the canvas itself, you need to consider the pixel density p5 is using. By default p5 will create a 2x resolution canvas when running on a high-dpi (retina) display. You can call pixelDensity(1) to disable this feature. If you don’t, you’ll need to take into account the density when calculating a position in the pixels[] array.

The examples on this page work with the pixels of images instead of the canvas to avoid this issue all together.

Performance

The built-in p5 someImage.get(x, y) function gets the RGBA values of a pixel in an image. As noted in the reference, the get call is slower than accessing the values in the .pixels array directly. In fact, get() can be 1000s of times slower. You can use the following function to grab the pixel values more quickly.

// find the RGBA values of the pixel at x, y in the img.pixels array
// use instead of p5s built in .get(x,y), for much better performance (more than 1000x better in many cases)
// see: http://p5js.org/reference/#/p5/pixels[]
// we don't need to worry about screen pixel density here, because we are not reading from the screen

function getQuick(img, x, y) {

    var i = (y * img.width + x) * 4;
    return [
        testImage.pixels[i],
        testImage.pixels[i+1],
        testImage.pixels[i+2],
        testImage.pixels[i+3],
    ];
}

Copy the getQuick() function above into your sketch. You can then replace a built in p5 get call with a call to getQuick:

c = img.get(x, y);

becomes

c = getQuick(img, x, y);

Study Example

cf.png

Misc Links

Reaction Diffusion in Photoshop, Factorio, Icon Machine