CS116      Lab 2A - Modifying Pictures Using Loops

Objectives:

  1. Before starting this lab you should have read chapter 4 in your text.
     
  2. Open DrJava and open the Picture class.
     
  3. In Chapter 4 you should have read about how pictures are made up of a grid (or array) of pixels.  Each of these pixels has a color value which is made up of component values of red, green, and blue.  We can explore this by typing the following commands in the Interactions Pane:

    Picture picture = new Picture(FileChooser.pickAFile());
    picture.show();
    picture.explore();


    The FileChooser class brings up a chooser where you can browse for a picture file.  You can use any of the pictures in the mediaSources directory or use one of your own.  The show method simply displays your picture.  The explore method brings up a window that lets you examine the values at particular locations within your picture.
     

  4. Check out the documentation for the Picture class.  You will see that there is a method getPixel(x,y) which will return the Pixel at a particular x an y location.  Check out the documentation for the Pixel class. You can see that we can get the red, blue, and green values of a pixel and we can also set the color of a pixel to another color.  Try the following and check that the pixel color has been changed. (You may want to use a color other than black and different x and y values.  You can check the documentation of the Color class in the Java API to see what other built in colors are available.) 

    import java.awt.Color;
    picture.getPixel(10,100).setColor(Color.black);
    picture.explore();

    The import statement allows you to access the Color class from the java.awt library. 
     

  5. If we want to change a lot of the pixels in the same way, it would be extremely tedious to have to write statements for each pixel.  Instead, we need a way of repeating the same statements for different objects.  We will now look at how to write methods that change some property of ALL the pixels in a picture.  Three types of loops are described in the chapter that allow us to execute a group of statements many times. 

    The for-each loop is of the form
        for (Type variableName: arrayName){
            // group of statements here...
      }

    The group of statements is performed for each element in the array.

    The following method which we can add to the Picture class decreases the red value in each element of the array of pixels that make up the picture.  (Note in the code this.getPixels() we are invoking the method getPixels on the picture for which the method is being used.)

     public void decreaseRedForEach(){
        Pixel[] pixelArray = this.getPixels();
        int value = 0;
        // loop through all the pixels in the array
        for (Pixel pixel : pixelArray){
            // get the red value
            value = pixel.getRed();
            // decrease the red value by 50%
            value = (int) (value * 0.5);
            // set the red value of current pixel to new value
            pixel.setRed(value);
        }
    }

    Add that method to the Picture class.  Now in the Interactions Pane, create a new picture object and try this method on it.  Show the new picture.
     

  6. Another type of loop is a while loop which is of the form
        while (test){
            // group of statements here...
      }

    The group of statements is performed as long as the test is true.

    The following method performs exactly the same as the previous one, only with a while loop.  Here, we have to use an index to specify which pixel in the array we are using each time through the loop.  Therefore at the end of the loop we add 1 to the index so that we act upon the next pixel in the next iteration of the loop.

     public void decreaseRedWhile(){
        Pixel[] pixelArray = this.getPixels();
        Pixel pixel = null;
        int value = 0;
        int index = 0;
        // loop through all the pixels in the array
        while (index < pixelArray.length){
            // get the current pixel
            pixel = pixelArray[index];
            // get the red value
            value = pixel.getRed();
            // decrease the red value by 50%
            value = (int) (value * 0.5);
            // set the red value of current pixel to new value
            pixel.setRed(value);
            // increment the index
            index++;
        }
    }

    Add this method to the Picture class and try it out.
     

  7. A final type of loop is a for loop which is of the form
        for (initialzation; test; change){
            // group of statements here...
      }

    The for loop performs like a while loop except that the initialization and the change of the index are built into the loop.

    The following method performs exactly the same as the previous one, only with a for loop. 

     public void decreaseRedFor(){
        Pixel[] pixelArray = this.getPixels();
        Pixel pixel = null;
        int value = 0;
        // loop through all the pixels in the array
        for (int index = 0; index < pixelArray.length; index++){
            // get the current pixel
            pixel = pixelArray[index];
            // get the red value
            value = pixel.getRed();
            // decrease the red value by 50%
            value = (int) (value * 0.5);
            // set the red value of current pixel to new value
            pixel.setRed(value);
        }
    }

    Add this method to the Picture class and try it out.
     


  8.  

    Assignment:
    Write a Picture method keepBlue to keep just the blue color.  This means you will set the green and red values to zero. 

     


  9.  

    Assignment:
    Write a Picture method maximizeBlue which sets blue to its maximum value (255).  Use a different type of loop than the one you used in the keepBlue method.

     


  10.  

    Assignment:
    Write a Picture method which morphs one picture into another.

    To morph one picture to another we will generate a sequence of intermediate images which will systematically appear more and more like the ending picture.

    Suppose that there are n intermediate images.  We will compute the color values of red, green, and blue for each pixel of the kth intermediate image by computing a weighted average:

      color_value = start_color + ((end_color - start_color)/ n) * k

    Since this method does not operate on a single picture it will not be an object method but will be a class method.  You can read about class methods on p41 of your text.  We define a class method my using the keyword static.  We will define the morph method as follows:

    /* Method to return a morphed intermediate image
    * @param  start is the starting image
    * @param  end is the ending image
    * @param  n is the number of intermediate images
    * @param  k is a position in the intermediate image
    * @return a the kth image in the intermediate image sequence
    */

    public static Picture morph(Picture start, Picture end, int n, int k){
      Picture result = new Picture(start.getWidth(), start.getHeight());

      // set the color values of all the pixels in intermediate picture p
      return result;
    }

    Note that morph is creating a new Picture object of the same size as the starting image.  It is also assumed that the ending image is the same size as well.  (Later we will learn how to check that this condition holds).  The new image is returned as output by the function at the end. 

    You will need to get three arrays of pixels for the three images: start, end, and result.  Use a while or for loop to iterate through all the pixels of the start image and use the same index in the end image to compute the pixels in the resulting image.

    For each pixel, compute the weighted red, green, and blue color values and set these values in your result pixel.

    After writing the method, modify MyProgram to input two pictures using FileChooser to select the pictures, and then show the starting and morphed images.  For example, to show the first morphed image from a sequence of four you would use the code:

    Picture.morph(start,end,4,1).show();

    In the mediasources you will find a number of images of the same size to test this out.  For example, whiteFlower.jpg, YellowFlowers.jpg, and rose.jpg are all of the same size.

     

  11. Send your modified code Picture.java and MyProgram.java to me using GoucherLearn.