Image Lab III

Due Wednesday, November 25th, 2009

Paste your functions doubleSize and crop into your portfolio page,  along with a link to the file on the CS web page, just as you did for all the previous python assignments.

Getting Bigger


Let's say we want to enlarge our image.  How can we make our image twice as large?  Consider the following test image:



What pixel in the new, enlarged image corresponds to the pixel at location (10,10)?  The pixel at location (10,10) in the original image is mapped to the pixel at location (20,20) in the new image.  In general, the pixel at location (x,y) will be mapped to the pixel at location (2x, 2y). 

So, to create a magnified picture, we need to

  • create a blank picture twice as large (that is, a picture whose height and width are twice as big as our original pictur
  • For each location (x,y) in the original picture, copy that pixel to location (2x, 2y)
So, our code would be (Skipping one stripe of pixels to avoid the starting at index 0 / starting at index 1 versioning problem with JES):


def doubleSize(picture):
  width = getWidth(picture)
  height = getHeight(picture)
  newPicture = makeEmptyPicture(width * 2, height * 2)
  for xpos in range(1, getWidth(picture)):
    for ypos in range(1, getHeight(picture)):
      pixel = getPixel(picture, xpos, ypos)
      oldColor = getColor(pixel)
     
      newPixel = getPixel(newPicture, 2*xpos, 2 * ypos)
      setColor(newPixel, oldColor)
  return newPicture

Given a picture of the USF logo:


We get:


This is doubled, but it's like we're looking at it through a screen door.  This is not surprising, since we copied one pixel into the target image from each pixel in the source image -- and the target image has 4 times the pixels as the source image!  We could try doubling up some of the pixels -- moving several copies into the new picture, as follows:


def doubleSize2(picture):
  width = getWidth(picture)
  height = getHeight(picture)
  newPicture = makeEmptyPicture(width * 2, height * 2)
  for xpos in range(1, getWidth(picture)):
    for ypos in range(1, getHeight(picture)):
      pixel = getPixel(picture, xpos, ypos)
      oldColor = getColor(pixel)
    
      newPixel = getPixel(newPicture, 2*xpos, 2 * ypos)
      setColor(newPixel, oldColor)
      newPixelRight = getPixel(newPicture, 2*xpos + 1, 2 * ypos)
      setColor(newPixelRight, oldColor)
     
  return newPicture

This gives us a slightly better image:



However, this image still has white lines through the middle of it -- which leads to our next problem:

1.  Rewrite doubleSize so that you copy enough pixels over (4 pixels in the new image for each pixel in the old image) to remove any  while lines


Another common operation for manipulating photos is cropping a photograph.  We can do a simple crop of a picture by reducing the width and height of the photograph.  We can write a function that takes as input parameters an image and a new width and height, and creates a new image that is the new width and height, by cropping the old photograph, as follows:


def crop(picture, width, height) :
  newPic = makeEmptyPicture(width, height)
  for xvalue in range(1, width) :
    for yvalue in range(1,height) :
      pixel = getPixel(picture, xvalue, yvalue)
      color = getColor(pixel)
      newPixel = getPixel(newPic, xvalue, yvalue)
      setColor(newPixel, color)
  return newPic

This will properly crop the picture, but it will not work if the width or height passed in are larger than the actual width or height of the picture passed in.  (Can you see where the error will occur?)  Rewrite crop so that if the width and height passed in are larger than the original picture, then black pixels are copied into the extra spaces.  So, if we were to load the USF logo into a variable named usflogo (using makePicture and pickAFile), and then called crop as follows:

>>  logoCrop = crop(usflogo, 400, 50)

we would get the image:



Extra Credit

Not feeling sufficiently challenged?  Here are some further problems to work on.

EC1:  Better Doubling

Note that with your answer to question 1 above, you will get a fairly blocky image.  Given our standard cat picture:



We get the enlarged picture:


Note the pixelation, especially in the edge of the bed, or in Voodoo's face and ears.  We can make this much nicer by not just doubling pixels, but instead interpolating them.  That is, for each of the original "blank" pixels, copy in the average of the two (or four) pixels around it.

EC2: Better Cropping

Note that our cropping program for question 2 only crops the right and bottom of the picture.  To be a truly useful cropping function, we should be able to crop any rectangle out of our image.  This leads to a 2-part cropping extra credit problem:

Part I:  Rewrite the function crop so that it takes a picture, a starting x position, a starting y position, a width, and a height, and returns a new picture of the appropriate width and height, cropped starring with the passed-in x and y positions. 

Part II:  Extend your crop function so that if the width or height are larger than the image passed in, then the new image will have the old image centered in it, with black bars on the left and right and/or top and bottom.