Modifying Images with tint and filter

In these notes you will learn:

  • How to change the transparency of an image using the tint function.
  • How to modify the entire screen using the filter function.
  • How to modify individual images by calling their filter function.
  • How to copy an image using get().

Introduction

The topic of image processing is a big and important one. Almost any software that deals with images does some sort of image processing, such as:

  • cropping or re-sizing images
  • changing colors or brightness
  • removing “noise”, such as dust due to a dirty lens
  • applying special effects, such as converting to black and white, sharpening, or blurring the image
  • finding faces

Here, we will only scratch the surface of image processing by looking at two useful Processing functions: tint and filter.

The programs below use these images: kandinsky.jpg, cat.jpg, and dog.jpg. If you want to run the programs on your computer, then add them to your program’s data folder.

The tint Function

One of the easiest ways to modify an image is to use the tint function. Using tint, we can do things like change an image’s transparency, or alter its overall color.

We will start with the program from Using Images in Processing that displays an image:

PImage img;

void setup() {
  // load the image file from the "data" folder
  img = loadImage("kandinsky.jpg");

  // set the window to be the same dimensions as the image
  size(1098, 757);
}

void draw() {
  // set the image's tint
  tint(100, 0, 204);  // bluish tint

  // display the image so that its upper-left corner
  // is on the upper-left corner of the screen
  image(img, 0, 0);
}

For this program to work, you must have a file named “kandinsky.jpg” in a folder named data in your program’s folder.

Just before the image is drawn on the screen, we set the tint like this:

tint(100, 0, 204);  // bluish tint

The RGB color (100, 0, 204) is a shade of blue, and so this gives the entire image a blue tint.

As you might imagine, changing the color you give to tint changes the overall coloring of the image, e.g.:

  • tint(221, 160, 221) gives the image a “plum” colored tint
  • tint(200, 200, 200) gives the image a light-gray tint
  • tint(0, 0, 0) makes the entire image black
  • tint(255, 255, 255) doesn’t change the image color at all

Changing Transparency with Tint

The tint function can also be used to set an image’s transparency. For example, consider this modified version of the above image-displaying program:

PImage img;

void setup() {
  // load the image file from the "data" folder
  img = loadImage("kandinsky.jpg");

  // set the window to be the same dimensions as the image
  size(1098, 757);
}

void draw() {
  background(img);

  // set a bluish tint, and a transparency level of 126
  tint(0, 153, 204, 126);
  image(img, mouseX, mouseY);
}

This program draws img twice: once as an untinted background, and then a tinted version at the mouse pointer. By moving the mouse around you can see the image really is transparent, i.e. you can see the background image behind it.

If you want to change an image’s transparency without changing its color, then use a white tint, e.g.:

tint(255, 255, 255, 126);  // change transparency only

The filter Function

Another easy way to modify the entire screen is to use the filter function. Consider this version of our standard image-drawing program:

PImage img;

void setup() {
  // load the image file from the "data" folder
  img = loadImage("kandinsky.jpg");

  // set the window to be the same dimensions as the image
  size(1098, 757);
}

void draw() {
  image(img, 0, 0);

  filter(THRESHOLD, 0.5);
  //filter(GRAY);
  //filter(INVERT);
  //filter(POSTERIZE, 4);
  //filter(BLUR, 6);
  //filter(ERODE);
  //filter(DILATE);
}

We’ve added a number of calls to filter, all but the first commented-out. The statement filter(THRESHOLD) converts the image to black-and-white. It does this, essentially, by calculating the brightness of each pixel in the image and converting the brighter ones to white, and the darker ones to black. It uses a brightness scale of 0.0 (minimum brightness, i.e. black) to 1.0 (maximum brightness, i.e. white). The 0.5 is called the threshold value, and you can get different results by changing it to other values in the range 0.0 to 1.0.

The comment-out filter statements work as follows:

  • filter(GRAY) converts all of the image’s color to shades of gray, i.e. grayscale.
  • filter(INVERT) sets each pixel in the image to its inverse color.
  • filter(POSTERIZE, 4) limits the red, green, and blue components of each pixel to only 4 colors.
  • filter(BLUE, 6) blurs the image. Higher values result in more blur.
  • filter(ERODE) reduce light areas.
  • filter(DILATE) increases light areas.

You comment/uncomment any combination of these filter calls to get a variety different special effects.

Note

In fact, with 7 different filter statements, there are exactly \(2^7=128\) different ways to turn them on/off.

Note that applying a filter to an image it must process every pixel of the image. So if you apply a lot of filters to a big image you might notice some delays.

Processing also lets you use shaders with filters, although it is a relatively advanced topic that we won’t go into here. If you are curious about this, this tutorial is a good place to start.

Filtering Individual Images

The filter function in the previous section is applied to the entire screen. If, instead, you want to apply a filter to a particular PImage, you can do that as follows:

PImage cat;
PImage dog;

void setup() {
  // load the image files from the "data" folder
  cat = loadImage("cat.jpg"); // 220 x 210
  dog = loadImage("dog.jpg"); // 240 x 180

  // apply some special effects
  cat.filter(POSTERIZE, 4);
  dog.filter(GRAY);

  // set the window to be big enough to display both images
  // side-by-side
  size(220 + 240, 210);
}

void draw() {
  // display the images side-by-side
  image(cat, 0, 0);
  image(dog, cat.width, 0);
}

This program uses two different PImage objects, cat and dog. They both load their own file, and then we call the filter function on the objects to apply a special effect.

To make the filter commands apply to just one image, we write, for instance, dog.filter(GRAY). If we had written filter(GRAY) instead, the entire screen, including both images, would have been grayscale.

Copying an Entire Image

Suppose you want to display two copies of the same image. While you could call loadImage twice, that’s inefficient. Instead, PImage objects let you make copies using the get() function like this:

PImage original;
PImage duplicate;

void setup() {

  original = loadImage("cat.jpg");
  duplicate = original.get();  // makes a new copy of original

  // ...
}

There are now two different copies of the “cat.jpg” in the program’s memory: one referred to by original, and the other referred to by duplicate.

Note

PImage objects also have a function called copy that you can use to make a copy of any sub-rectangle of an image. We could have used copy here, but get() is less typing.

Questions

  1. What are three different things an image processing program might do to an image?

  2. Describe, in English, how the following tints would change the color of an image:

    • tint(0, 0, 0)
    • tint(255, 255, 255)
    • tint(100, 0, 0)
    • tint(200, 0, 0)
  3. Write the tint statement that would set the transparency level of an image to 10 without changing its color.

  4. Explain this statement in English:

    filter(THRESHOLD, 0.5);
    
  5. Write the filter statements you would use to create a blurry grayscale version of a color image.

Programming Questions

  1. Modify the last program in the notes that shows the cat and dog pictures so that the instead of being drawn side-by-side, the cat is drawn on top of the dog. The two images not overlap.
  2. Modify the last program in the notes that shows the cat and dog pictures so that the image of the cat is shown twice. Call loadImage exactly once, and then use get() to copy it.