Assignment 10

COMP102/112 2022 Tri 1: Assignment 10

days Due 2 Jun 10am

Goals

This assignment is intended to give you more experience in developing programs that use 2D arrays, including image data, and arrays of objects.

Preparation

Download the zip file for assignment 10 and extract it to the COMP-102-112-2022T1-Assig10 folder in your home folder. It should contain templates for the Java program you are to complete. Read through the whole assignment to see what you need to do.

Go over the slides from the lectures on 2D arrays.

Later when the model answer to assignment 9 becomes available, make sure you understand all the components of the programs.

Summary

  • ImageProcessor:
    right Write a program to dispays and edit a greyscale image in a number of ways.

To Submit

  • Your version of ImageProcessor.java

Image Processor

ImageProcessor is a program that allows a user to display and edit a greyscale image in a number of ways. It is a simplified version of the many commonly used simple image editors available for personal computers. You are to complete several methods for modifying images.

Images can be represented as 2D arrays of pixel values, where each pixel is a spot of one colour. Images come in several varieties. Three simple image types are black and white "bitmaps" (where each pixel is a single bit); greyscale, where each pixel is a number representing a grey value somewhere on the scale from black to white; and full colour, where each pixel is a colour value represented, for example, by its red, green, and blue components.

For simplicity, the ImageProcessor program only deals with greyscale images. Each pixel value is an integer between 0 and 255 where 0 represents black and 255 represents white. The ImageProcessor class contains a field called image which contains the 2D array of pixel values.

There are lots of different possible modifications to images, and programs such as Photoshop and the Gimp provide an extensive set of menus of actions. ImageProcessor only has a small number of actions; you have to complete several methods to make them work.

It is possible to store images in files as tables of the pixel values. The bmp and plain ppm file formats store images in this way, though they both include some "header" information to describe the image. However, such files can be very large, and it is more common to store images in files using more complex formats such as jpg and png, where the pixel values are stored in a highly compressed form. This makes them difficult to deal with directly, but makes the file sizes much smaller than storing all the pixel values explicitly. To edit a jpg or png image, it is necessary to convert the compressed format into a simple array of pixel values.

The ImageProcessor template contains three important methods already written for you: redisplayImage, loadAnImage, and saveImage:

  • redisplayImage() will redisplay the current image stored as an array of greyscale values in the image field, drawing each pixel as a square of the appropriate grey colour. (If the array contains values below 0 or above 255, it will draw them in colour to indicate that you have done something wrong).
  • loadAnImage(String imageName) will load any jpg or png file (coloured or greyscale) and convert the image to an array of greyscale pixel values between 0 and 255. It returns the image as a 2D array of integers.
  • saveImage() will save the current image stored in the image field to a png file.

The template also contains some GUI code for creating the buttons.

Run the demo program, load an image, and try out the different editing actions to see what they do. You can also watch the [demo video.

Start by compiling and running the template code that we have provided. It is important that you run the program by calling the main method. This is to make sure that the program starts by loading an image before setting up the GUI. The program also let you load and display any jpg or png file (as long as it is not too big). Initially, none of the editing actions will work; complete one method at a time, then test it, before working on the next one.

Core:

Complete the following methods:

  • lightenImage():
    Makes the whole image lighter by 20 greylevels. That is, it should increase the value of each pixel by 20, except that the pixel value must never go above 255.

  • fadeImage():
    Decreases the contrast in an image. All the lighter pixels (above 128) should be made 20% darker and all the darker pixels (below 128) should be made 20% lighter.
    For example, a light pixel value of 158 is 30 levels above 128. It should be darkened by 20% of 30 (= 6) to 152. A dark pixel value of 48 is 80 levels below 128. It should be lightened by 20% of 80 (= 16) to 64.
    Note that white equals to 255, and black to 0, and the new values must keep in the 0-255 range.

  • flipImageHorizontally():
    Flips the image horizontally so that each pixel in the left half of the image is exchanged with the pixel opposite it in the right half. Be careful not to flip the image twice (eg by copying a pixel to the opposite side and then copying it back) which will put the image back to its original state!

  • shiftImageVertically():
    Shifts the image vertically by moving each row of the image one step down and moving the bottom row up to the top.

Completion

These methods are more tricky. Do not work on the completion until you have completed the core parts of the other questions.
  • rotateImage180():
    Rotate the image 180 degrees so that each pixel in the image is exchanged with the pixel diagonally opposite it. Again, be careful not to rotate the image twice.

  • rotateImage90():
    Rotate the image 90 degrees anticlockwise. Note that the resulting image will have different dimensions from the original image - the width of the new image will be the height of the old image, and the height of the new image will be the width of the old image. You will need to make a new image array of the new dimensions, fill it with the correct pixel values from the original array, and then set the image field to contain the new image.

Challenge

  • expandImage():
    Expands the top left quarter of the image to fill the whole array -- each pixel in the top left quarter will be copied to four pixels in the zoomed image. Be careful not to access elements past the edge of the array!

    Hint: It is actually easier to work backwards from the bottom right corner: for each cell at (row,col) copy the pixel value from the cell at half the row and half the col. Alternatively, copy pixels into a new array, and then assign the array to the image field (replacing the original array).

  • mergeImage():
    Asks the user to select another image and constructs a merge of the current image and the new image. Loads the other image into a temporary array. Each pixel value in the current image is replaced by the average of the pixel value in the current image and the corresponding pixel value of the other image. If the images are of different sizes, it only merges the images in the region that is common to both images.

    Hint: Remember that the number of rows in the image is this.image.length; the number of columns in the image is this.image[0].length.

To go further

It is important to understand how Java works, as well as writing programs in Java.

  1. Some of the methods in the ImageProcessor program could be done in two different ways: "in-place" (only using the array containing the image), or using a temporary array to store the image as it was being processed. Discuss the advantages and disadvantages of the two approaches.
  2. This was the last assignment. Think back to the beginning of the course and what you knew at that point, and then list some of the new skills and understanding that you believe that you have gained during this course.

[For some of you who are still finding the course difficult, you could try doing some of the early assignments again; you may find them an awful lot easier the second time round, demonstrating that you have learned stuff!]