Program 8: Image Processing

For this program, you will be modifying image files. The image format we are going to use is called PPM, which stands for Portable Pixmap format. Don't worry if you're not familiar with PPM images, they are not used much these days. Their main advantage for this project is that they are stored as plain text files, they are easy to easy to read from and write to files, and they can easily be stored in Python lists. Formats like GIF, JPEG, or PNG are not so easy to work with, unfortunately. We describe the way PPM images work later in this document.

The main disadvantage to PPM images is that they take up a lot of storage space on your computer as compared to formats like JPEG or PNG. Most modern image formats use some kind of compression to make their size reasonable while preserving the image appearance. PPM images are not compressed at all.

Mac computers come with the built-in ability to open and read PPM images (you can double-click on them and they'll open in Preview). Windows computers, unfortunately, do not have this ability built-in, so you will want to download a program to view PPM files. IrfanView is a small program you can use to do this (click here to download IrfanView for Windows). IrfanView will also allow you to convert your own images to PPM so you can practice with your own pictures (keep in mind that you may need to make them very small or the resulting PPM will be quite large!).

PPM Image Format

The various colors in an image are represented in a PPM file as RGB triples, where RGB stands for red-green-blue. This is a standard way of representing colors.

RGB Triples

An RGB triple is three numbers, usually between 0 and 255, that when taken together, represent a color. The three numbers specify different intensities of red, green, and blue, that are then mixed together to create one color. For instance, the color red is represented by (255, 0, 0). The 255 as the first number means "all the red," and the two zeroes mean "no green and no blue." That color red looks like this:          . The RGB color (0, 255, 0) would be all green, like this:          , and (0, 0, 255) would be all blue:          . Black is (0, 0, 0) and white is (255, 255, 255).

By varying the numbers, you can make almost any color. For instance, yellow          is (255, 255, 0), purple          is (128, 0, 255), and a medium gray          is (128, 128, 128). Try playing around with RGB values at this link and see what colors you can make.

Inside a PPM file

The PPM image format encodes an image by simply listing, in order, the color of every pixel in the image, one by one, row by row, top to bottom. Recall that a pixel is an individual dot of light on your computer's screen.

The PPM image format is encoded in human-readable plain text. A PPM image has two main parts: the header followed by the body.

PPM Header

The PPM header is always the first three lines in the file. Here is an example:

P3
4 4
255

PPM images have a few different encoding conventions; the first line of the file specifies the specific type of encoding that the file uses. For this project, we will always use the "P3" specification, so the first line of our files will always be P3.

The second line of the header always contains exactly two numbers. These are the dimensions of the image in pixels: the first number is the width (number of columns), and the second is the height (number of rows). In the example above, we have a 4 pixel by 4 pixel image. Remember that a pixel is an individual point of light on your screen, so a 4-by-4 image will appear incredibly small --- probably too small to actually examine closely.

The third line of the header always contains exactly one number. This number indicates the maximum value for each red, green, and blue (RGB) element in the picture. We will always use a max value of 255.

PPM Body

Below the header is the body of the PPM file. Each row of the file specifies a row of the image as RGB triples. For example, the body content of our 4x4 image might be:

255 0   0       0   255 0      0   0   255    255 255 255
0   0   0       255 0   0      0   255 0      0   0   255
255 0   255     0   0   0      255 0   0      0   255 0
0   255 255     255 0   255    0   0   0      255 0   0

With these values, the pixel in the first column and first row has a RGB value of (255, 0, 0), which is red. The pixel in the last column and the first row has a RGB value of (255, 255, 255), which is white. The spacing of the numbers on each line doesn't matter, as long as there is at least one space separating each number.

A blown-up image containing these values would look like this:

You can download this PPM image here and open it in a text editor (IDLE, Notepad, or TextEdit) to take a look at it.

A larger example PPM image

Download this PPM image of the Rhodes College Byran Campus Life Center: bclc.ppm. Again, you can open the image with software such as IrfanView to view it as an image. You can also open it as a text file (directly in IDLE, for instance, or you can open it in Notepad on Windows or TextEdit on Mac) to view it as plain text (useful for debugging your code!).

How your program will work

Your program will prompt the user for the name of a PPM image file to read from. Then your program will the user for what modifications they would like to make to the file. The possible modifications are:

  1. Invert red
  2. Invert blue
  3. Invert green
  4. Invert all
  5. Remove red
  6. Remove blue
  7. Remove green
  8. Flip horizontally
  9. Grey scale

Your program should output (write) a PPM file with the modifications made to the input PPM file. The output file name should include your name as well as the name of the modification that you did to the file.

How to get started

  1. Begin by downloading the starter code here. Read it over and familiarize yourself with it. The program will come together by writing a series of functions. First, write the function make_output_filename. Be sure to add your name to the file name. Test it in the Python shell. Here are some examples:

    >>> make_output_filename("bclc.ppm", 2)
    'bclc_kirlin_phillip_invert_blue.ppm'
    
    >>> make_output_filename("bclc.ppm", 9)
    'bclc_kirlin_phillip_grey_scale.ppm'
  2. Write the functions invert, flatten, average3, and reverse. Read the comments above each function in the starter code to understand how these functions should work. Test these functions from the Python shell, by calling them manually with different input lists. Here are some examples:

    >>> invert([1, 2, 3, 200, 100, 150])
    [254, 253, 252, 55, 155, 105]
    
    >>> flatten([1, 2, 3, 200, 100, 150])
    [0, 0, 0, 0, 0, 0]
    
    >>> reverse([2, 1, 5, 4, 3, 6])
    [6, 3, 4, 5, 1, 2]
    
    >>> average3([1, 200], [2, 100], [3, 150])
    [2, 150]
  3. Write the function ppm_to_lists. This function takes a line of text from the body of a PPM image and converts it into three lists, one each for the red, green, and blue values. Follow the guide in the code, making sure to end your function by returning all three lists at once (try: return red, green, blue as the last line of code).

    Test from the Python shell:

    >>> ppm_to_lists("1 2 3 4 5 6 7 8 9")
    ([1, 4, 7], [2, 5, 8], [3, 6, 9])
    
    >>> ppm_to_lists("20 50 70 40 80 90 0 100 50")
    ([20, 40, 0], [50, 80, 100], [70, 90, 50])
  4. Write the function lists_to_ppm. This function takes is the opposite of the previous function: it takes three lists of RGB values and converts them into a single line of text that will go into the body of the PPM file. Follow the guide in the code, making sure to attach a newline character to your string before you return it (if your string is called answer, try doing answer += "\n" right before you say return answer.

    Test from the Python shell:

    >>> lists_to_ppm([1, 4, 7], [2, 5, 8], [3, 6, 9])
    '1 2 3 4 5 6 7 8 9 \n'
    
    >>> lists_to_ppm([20, 40, 0], [50, 80, 100], [70, 90, 50])
    '20 50 70 40 80 90 0 100 50 \n'
  5. Fill in the gaps in the code in process_file. Look for YOUR CODE HERE. You can uncomment the call to main() at the end when you start working on this. You shouldn't have to modify any of the code in main except where it says YOUR CODE HERE, with the exception of maybe uncommenting the print(lineout) statement to see the output as its written to the file. Comment it back out before you submit, however!

  6. Add in an input validation loop to the main function so that if the user selects a modification outside of the 1-9 range, they are prompted to re-enter the number.

How do I know when my program works?

You should begin by testing on the fourbyfour.ppm image from above. You can download it again here. Try running this image through all nine modifications and look at the output files that are generated. You can also print out the lines as they are written to the file to verify they make sense.

When you're ready to test with larger files, you can try these BCLC images:

Original

bclc.ppm:

Invert Red

bclc_invert_red.ppm:

Invert Blue

bclc_invert_blue.ppm:

Invert Green

bclc_invert_green.ppm

Invert All

bclc_invert_all.ppm

Remove Red

bclc_remove_red.ppm:

Remove Blue

bclc_remove_blue.ppm:

Remove Green

bclc_remove_green.ppm

Flip Horizontally

bclc_flip_horizontally.ppm

Grey Scale

bclc_grey_scale.ppm

More images to test on

barrett.ppm

rhodes-campus.ppm

lynx.ppm

ny.ppm

What to turn in

Through Moodle, turn in your code as a file called images_yourLastName_yourFirstName.py.

Challenge problems