CSCI 150: Lab 4

Pictures and Functions
Due: 10PM on Tuesday, March 3rd

The purpose of this lab is to:

  • Gain practice using and creating functions
  • Get (much more) practice with nested loops
  • Implement a basic photo editor

Before you begin, please create a folder called lab04 inside your cs150 folder (for a refresher, here's how you did this on lab 02). This is where you should put all files made for this lab.

Part 1 - Primes

primes.py: 13 points

As you may know, a number x is said to be prime if x is at least 2, and the only proper factors of x are itself and 1. So the first few primes are 2, 3, 5, 7, 11, 13, 17, 19, 23, etc. 4 isn't prime, since it is divisible by 2. Same goes for 6 and 8. 9 is out thanks to 3. And so on. There are a lot of primes. More precisely, there are infinitely many primes.

A twin prime is a pair of prime numbers that differ by exactly 2. So (3,5), (5,7), (11,13), (17,19) and (29, 31) are all twin primes. Note that not every prime is part of a twin prime. It is conjectured that there are infinitely many twin primes too, but no one knows for sure.

Describe the Problem

Write a program called primes.py that prints out some number of primes and the number of twin primes amongst them.

Input: A number n.
Output: The first n primes, and the number of twin primes amongst these n.

Understand the Problem

If the user enters 13 then the output should be

  The first 13 primes are:
  2 3 5 7 11 13 17 19 23 29 31 37 41
  Amongst these there are 5 twin primes.
                          
Note that (41, 43) is a twin prime, but we didn't count it since 43 wasn't amongst the first 13 primes.

Design an Algorithm

Write pseudocode to solve this problem. You should decompose your main algorithm into small manageable chunks. For example, you should:

  • design a function that takes in an integer x and determines whether x is prime. For example, "isPrime(10)" would return false, while "isPrime(31)" would return true.
  • make liberal use of this isPrime function to generate the first n primes.

Implement a Design

You may want to use a while loop as you search for primes, since you won't know ahead of time just how far you need to go.

Test the Program

Try your program with a variety of inputs n. Certainly you should try n=0,1,13 but you should also try n=14 to get that one extra twin prime, as well as others! You should use try/except and while loops to catch any exceptions if the user enters a negative number or something that is not an integer.

Handin

Please handin what you've completed thus far.

Part 2 - Image Manipulation

imageEdit.py: 25 points

In this portion of the lab you'll create a program that reads in an image and does a sequence of modifications to that image, as specified by the user. Things like inverting the image, mirroring it, increasing or decreasing the contrast, etc. In doing so, you'll get more practice with nested for loops, while loops, creating functions and using objects.

To be able to edit individual pixels, we will be using an image module called picture2.

Describe the Problem:

Write a program called imageEdit.py that provides the user with image editing functionality. The user should first be prompted to enter a file name. That file should be loaded and displayed. Then the user should be presented with a list of filters that can be applied.

Understand the Problem:

Your program should be capable of the following operations:

  1. Make Negative OR Make Grayscale (choose one and implement it)
  2. Flip Horizontally
  3. Scroll Horizontally
  4. Zoom
  5. Your Choice: (Pick one -- Blur, Posterize, Increase Contrast, etc.)
  6. Quit
Examples of these operations are given below.
Original Image:
original
Negative: Greyscale:
flip mirror
Flip: Scroll:
scroll negative
Zoom:
zoom
Other Ideas
Posterize: Blur:
poster scroll
Find Edges: Tiled:
find edges tiling
Shear: Bizarre:
shear bizarre
Contrast:
negative

Design an Algorithm:

Your program should begin by printing a welcome to the user, informing them just how fortunate they are to have stumbled upon your very own image editor. You should then prompt the user in the console to pick a file to load in. As will be standard from here on out, you'll want to be robust against bad user input, so if the user enters something that isn't a valid file and an exception is thrown, you can catch it and prompt them again for a file.

Once you have an image loaded, display it. Then use a while loop to repeatedly print a table of possible operations, prompt the user to select one of these operations to apply to their image, apply the selected operation (create a distinct function for each operation), and display the resulting image. Thus, the user might choose to reflect the image, then increase the contrast (of the now reflected image), and then blur (the now reflected and contrasty image). At each step, the user should be able to see the resulting image. Again, be sure to handle bad input from the user.

Of course, this still leaves out the details of each operation, for which you will want to write pseudocode before you start writing functions. Details for some of these operations are given below.

Negative: The negative of an image is creating by inverting each color channel. So if the red value of a pixel were 255, it should become 0. If it were 254, it should become 1, and so on, down to 0, which should become 255. Similarly for green and blue.

Grayscale: Shades of gray have the same red, green and blue value. To convert an image to grayscale, you want to set the red, green and blue values all to the average value of the three channels of the original pixel.

Scrolling: Scrolling should ask the user to specify some number of pixels, and should then shift the image that many to the right. Pixels that would fall off the edge of the image should wrap around to the other size. Modular arithmetic may come in handy here.

Zoom: This function result in an image of the same size as the original, but consist of the center of the image blown up by a factor of 2. So if the image has width w and height h, zooming should expand the middle w/2 by h/2 region to fill the whole picture.

Blur: When you blur an image, you set the color of each pixel to be the average of the 9 pixels in the 3 x 3 square centered at that pixel (i.e. the average of the original pixel and its original 8 neighbors). You'll probably want to create a new Picture object; otherwise, you'll be adjusting pixel values that you'll need for subsequent calculations. Be careful at the borders, not all pixels have 8 neighbors!

Posterize: A typical pixel can have one of 256 value for each color channel. In a posterized image, this number is drastically decreased. Each color channel value should be rounded to the nearest multiple of 32.

Increase Contrast: When increasing the contrast, color values at 128 should be unchanged. For any other value x, the difference between x and 128 should be scaled a factor of 2. For example, a color value of 129 (1 above 128) would become 130 (2 above 128). 125 (3 below 128) would become 122 (6 below 128). Just remember that you'll need to stay between 0 and 255.

Implement a Design:

This program will be a good deal larger than those you've created on previous labs. Making a single large function that does everything will most likely end in tears. As such, think carefully about how to break your program into logical and managable pieces using functions. It is very important that you test your code incrementally as you build your program -- don't try to write the whole thing before you start testing. It is also critical that you use comments to explain what each function you create does.

Since we're creating an image manipulation program, you'll want to save picture2.py into your working directory. To create a new picture object, first add an import picture2 statement at the top of your program. Then you'll be able to use


  pic = picture2.Picture("crayons.bmp")
                      
where pic is just a variable name for the picture object (we used canvas last time, but you can use whatever name you want).

This causes a new picture object called pic to be created, but rather than starting as a blank image, pic is initialized to match the image in the file crayons.bmp. To create a new blank image (which may be useful if you need to create a copy of the current image), you'll use almost the same syntax we had for picture.py, minus one set of parens. In particular,


  pic = picture2.Picture(w,h)
                      
will create a new blank image with width w and height h.

Whichever image file you use should be saved in your working directory. You can use crayons.bmp or an image of your choice, although I suggest sticking with images which are in .bmp format. If you're looking for files on Google images, you can add filetype:bmp to your query to restrict hits to this file type.

Some Important Methods

The following functions will be useful in completing this lab. For starters, you often won't know the height and width of the image you read in. To find out, the functions getHeight() and getWidth() can be used. Both return an integer. Remember that to call these functions, you'll use the object name, followed by a period, followed by the function invocation. For example, w = pic.getWidth().

Keep in mind that if the width of the image is w, then the x-coordinates of all pixels range from 0 to w-1. Trying to access or modify a pixel with an x-coordinate of w or greater will cause an error. Similarly for the height.

Since we'll be doing pixel-by-pixel modifications, we need to be able to read and set the three color channels of any given pixel. The function getPixelRed(x, y) returns the red value of the pixel at location (x,y). The function setPixelRed(x, y, v) assigns the pixel at (x,y) a red value of v. This function does not return a value.

The functions getPixelGreen(x,y), setPixelGreen(x,y,v), getPixelBlue(x,y) and setPixelBlue(x,y,v) behave as you'd expect. Keep in mind that when setting any color value, you must use an integer in the range from 0 to 255 (inclusive).

It'll often simplify your code to use getPixelColor(x,y) (which returns three integers, one per color channel) and setPixelColor(x,y,r,g,b).

As we've seen, the function display() can be used to pop open a window with the current contents of your Picture object.

Note About Copying Picture Objects

For some of the operations listed above, it's helpful (if not necessary) to create a duplicate of a Picture Object.

If you have a picture object pic containing your original image, the assignment statement picCopy = pic will not suffice to create a duplicate image. All this will do is give you two variable names pointing to the exact same picture object, and any changes to either will be reflected in both. Instead, you'll need to create a new Picture object of the same size, loop through all pixels of pic and copy the corresponding color channels into same pixel in picCopy. You may want to create a copy(pic) function specifically for this task, that takes in a picture object, makes a new picture object of the same size with the same pixel values, and returns it. Only call display on your original picture object pic. Any function that makes use of a copy of your picture should create a new variable, say, pic2, using your copy function. Then use that copy to modify pic. Don't assign pic2 to pic, and don't display pic2.

Test the Program:

This is a big one, so hopefully you've been testing as you go along. Make sure each individual operation does what it is supposed to, and then make sure that combinations work as well. Just like before, use try/except and while to make sure the user input is correct.

Part 3 - Wrap Up

2 points

As with every lab, your last job prior to submission is to complete a brief write-up by filling out a Google Form.

Handin

You now just need to electronically handin all your files. As a reminder

 
   cd             # changes to your home directory
   cd cs150       # goes to your cs150 folder
   handin         # starts the handin program
                  # class is 150
                  # assignment is 4
                  # file/directory is lab04
   lshand         # should show that you've handed in something
                

You can also specify the options to handin from the command line

 
   cd ~/cs150     # goes to your cs150 folder
   handin -c 150 -a 4 lab04
                

File Checklist


You should have submitted the following files:
  primes.py
  imageEdit.py
  picture2.py   (for ease of grading)
  crayons.bmp	(for ease of grading)
                


C. Taylor, A. Eck, T. Wexler, A. Sharp.