Image courtesy of Little Green Footballs.
Images are a powerful way of conveying information and computers give us powerful way of modifying images. This lab involves manipulating pixmaps by transforming each color in the original pixmap using the same algorithm (such as darkening, inverting, posterizing, coverting it to grey scale). Your program will then perform several operations on these images to acheive a larger effect.
Images are stored by computers in a variety of formats, such as GIF, JPG/JPGEG, TIFF, and PNG. These formats differ in how faithfully they represent the original picture, how well they can be compressed to reduce the space each image takes up, or how well they can be copied from one type of computer to another. However, no matter what format the image is stored in, it can always be represented as a mapping of (x, y) pixel position to a color (the range of colors may be restricted to values of grey or just black and white). Thus, for the remainder of this project, we will refer to all formats of digital images as images.
This week's lab introduces you to the Python Imaging Library (PIL) which provides a simple interface for processing images. We will create basic color filters (RGB color model) that can be applied to images then combine them to create larger effects.
TinEye is a search engine whose queries are images and whose search results are places that this image can be found. When you get a chance, experiment with it to try to figure out how it works. Can the search results be different file formats than your query (e.g., JPEG vs. GIF)? How much detail/quality can you leave out of the image without throwing off the results?
Start by snarfing the Lab 8 code from the class website. Alternatively, you can browse code here .
In this lab we will be using a few functions from Python's Image library (shown in the code snippet below). This code opens an image, displays the image, gets all RGB pixel values from the image, sets each pixel's red value to zero, and then displays the image again.
The images displayed are shown below, unaltered on the left, no red on the right.
![]() | ![]() |
The image above is included in your snarf files. If you accidentally overwrite the original with a transformation, you can re-download the image here. It depicts custom made vases from Tsuga Studios
Here's a brief summary of the Image
methods we will use in this lab (although PIL provides many more).
Image.open(image_filename)
, opens an image
file. To use the image in a program
assign it to a variable. You'll need
to convert all opened images to RGB format, e.g., use the
convert
function as shown.
img.getdata()
returns all of the pixels
from the image, where each pixel is a tuple of 3
integers, representing the red, green, and blue channels of the pixel. Each of these
values is between 0 and 255, inclusive. The following
example:
list_pixels = im.getdata() for pixel in list_pixels: print pixelcould show something like this, depending on the RGB values in the image.
[(255, 0, 0), (0, 255, 0), (0, 0, 255), ... ]
img.putdata(list_pixels)
takes a list of pixels as an argument (it must have length equal to the
original image's size) and stores these pixels into img
's
internal representation of the image.
im.show()
displays the image using the
default image viewer on your computer.
In the first part of the lab you'll write several filter functions. Each one takes a single (R,G,B) tuple, changes the values or R, or G, or B (or all of them or none of them) and returns a new (R,G,B) tuple. See the explanation below.
We have started by developing a framework for image filters in
Python in the module ImageProcessing
. It works by
applying the filters you write to each pixel of the image. You should
implement each of the following filters: test each one, see if
the image looks like the altered blue-devil.
Invert. Create a photographic negative of the image by inverting each of the three RGB channels of the pixel. For example, if the pixel has the values (255, 0, 128) for its red, green, and blue channels, respectively; then the resulting color should have the values (0, 255, 127). In other words, each value is the other's opposite within the range of possible values from 0 .. 255. Thus, if this operation is performed on an image twice in succession, the image would appear unchanged. Darken. Darken the image by reducing the values of each of the three RGB channels of the pixel by 25% of their original value. Be careful not to produce a color value outside the range of possible values from 0 .. 255. Don't forget to make the R,G,B values of each tuple an int
, e.g., if R is 255, then 255*0.75 = 191.25, but you need that to be an int value like 191 --- just useint(R*0.75)
.Brighten. Brighten the image by increasing the values of each of the three RGB channels of the pixel by 25% of its original value. Note, this method should exactly undo the results of performing the Darken filter (as long as none of the image's colors are already as dark as possible), so that doing one operation then the other should result in no net change in the image. Be careful not to produce a color value outside the range of possible values from 0 .. 255. GreyScale. Create an image that has only shades of grey values by computing the average value of the pixel's three RGB channels and using that average value for all three channels of the new color. For example, if the pixel has the values (255, 0, 128) for its red, green, and blue channels, respectively; then the resulting color should have the values (127, 127, 127). Posterize. Create a posterized version of the image by reducing its total number of colors. To do this, you should restrict the values each of the three RGB channels of the pixel so that it takes on four distinct values based on a level-range. Specifically, if the value of each R,G,B is between 0 and 63 inclusive, it should be set to 50; if the value is between 64 and 127 inclusive, it should be set to 100; if the value is between 128 and 191 inclusive, it should be set to 150; and if the value is between 192 and 255 inclusive, it should be set to 200. In this way, the 256 possible values each channel can have is resticted to just 4. Solarize. Create a solarized version of the image by inverting the values of each of the three RGB channels only if they are too dark, i.e., less that 128. To do this, you should check the value of each channel and only if it is less than 128, invert its value (i.e, subtract it from 255). For example, if the pixel has the values (255, 0, 128) for its red, green, and blue channels, respectively; then the resulting color should have the values (255, 255, 128).
Test these filters by experimenting with them singly and in
combinations in the Python module FilterEffects
.
Answers here on handin pages, also see end for submitting code.
This image has been shot with a broken camera. The results of the technical inspection concluded that the camera light sensor gave random values for the blue and green channel, while it was diminishing the value of red channel by a factor of roughly 10 times. We would like to "denoise" the picture in such a way it is interpretable by humans by removing the "bad" color channels (blue and green) and enhancing the valid one (red).
denoise
to return an (R,G,B)
tuple in which the R value is unchanged, and the G, and B values
are set to zero. Apply this filter to the image noise.png,
what does it look like?
Answer on handin page.
denoise
so that the red value
is multiplied by 10 (and the G, and B values are zero). Run this filter
on the images noise.png and iron-puzzle.png. What are
the resulting images and from what city do they come?
Answer on handin page.
Answer on handin page.
clue2.bmp
(check clue.bmp too). To find the hidden message you should change
every completely red pixel, e.g., (255,0,0) to black which is all
zeros. You should also change any white image (all 255 values)
to black as well. When you do this you'll find a hidden
message. What is the hidden message?
Answer on handin page.