Skip Site NavigationCarleton College: Home
 
 

Note: I've recently updated this assignment to break it up into three parts, instead of two. You've now got a little more time to work on this.

This is an individual assignment.

For this assignment, we will get fancier in our ability to process images. We will now think of an image as a three-dimensional array of pixels: the first dimension corresponds to the rows, the second to the columns, and the third to the color bands. Note that this is a three part assignment. You need to write six methods, described below. Turn in any two of these methods on Friday, contained in a directory called image2. Turn in another two (with the original two, so four together) by Monday night in a directory called image3. Turn in the remaining two (with the other four, so a total of six) by Wednesday night in a directory called image4.

We will again use the EzImage class, which gives us some of the basic tools that we need. For images, you can again use background1.jpg, background2.jpg, background3.jpg, amy.jpg, or dave.jpg, or obtain your own image instead if you like: you can use your picture from the Carleton directory or you can take a picture with a digital camera.

Your mission is to write new methods for PhotoLab. Start again from scratch with a new PhotoLab class. Here are the methods that your PhotoLab class should have:

  • public EzImage crop(EzImage image, int rowStart, int rowStop, int colStart, int colStop)
    Crops your image. Extracts only those pixels from pixels rowStart through rowStop and colStart through colStop. If any of the parameters are out of range for your image, return null. Otherwise, return the new image.
  • public EzImage dither(EzImage image)
    Dithering is a technique used when you want to print a gray picture in a place such as a newspaper where no shades are available. Instead, you need to use individual pixels of black and white to simulate shades of gray. The popular Floyd-Steinberg algorithm for dithering is as follows:
    • Loop over all pixels, running across one row at a time.
    • For each pixel: if its value is larger than 128, set it to 255 (pure white). Otherwise, set it to 0 (pure black). Record the "error", which is the old value of this pixel minus the new one.
    • This "error" represents how much blackness we have added to this pixel. Distribute this blackness to adjacent pixels as follows:
      1. Add 7/16 of the error to the pixel immediately to the right ("east").
      2. Add 3/16 of the error to the pixel immediately diagonally to the bottom left ("southwest").
      3. Add 5/16 of the error to the pixel immediately below ("south").
      4. Add 1/16 of the error to the pixel immediately diagonally to the bottom right ("souhteast").
    • Any error to be distributed to pixels that are out of range should be ignored.

    Dithering should only be done on gray images, so convert the image to gray first inside your dither method. You can use the EzImage instance method copyToGrayScale() to convert an image to gray.

    In order for dithering to work, you must make your changes to the same image that you are looping over. Dithering by reading one image and making your changes on a copy will not work correctly, because the "error" never gets a chance to accumulate. In other words, make sure that you make a gray scale copy of the image first, and then do all dithering work (looping, reading, writing, etc.) on the copy itself. If your image looks really weird, this may likely your problem.

    Dithered Europe
  • public EzImage overlay(EzImage originalImage, EzImage overlayImage, int row, int col)
    Overlays a smaller overlayImage onto the originalImage, as in the example below. If overlayImage can't be placed on the image (perhaps because it is too large or row or col are not valid), return null. Otherwise, return the new image.
  • Dave Head
  • public EzImage circleCrop(EzImage image, int centerRow, int centerCol, int radius)
    Crops the image to a circular shaped portion of the original with a center at centerRow and centerCol and a radius of radius. Since the image itself must still be rectangular to fit inside a window, make the background of the rest of the image white. See example below, which was cropped from background3.jpg. If centerRow, centerCol, radius, or some combination thereof are invalid, return null. Otherwise, return the new image.
  • Streetlamp
  • public EzImage scale(EzImage image, double scaling)
    Scales your image. If scaling is 2, for example, your image should double in size. Likewise, if scaling is 0.25, your image should be 1/4 the size of the original. If scaling factor is less than or equal to 0, make no changes to the image and return null. Otherwise, return then new image.
  • public EzImage blur(EzImage image, int radius)
    Blurs an image. For each pixel, average all of the pixels within a circle centered at that pixel and with a radius as given. Make sure to put all of your results in a new array, instead of overwriting your original as you go; otherwise, your blurred pixels will cascade on top of each other. Keep in mind that some approaches to programming this result in much slower algorithms. On my office machine, which is slightly slower than the lab machines, I can blur background3.jpg in 5 seconds with a radius of 3 and 20 seconds with a radius of 10. Any technique that works will receive most of the points for this problem, but you need to end up with timing close to these numbers if you wish to earn it all.

Test your program by writing a corresponding PhotoLabTester class. Check the return values from your methods, and print out text indicating whether or not your methods were successful.

Good luck, and have fun!

Available from: Wednesday, May 2 2007, 09:20 AM
Due date: Saturday, May 5 2007, 11:55 PM