T-Th 9:05
or
T-Th 11:15
in Phillips 101

CS 1110: Introduction to Computing Using Java

Spring 2012

Color Models

Due to CMS by Thursday, March 15

Now that you have been introduced to the basics of OO programming, we are going to start having more interesting assignments that take advantage of the graphics capability of Java. This assignment is a warm-up for these later assignments, and serves three very important roles:

  1. It introduces three color models that are used in computing and graphics.
  2. It gives you practice in writing functions beyond simple getters and setters.
  3. It introduces an extension of the testing and debugging methodologies you have learned about so far.

You have a lot longer to do this assignment — over two weeks. However, you should still start early on this assignment because the first prelim overlaps the time that you should spend on it. In addition, we want you to keep track of how long you spent working on this particular assignment (see Finishing the Assignment, below).


Table of Contents


Before You Get Started

Academic Integrity

We have given this assignment before. It is a good one, and students really like it. Do not share your code with others. Do not obtain or look at a copy of the earlier solution or a version being done by another student. Such cheating helps no one, especially you, and it makes more unnecessary work for us.

Unlike the Acorn.com assignments, it is highly unlikely that your code for this assignment will look exactly like someone else's. This is the first assignment that we will actively be using Moss to check for instances of cheating and plagiarism.

Collaboration Policy

You may do this assignment with one other person. If you are going to work together, then form your group on CMS as soon as possible. If you do this assignment with another person, you must work together. It is against the rules for one person to do some programming on this assignment without the other person sitting nearby and helping.

With the exception of your CMS-registered partner, you may not look at anyone else's code or show your code to anyone else, in any form what-so-ever.

Getting Help

If you do not know where to start, if you do not understand testing, or if you are completely lost, please see someone immediately. This can be the course instructor, a TA, or a consultant. Do not wait until the last minute, particularly since this is due on a weekend. A little in-person help can do wonders. See the staff page for more information.


An Overview of Color Models

Color Model RGB

The RGB system is named after the initials of the three color names: red, green, and blue. In this color model, light from these three colors is mixed to produce other colors, as shown in the image to the left. Black is the absence of color; white the maximum presence of all three.

In the upper right is a colored image. Below it is its separation into red, green, and blue (here is a high resolution version). In the three separation panels, the closer to black a point is, the less of that color it has. For example, the white snow is made up of a large amount of all three colors, whereas the brown barn is made up of red and green with very little blue. Because it works by adding colors to black, the RGB system is “additive”.

The color model RGB is used in your TV and computer screens, and hence on web pages. Its roots are in the 1953 RCA color-TV standards. But the idea has been around longer; see this exhibit for some amazing full-color images taken with an RGB camera over 100 years ago.

In the RGB model used in Java, the amount of each of red (R), green (G) and blue (B) is represented by a number in the range 0..255. Black, the absence of color, is [0, 0, 0]; white, the maximum presence of R, G, and B, is [255, 255, 255]. This means that there are 16,777,216 different colors. The class java.awt.Color has some constants (e.g. final, static variables) that you can use for some of the possible colors. For example, Color.magenta is [255, 0 , 255] and Color.orange is [255, 200, 0]. There is a Wikipedia page with a list of colors that gives (non-Java) names to many RGB colors.

In some graphics systems, RGB is used with double numbers in the range 0.0..1.0 instead of int values 0..255. The reasons for this descrepancy is that the mathematical formulas for color require real numbers 0.0..1.0, but it takes a lot less memory to story ints instead (and images require a lot of memory). In your program, you may have to convert each number in the integer range 0..255 to a double in 0.0..1.0, calculate a mathematical formula, and then convert back to 0..255. An example is the complementRGB method below.


Color Model CMYK

For your ink-jet printer, you buy expensive ink cartridges in the colors cyan, magenta, yellow, and black. The printer mixes these inks in different amounts on paper to make the full range of colors. Black is referred to using K (originally for “Key”) to avoid confusion with Blue.

The process works similarly to RGB on a monitor, but in reverse. The paper starts off white (equal parts red, green, and blue), and the colors of these inks are chosen so that cyan ink absorbs red light, removing it from the color of the paper; similarly, magenta removes green, and yellow removes blue. Black ink removes all three colors in equal amounts. For instance, paper printed with only yellow ink appears the same color as a monitor that is displaying a yellow color [255, 255, 0] because it has removed all the blue, leaving the red and green. Printing magenta and cyan removes red and yellow and results in blue [0, 0, 255]. Because it works by removing color, this kind of system is “subtractive”.

Theoretically, only C, M, and Y are needed to achieve any color, but in practice it is hard to get a good black by mixing colored inks; instead you get a soggy, expensive brown-black. By using the black ink to do the “heavy lifting” of absorbing most of the light when printing dark colors, a lot of ink can be saved (This is a simplified view of color printing; more complicated calculations are needed to get accurate colors with real inks).

To demonstrate, in the upper right, we show you an image; below it is its separation into cyan, magenta, and yellow. To the right of that, you see the same image separated into four components; C, M, Y, K. Much less of the CMY colors is needed to make the image when black is also used (here is an enlarged version of the CMY image and an enlarged CMYK image).

In the CMYK system, each of the four components is traditionally represented by a percentage, which we represent in our system as a double value in the range 0.0..100.0.


Color Model HSV (or HSB)

The HSV model, used heavily in graphics applications, was created in 1978 by Alvy Ray Smith. Artists prefer the HSV model over others because of its similarities to the way humans perceive color. HSV can be explained in terms of the cone that appears to the left.

H, the Hue, defines the basic color. H is an angle in the range 0 ≤ H < 360, if one views the top of the cone as a disk. Red is at angle 0. As the angle increases, the hue changes to orange, yellow, green, cyan, blue, violet, magenta, and back to red. The image above shows the angles for some colors.

S, in the range 0 ≤ S ≤ 1, is the Saturation. It indicates the distance from the center of the disk. The lower the S value, the more faded and grayer the color. The higher the S value, the stronger and more vibrant the color.

V, the Value, also called the Brightness, is in the range 0 ≤ V ≤ 1. It indicates the distance along the line from the point of the cone to the disk at the top. If V is 0, the color is black; if 1, the color is as bright as possible.

To the right at the top is a picture. Below it we see its hue, saturation (white is zero saturation, red is full saturation), and brightness components. The hue component shows color. The snow has color, but its saturation is low, making it almost grayish. Look at the various components of the image —the sky, the green grass, the snow, the dark side of the barn, and so on — to see how each component H, S, and V contributes. You can see more detail in this high-resolution version.


Assignment Overview

For this assignment, we are providing you with a lot of code already written. In that respect, this assignment is going to be a lot more like a lab, where you fill in the extra details. In addition, we are providing you with a working solution (as a JAR file, so you are not tempted to look at the source code), so that you know what your final result will be like.

Experimenting with an Example Solution

You should download our solution, a4.jar, from the course webpage. If you double-click its icon, a GUI will appear on your monitor with two color panes and sliders for all the RGB, CMYK, and HSV components. This will give you some idea of what your final result should be like, and help you to understand what you should be doing.

The initial color of the left pane is green, and the pane to its right contains the complementary color. In the title, you see the RGB values for green. In addition, the color pane and complementary-color pane contain information on the RGB, CMYK, and HSV values for the current colors in the panes.

On the bottom, you will see fields into which you can type numbers for the RGB, CMYK, and HSV components. After typing in their RGB numbers, click button RGB and the panels and sliders will change to represent that RGB value; similarly for the other color models. This feature lets a user see what any color in one model looks like in the others. It may be useful to you in debugging --you can see what our solution produces.

The numbers should be in their respective ranges: 0..255 for R, G, B; 0.0..100.0 for C, M, Y, K; 0.0..1.0 for S, V; and 0.0..359.99999999 for H. In a negative number is input, the program replaces it and uses 0 intead. If too large a number is input, the program replaces it and uses the maximum value for the range.

When you move one slider, the colors change accordingly. Furthermore, all other sliders change too, so that all three models (RGB, CMYK, and HSV) register the same color. As a first move, very slowly move Hue slider H up and watch how the colors (and the other sliders) change. Then change the saturation S and value V sliders to see their effect. Play around like this, while reading about the color models, to get an understanding of how they relate to each other.


Assignment Source Code

The example solution is just that — a solution. Now it is time for you to write some Java code that does exactly what that solution does. However, we are still giving you some help, and we have completed part of it for you already. This assignment will involve five .java files, three of which are completed by us, and two of which you must finish yourselves. You can find all of these source code files in a single compressed zip file, which is available here.

The following are the three completed source code files (You should not need to modify the contents of these files at all):

A4.java
This class contains the GUI functionality (e.g. JFrame, sliders, and text boxes) of the program. It will not work at first, but will become more functional as you complete more of the assignment.
HSV.java
Instances of this class represent a color in the HSV color model.
CMYK.java
Instances of this class represent a color in the CMYK color model.

In addition, the following source code files are skeletons (e.g. they are incomplete and you are expected to add functionality to them):

A4Methods.java
The class contains the functions that do most of the work behind the scenes. Filling in the function stubs in this class will help A4.java work properly.
A4Tester.java
This is a JUnit test class to verify that the class A4Methods is working properly. We do not trust your visual color perception enough to leave all the testing to "eye-balling"

To get started with the source code, put them all in a new directory and compile them in DrJava. Then, from the Interactions pane, execute the command

  A4.main(null)

You will see the GUI as discussed above, but the text will not display properly and the two panels will be green. The RGB sliders work, but the other sliders have no effect. Your job is to write and test, one by one, the methods in class A4Methods. As you do, more and more of the GUI will work properly.


Enhanced Testing Methodology

Because we are advancing to more complex programs, you need to start using enhanced testing methodology. First, as usual, write test cases in class A4Tester using assertEquals statements before you write the method body, to check that your method has the correct final behavior; the class A4Tester contains some test cases, but you should add more. As usual, you should organize your test cases into logically coherent test procedures.

In addition, as you write each method, add test cases to ensure there is complete test coverage of the "internals" of the method: each statement or expression within the method body should be exercised by at least one test case. It is OK for one test case to exercise many statements or expressions; but it is not OK for some statement/expression (such as an "else" clause) to not be tested at all. This is the topic of the lecture on March 8th.

Finally, the JUnit test is nice, but it would also be good to debug while the GUI is running. As shown in class, the way to do this is with println statements. The procedure call System.out.println(s) prints its arguments into the Console window.

Here is an example of using println. Suppose you are trying to find an error in method RGB2HSV (or in a method that calls RGB2HSV) and that RGB2HSV changes a variable h at line 36. Then, you might insert at line 37 a statement like

   System.out.println("RGB2HSV: h at line 36 is " + h);

Execution of this call prints the value of h to the Console window, and if that value is not what you expected, you have learned something about the source of the error you are tracking down.


About Objects Containing Color Values

The built-in class java.awt.Color is used to maintain RGB colors. You should use import java.awt.*; as the first line of your .java file to access this class. You create a new RGB color object using new Color(r,g, b), where r, g,and b are in the range 0..255. Given an RGB object c, you can obtain its three components using the methods c.getRed(), c.getGreen(), and c.getBlue().

For the other color models &mdash CMYK and HSV &mdash use the classes CMYK and HSV that we have provided. Take a look at the classes; their use should be obvious. The toString functions in these classes call functions in A4Methods, which you will write.


Assignment Instructions

Below, we outline the functions that you are expected to write for this assignment. You should write and test your functions, one at a time, in the order given. Read the text below, but also make sure you carefully read the specifications and comments in the provided code. In this assignment, sometimes we give hints in the specs/comments about how best to write your functions.

complementRGB(Color)

We gave you some partial code that you need to fix. The complement of a color is like a color negative. If R, G, and B are color components of the RGB value in the range 0.0..1.0 (not 0..255!), then the color components of the complement are 1-R, 1-G, and 1-B. However, remember that you must convert everything back to 0..255 before you make the color value. When you convert back, this means that the complementary color of the RGB color [r, g, b] is the color [255-r, 255-g, 255-b].

We provide a test case for this function in the class A4Tester (should you add more?). This test case which will not work until you rewrite the function. Finish the function and test that it works.


truncateTo5(double)

There is a stubbed-in return statement in the current version of this function so that the program compiles. Write this function, using the guidance given as comments in the body. We have provided test cases for it in class A4Tester (should you add more?) so that you can test it when done. This function will be needed later.


roundTo5(double)

This function is most easily written by calling truncateTo5 appropriately. There is a stubbed-in return statement in it so that the program compiles. Write this function, using the guidance given as comments in the body. We provided test cases for it in class A4Tester (should you add more?). Within this assignment, this function should be used only to get values to appear in the GUI in a consistent format; values should always 5 characters long.


toString(Color)

You will need to write this function. It is a static function, and not the instance method that you are generally used to. When this is written, RGB values will appear in the title of the GUI and in the two color panes. We provided one test case for this function in class A4tester; that is all that is needed.


toString(CMYK)

You will need to write this function. When written, CMYK values will appear in the two color panes. This function should call function roundTo5 to round each CMYK value to 5 characters. We do not provide test cases for this function. You must write at least two of them.


toString(HSV)

You will need to write this function. When written, HSV values will appear in the two color panes. This function should call function roundTo5 to round each HSV value to 5 characters. We do not provide test cases for this function. You must write at least two of them.


convertRGBtoCMYK(Color)

This function converts an RGB value to a CMYK value. When you get it working, moving the RGB sliders will cause the CMYK sliders to move as well. There are several different ways to convert, depending on how much black is used in the CMYK model. Our conversion uses as much black as possible.

Let R, G, and B be the color components of the RGB in the range 0.0..1.0 (not 0..255!); that means that you will need to divide the values in Color by 255.0. Once you do that, then the conversion is as follows:

  1. Compute C' = 1 - R,   M' = 1 - G,   and   Y' = 1 - B.
  2. If C', M', and Y' are all 1, use the CMYK value (0, 0, 0 , 1).
    If not, compute and use the following:
          K = minimum of C', M', and Y',
          C = (C' - K)/(1 - K),   M = (M' - K)/(1 - K),   Y = (Y' - K)/(1 - K).

The resulting CMYK values are in the range 0.0..1.0, and they must be converted to the range 0..100.0. And that is it! Not too bad, eh?

Providing test cases is a bit problematic because double values are only approximations to the real values, and slightly different ways of computing might produce different results. To show you how to do this, we provide in A4Tester three test cases, testing only the rounding of the values to 5 characters (except in the two first, extreme cases), since that is what appears in the color panes of the GUI. Add a few more test cases following our example.


convertCMYKtoRGB(CMYK)

This function converts a CMYK value to an RGB value. When you get it working, moving the CMYK sliders will cause the RGB sliders to move as well. Let C, M, Y, and K be the color components of the CMYK value, all in the range 0.0..1.0 (not 0..100.0; you will need to convert this first). Then the conversion is as follows:

           R = (1 - C)(1 - K),            G = (1 - M)(1 0 K),            and B = (1 - Y)(1 - K)

This produces RGB values in the range 0.0..1.0, and they must be converted to the range 0..255. You should use rounding in converting the answer to an int. We will say it again because in previous semesters students have not complied: ROUND; DO NOT TRUNCATE. Remember that casting truncates, and does not round.

You should put at least two test cases for this function in class A4Tester. To figure out what test cases to use, you can use the example solution that we provided (a4.jar) in order to find out what the values in one color model should be in a different color model.


convertRGBtoHSV(Color)

This function converts an RGB value to an HSV value. Warning: class Color has a function RGBtoHSB, but it produces output in a different format than what we want (and uses a construct you have not learned about yet). So, in this case, do not use this pre-existing code. In our experience, it is easier (and more educational) for students to write this function from scratch than to figure out how to correctly employ the static method Color.RGBtoHSB.

When you get the function working, moving the RGB sliders will cause the HSV sliders to move. Here is how the conversion works:

Let MAX be the maximum and MIN be the minimum of the (R, G, B) values. H will satisfy 0 ≤ H < 360 and S, V, R, G, and B will be in 0..1.

H is given by 5 different cases:

(a) MAX = MIN: H = 0
(b) MAX = R and G ≥ B:       H = 60.0 * (G - B) / (MAX - MIN)
(c) MAX = R and G < B: H = 60.0 * (G - B) / (MAX - MIN) + 360.0
(d) MAX = G: H = 60.0 * (B - R) / (MAX - MIN) + 120.0
(e) MAX = B: H = 60.0 * (R - G) / (MAX - MIN) + 240.0

S is given by: if MAX = 0 then 0, else 1 – MIN/MAX. Finally, V = MAX.

You have to provide at least 5 test cases in class A4Tester, so that each expression in the cases for H is evaluated in at least one test case.


convertHSVtoRGB(HSV)

This function converts an HSV value to an RGB value. When you get it working, everything in the GUI should work (provided that you followed instructions and left this function for the end).

To peform the convertion, you first need to compute a the following values

Hi = floor(H/60),     f = H/60 – Hi,     p = V(1-S),     q = V(1-fS),     t = V(1-(1-f)S)

Once you have this computed, the values R, G, and B depend on the value H' as follows:

If Hi = 0, then R = V,  G = t,    B = p
If Hi = 1, then R = q,   G = V,  B = p
If Hi = 2, then R = p,   G = V,  B = t
If Hi = 3, then R = p,   G = q,   B = V
If Hi = 4, then R = t,    G = p,   B = V
If Hi = 5, then R = V,  G = p,   B = q

This produces RGB values in the range 0.0..1.0, and they must be converted to the range 0..255. You should use rounding in converting the answer to an int. We will say it again because in previous semesters students have not complied: ROUND; DO NOT TRUNCATE. Remember that casting truncates, and does not round.

In testing your code, you should provide at least 6 test cases for this function because of the 6 possible values of Hi.

Note: If you look at the Wikipedia entry, you will note that it uses

             Hi = floor(H/60) % 6              and              f = H/60 – floor(H/60)

Because H satisfies 0 <= H < 360 (degrees), the values (floor(H/60) % 6) and floor(H/60) are equivalent. Therefore, we use the simpler one.


Finishing the Assignment

At the very top A4Methods.java you should put two single line comments (//, not /** */). In the first comment, put your name(s) and the date. In the second comment, put how much time you have spent working on this assignment. We gather those statistics to help us gauge the class.

In addition, you should make sure that class A4Methods is indented properly. Do this by hitting tab on every line in DrJava, so that it will auto-indent for you. Do the same for A4Tester as well.

Turning it In

Upload files A4Methods.java and A4Tester.java onto CMS by the due date: Thursday, March 15th at 11:59PM (Just before Spring break). You do not need to submit any of the other source code files. Do not submit any files with the extension/suffix .java~ (with the tilde) or .class. It will help to set the preferences in your operating system so that extensions always appear.