CS 151: Lab 4

Title image Project 4
Fall 2019

Lab Exercise 4: Images

The main purpose of this lab is to give you the tools you need to complete an image-manipulation project. You will be using John Zelle's graphics package. Here is the reference guide.

Tasks

  1. Setup

    In your personal file space, make a folder called Project4. Then download the following files to it.

    Open a text editor (e.g TextWrangler). Create a new file called show.py. Put a comment at the top of the file with your name and the date. Save it in your Project4 folder.

  2. Get ready to code

    After the comment line, write the command to tell Python to import the graphics package, the display package, and the sys package:

    import graphics
    import display
    import sys

    Download one of the following images to use in the lab exercises. You should right-click on the Image and do "Save Link As..."

    If you want to use your own images, check out the more detail section.

    + (more detail)

    If you would like to use any additional photos, then you may want to make the images smaller for testing. On the lab computers, You can use the convert program to change the size of any image. (Note: if you want to use convert on your own computer, you will need to install ImageMagick. Alternatively, you can use a web-based image-converter.)

    convert myImage.jpg -scale 25% mySmallImage.jpg

    You can also change an image of one format to a different format. The Zelle graphics library can open only PPM format images, not JPGs. You can change a JPG to a PPM using one of the following examples.

    convert myImage.jpg myImage.ppm

    PNG and JPG images are the formats for you will need to use for your reports or for web pages. Note that you can change the format and change the scale at the same time.

    convert myImage.jpg -scale 25% myImage.ppm

    The convert program is a very powerful application for manipulating images. If you want to find out more about it, check out the ImageMagick web site.

  3. Write a program to read and display an image

    The first thing we're going to do is create a simple program that will read image data from a file and display it in a window. We'll use the command line to specify the filename of the image to view.

    Create a main function in your show.py file. Give it one argument, argv, which will be the list of strings from the command line. One of these strings should be the filename of the image to open and view. The main function should do the following.

    1. Check if the user provided enough command-line arguments

      Test if there are at least two strings in the main function parameter: the name of the python program and the filename of the image to open. If there are not at least two strings, print a usage message and exit using the exit() function. Use the len() function to test how many strings there are in the argv list.

    2. Use the graphics.Image function to read image data from a file

      Load image data from the file specified in the second string of the main function parameter into an Image. Assign to a variable (e.g. src) the result of calling the function graphics.Image() with a Zelle Point object (graphics.Point(0, 0)) as the first argument and the filename as the second argument. The filename will be the second element in the list argv that is the parameter of your main function. Assign the return value of the graphics.Image function to a variable.

      Use an assignment statement any time you need to store, retain, or assign information. In this case, we want to store the Image object created by the graphics.Image() function call. Therefore, put a variable name on the left side of an assignment and the graphics.Image() function call on the right.

    3. Display the image in a window using display.displayImage

      Use the displayImage function in the display package (display.displayImage()) to create a window and display the Image.

      The displayImage function takes two arguments, which are the Image to display and the title to be displayed in the window. You could use the filename as the title of the window. The displayImage function returns a window reference, which you need to assign to a variable. That means the variable to hold the window reference must be on the left side of an assignment and the function call must be on the right.

    4. Wait for user input

      Finally, call the getMouse method of the window. That means you type the name of the variable holding the window reference, then .getMouse() to call the method. This will wait for a mouse click in the window and then go on to the next instruction. If there is no next instruction, the program will terminate.

    Below the main function, put a conditional call to it, using the method we learned last week. Pass the main function the list sys.argv.

    if __name__ == "__main__":
        main(sys.argv)

    Once complete, try out your show function. On the terminal, make sure you are in the correct working directory and then run your program with an image filename as a command line argument.

    python3 show.py geraniums.ppm
  4. Manipulate the pixels of an image

    The second thing we're going to do in lab is figure out how to manipulate pixels in an image. Each pixel in a color image has three values (r, g, b). Each pixel is addressed by its row and column. There are rows x columns pixels in an image. The Image object has two methods that let you access and modify pixels.

    • getPixel( col, row ): returns the (r, g, b) tuple located at (col row)
    • setPixel( col, row, color): assigns the given color to the image at (col, row)

    The following shows an example of how you might use these functions, where src is the variable holding your Image object.

        (r, g, b) = src.getPixel( 42, 35 )
        src.setPixel( 42, 35, graphics.color_rgb(b, g, r ) )

    The Image object also has two methods that let you access the image height (number of rows) and image width (number of columns).

    • getWidth(): return the number of columns in an image
    • getHeight(): return the number of rows in an image

    The following is an example of how to use them with an Image object src.

        num_rows = src.getHeight()
        num_cols = src.getWidth()

    If you want to practice accessing or modifying pixels, you can edit your show.py function in between creating the image and displaying the image.

  5. Start a library of photo filters

    Create a new file called filter.py. Do the usual stuff of putting your name and a date at the top. Then import graphics and sys. Save it in your Project4 directory.

    In filter.py, create a function named something like swapRedBlue that takes in one argument, which will be a Image object. The algorithm is written below as comments, properly indented. Read through them and make sure you understand the process. Then fill in the python code. After the Python code has been written, please remove these comments. They do not make the code any more readable, as they are just the English version of the code.

    The number of rows in the image is provided by src.getHeight() if src is the Image object. The number of columns in the image is provided by src.getCol

    def swapRedBlue( src ):
        # for each row row_idx in the image
            # for each column col_idx in the image
                # assign to (r, g, b) the pixel values at (col_idx, row_idx)
                # set the pixel indexed by (col_idx, row_idx)  to the value (b, g, r)
        
  6. Test your photo filter

    Create a new test function in filter.py (this is a different function than swapRedBlue) that takes in an argument which is the list of strings from the command line.

    A simple option is to copy the main function from show.py and then call swapRedBlue(src) after reading the image and before displaying it.

    You can also save an image to a new file. If your Image variable is src, you can save it to the file myfilename.ppm by using the following.

    src.save('myfilename.ppm')

    You can pass whatever filename name you want to the save function. I'd recommend not having spaces in the name.

    At the end of your filter.py file, put a call to your test function behind a conditional that tests the value of the __name__ variable, as we did last week.

    if __name__ == "__main__":
        main( sys.argv )

    Note that this is the only place in your filter.py file where you should use the sys.argv variable. if you are using it in any of your functions, then you are not making proper use of the function parameters.

    When you are done, run your filter.py program, giving it an image filename as the argument. Then look at the result with your show program. Now, perhaps, you see why command line parameters are useful.

When you are done with the lab exercises, you may begin the project.