PA1 – MIMP

HONOR CODE REMINDER

You must work on programming assignments on your own. You may request help on programming assignments from the course instructor or the lab assistant. If you receive such help you must make note of it in the documentation for each method. The acknowledgement should state the full name of the person helping and a short blurb about what they helped with on a method-to-method basis on the line in the Javadoc comments after the description of the method. If help across methods was given this may be documented once in the class(es) affected again in the Javadoc comment after the description of the class(es), including a list of the methods where help was received. The goal of this is to help us both understand just how much help you are needing to get to the assignment done.

You may request help on general topics from other students and friends. You may even look at code, but you should not copy down any code or write code for another person. Looking at code should be used to help others debug their code only after you have satisfactorily written and submitted that code.

Representing someone else’s work as your own, in any form, constitutes an honor code violation. Directly copying or using the same code is an honor code violation. It is also a violation of the honor code to “render unauthorized assistance to another student by knowingly permitting him or her to copy all or a portion of an examination or any work to be submitted for academic credit.” That means that you can be written up for an Honor code violation if you share your code with someone else, even if you wrote it completely on your own.

Objectives

The purpose of this assignment is to practice working with two dimensional arrays and implementing Java classes according to an existing specification.

Introduction

Welcome to ImageCorp! You have been hired to work on a ground-breaking new image manipulation application named MIMP: The Madison Image Manipulation Program. MIMP is designed to be a competitor to existing products such as Photoshop or GIMP.

The User Interface Team has already designed a stylish and functional GUI. It will be your job to program the classes that actually store and manipulate image data.

Representing Images

There are many different ways to digitally represent images. One common approach is to maintain a two-dimensional grid of pixels, where each pixel corresponds to the color of a tiny rectangular region of the overall image.

The color of each pixel is represented by its red, green and blue components. Each color component is restricted to be an integer in the range 0 to 255. Under this representation (red=0, green=0, blue=0) corresponds to black, (255, 255, 255) corresponds to white, (255, 0, 0) corresponds to red etc. This approach enables us to represent 256*256*256 = 16,777,216 distinct colors. The individual color components are often referred to as “channels”.

The Java Standard libraries include some built in image classes, including java.awt.Image and java.awt.image.BufferedImage. Unfortunately these classes are not ideal for our purposes. They are designed primarily to represent images in a graphical interface, not to support pixel-level manipulation.

For this project you will implement three classes: one representing individual pixels, one representing complete images, and a utility class that is able to perform basic image manipulations such as grayscale, rotating etc.

We strongly recommend you implement the functionality in the order it is presented below.

The Pixel Class

Your implementation of the Pixel class should conform to the following UML diagram. Note that Pixel is an immutable type: once a Pixel object has been created it cannot be modified.

UML for the Pixel Class

(The {readOnly} annotation indicates that the fields should be final.)

Method details:

  1. Constructor – The constructor should automatically clip color values to the appropriate range. In other words, if a Pixel is declared as follows:
    Pixel p = new Pixel(-100, 300, 50);
    The resulting red green and blue color components should be 0, 255 and 50 respectively.
  2. toString – The toString method should return a string with the following format: "(red, green, blue)". The appropriate string for the pixel above would be "(0, 255, 50)". For this method, and all other methods that return strings, your formatting must exactly match the specifications.
  3. getChannel – The getChannel method should take an integer value in the range 0-2, indicating which color channel is requested, 0=red, 1=green, 2=blue, and return the corresponding color value. If any other channel is requested, the return value should be -1. This is a convenience function that makes it possible to loop over channels.
  4. equals – returns true if all private members of 2 instances of Pixel are equal.

The Image Class

Your implementation of the Image class should conform to the following UML diagram. Note that location (0, 0) is in the upper-left corner of the image.

UML for the Image class

Method details:

  1. The two-argument constructor should create a completely white image. The five-argument constructor should create an image using the indicated color values. If the provided width or height is less than or equal to zero, both constructors must create a 0x0 image. Color values outside of the allowable range should be clipped according to the logic described for the Pixel class.
  2. getPixel – This method must return null for pixel positions outside of the image boundaries.
  3. setPixel – This method must have no effect for pixel positions outside of the image boundaries or if a null Pixel argument is provided.
  4. toString – The format for the toString method is "<Image width=w height=h>" where w and h are the height and width of the image. For example: "<Image width=640 height=480>" would be the correct string for any image that is 640 pixels wide and 480 pixels high.
  5. toStringDebug – The toStringDebug method is designed to facilitate debugging by returning an easy-to-read string representation of an image. The following string illustrates the correct format for a tiny 4×5 pixel image:
    <Image width=4 height=5>
    	(1, 101, 201)	(2, 102, 202)	(3, 103, 203)	(4, 104, 204)
    	(5, 105, 205)	(6, 106, 206)	(7, 107, 207)	(8, 108, 208)
    	(9, 109, 209)	(10, 110, 210)	(11, 111, 211)	(12, 112, 212)
    	(13, 113, 213)	(14, 114, 214)	(15, 115, 215)	(16, 116, 216)
    	(17, 117, 217)	(18, 118, 218)	(19, 119, 219)	(20, 120, 220)	
    Use tab characters (“\t”) to indent your pixel values and separate the columns in your string.
  6. equals – returns true if all private members of 2 instances of Image are equal.

The ImageTransforms Class

ImageTransforms is a utility class that contains static methods for performing basic image transformations. Note that none of the methods defined in ImageTransforms modify the existing image. In each case a new image is returned that is a result of applying the requested transform.

Method details:

  1. roseTintedGlasses – This method simply increases the red color channel by 25. Here is the resulting image if we compute the roseTintedGlasses version of the original 4×5 image above:
    <Image width=4 height=5>
    	(26, 101, 201)	(27, 102, 202)	(28, 103, 203)	(29, 104, 204)
    	(30, 105, 205)	(31, 106, 206)	(7, 107, 207)	(8, 108, 208)
    	(34, 109, 209)	(35, 110, 210)	(36, 111, 211)	(37, 112, 212)
    	(38, 113, 213)	(39, 114, 214)	(40, 115, 215)	(41, 116, 216)
    	(42, 117, 217)	(43, 118, 218)	(44, 119, 219)	(45, 120, 220)
    
  2. convertToGrayscale – This method converts an image to grayscale by setting all three color channels to the same value. Most image processing programs accomplish this by computing a weighted average of the three color components. Green is weighed most heavily, reflecting the fact that the human eye is more sensitive to green wavelengths. Your method must use the following weighting scheme: L = 0.299R + 0.587G + 0.114B. Where L is referred to as “luminosity” or “brightness”. You can find more information on the Wikipedia Grayscale page.

    Here is the resulting image if we compute the grayscale version of the original 4×5 image above:

    <Image width=4 height=5>
    	(82, 82, 82)	(83, 83, 83)	(84, 84, 84)	(85, 85, 85)
    	(86, 86, 86)	(87, 87, 87)	(88, 88, 88)	(89, 89, 89)
    	(90, 90, 90)	(91, 91, 91)	(92, 92, 92)	(93, 93, 93)
    	(94, 94, 94)	(95, 95, 95)	(96, 96, 96)	(97, 97, 97)
    	(98, 98, 98)	(99, 99, 99)	(100, 100, 100)	(101, 101, 101)	

    In this example, the upper left pixel has the value 82 because
    0.299 * 1 + 0.587 * 101 + 0.114 * 201 = 82.5.
    Note that the floating point result is truncated rather than rounded. This is the default behavior in Java when a floating point value is assigned to an integer variable.

  3. threshold – This method converts the image to black and white by setting all pixels with a luminosity below the threshold to black, and all other pixels to white. The result of applying a threshold of 90 to our original image would be the following:
    <Image width=4 height=5>
    	(0, 0, 0)	(0, 0, 0)	(0, 0, 0)	(0, 0, 0)
    	(0, 0, 0)	(0, 0, 0)	(0, 0, 0)	(0, 0, 0)
    	(255, 255, 255)	(255, 255, 255)	(255, 255, 255)	(255, 255, 255)
    	(255, 255, 255)	(255, 255, 255)	(255, 255, 255)	(255, 255, 255)
    	(255, 255, 255)	(255, 255, 255)	(255, 255, 255)	(255, 255, 255)	
  4. rotateLeft – This method rotates the image 90° to the left (counter-clockwise). The result of applying this method to our original image would be the following:
    <Image width=5 height=4>
    	(4, 104, 204)	(8, 108, 208)	(12, 112, 212)	(16, 116, 216)	(20, 120, 220)
    	(3, 103, 203)	(7, 107, 207)	(11, 111, 211)	(15, 115, 215)	(19, 119, 219)	
    	(2, 102, 202)	(6, 106, 206)	(10, 110, 210)	(14, 114, 214)	(18, 118, 218)	
    	(1, 101, 201)	(5, 105, 205)	(9, 109, 209)	(13, 113, 213)	(17, 117, 217)	
  5. rotateRight – This method rotates the image 90° to the right (clockwise). The result of applying this method to our original image would be the following:
    <Image width=5 height=4>
    	(17, 117, 217)	(13, 113, 213)	(9, 109, 209)	(5, 105, 205)	(1, 101, 201)	
    	(18, 118, 218)	(14, 114, 214)	(10, 110, 210)	(6, 106, 206)	(2, 102, 202)	
    	(19, 119, 219)	(15, 115, 215)	(11, 111, 211)	(7, 107, 207)	(3, 103, 203)	
    	(20, 120, 220)	(16, 116, 216)	(12, 112, 212)	(8, 108, 208)	(4, 104, 204)	
  6. mirror – This method flips the image around the vertical axis. The result of applying this method to our original image would be the following:
    <Image width=4 height=5>
    	(4, 104, 204)	(3, 103, 203)	(2, 102, 202)	(1, 101, 201)
    	(8, 108, 208)	(7, 107, 207)	(6, 106, 206)	(5, 105, 205)
    	(12, 112, 212)	(11, 111, 211)	(10, 110, 210)	(9, 109, 209)
    	(16, 116, 216)	(15, 115, 215)	(14, 114, 214)	(13, 113, 213)
    	(20, 120, 220)	(19, 119, 219)	(18, 118, 218)	(17, 117, 217)	
  7. flip – This method flips the image around the horizontal axis. The result of applying this method to our original image would be the following:
    <Image width=4 height=5>
    	(17, 117, 217)	(18, 118, 218)	(19, 119, 219)	(20, 120, 220)
    	(13, 113, 213)	(14, 114, 214)	(15, 115, 215)	(16, 116, 216)
    	(9, 109, 209)	(10, 110, 210)	(11, 111, 211)	(12, 112, 212)
    	(5, 105, 205)	(6, 106, 206)	(7, 107, 207)	(8, 108, 208)
    	(1, 101, 201)	(2, 102, 202)	(3, 103, 203)	(4, 104, 204)	

Provided Code

The following code has been provided for you. You should not need to modify any of these files:

  • MIMP.jar – This contains the implementation of the the graphical MIMP application. Running this application is one way to test your finished classes. Note that this is not an executable .jar file. The application will be started using the MimpLauncher class below.
    • If you are using a CS@JMU lab machine or if your computer still has JDK 10 this JAR should work for you
  • MimpLauncher.java – This class contains the main for starting the MIMP application. This version is compiled with the current Java version (JDK 11)
  • Instructor-Provided Tests:
    1. PixelTest.java
    2. ImageTest.java
    3. ImageTransformsWithoutCompleteTest.java
    4. ImageTransforms2Test.java

Submission and Grading

Submission for this assignment is divided into two parts that should be completed in order. Within Part B, there are 3 classes that should be implemented in the order presented.

Part A: Readiness Quiz

In order to complete Part A you should first carefully read the project specification. We suggest that you print a paper copy of the document so that you can highlight and take notes as you read. Once you feel confident that you have a good grasp of the project requirements, log into Canvas and complete the Part A quiz. YOU MUST ANSWER ALL QUESTIONS CORRECTLY TO GET ANY CREDIT FOR THIS PART. You may take the quiz as many times as necessary.

Keep in mind that this quiz is considered part of the programming assignment and falls under the requirements of the course collaboration policy. Reading technical documentation is one of the skills we want to develop in this course. This means you should not ask your classmates for the answers to these questions. If you are stuck, feel free to talk to your instructor or a TA.

Part B: Implementation

Pixel Class, Image, and ImageTransforms Classes

Autolab will base your score on:

  1. Passing Checkstyle
  2. Passing the instructor-provided unit tests.

For Part B you submit the classes as you develop them to Autolab. Your submission must conform to the course style guide. Autolab will run Checkstyle against your submission and deduct points if your code is not formatted correctly.

Grading

Part A 10%
Part B Autolab Checkstyle: 10%
Part B Autolab Correctness: 60%
Part B Instructor grading based on style and code quality: 20%

The portion of your grade labeled “Instructor grading based on style and code quality” will be based on stylistic issues that cannot be checked automatically. These include:

  • Appropriate acknowledgment statement.
  • Meaningful variable names.
  • Clear documentation.
  • Avoiding unnecessary code repetition.
  • etc.

Acknowledgements

Thanks to Dr. Sprague for v1 of this assignment, to Dr. Weikle for many suggestions for this version, and to Dr. Bernstein for his support in using Autolab.