Simon gameCS109 Programming ProjectsImage processingColors!

Colors!

You are probably quite familiar with the RGB representation of colors: using three values to indicate the intensity of red, green, and blue. The setRGB method of BufferedImage uses this representation, and so does the org.otfried.cs109.Color class.

For many purposes, however, the HSV representation is more suitable. It represents a color using three components:

Displaying a rainbow

Our first program will display a window like this:

Rainbow output for v = 255

In this image, the hue changes from 0 at the left edge to 359 at the right edge: you see that hue is cyclic modulo 360, and that hue zero corresponds to red. The saturation changes from 0 at the top edge to 255 at the bottom edge. The value is constant at 255, but can be changed from the command line.

We first need to learn how to display a window. You need to have the CS109UI module installed, see the installation instructions.

Download the example program uitest1.kt. You can run the example from the command line by saying:

$ ktc uitest1.kt
$ kt Uitest1Kt 

Read the section "Basic Usage" of the cs109ui documentation.

Our program rainbow.kt will take one command line parameter, the value v (if the command line parameter is omitted, use v = 255). It should then create a BufferedImage of width 360 and height 256, and fill pixel \((x,y)\) of this image with the color with hue \(x\), saturation \(y\), and value v. To set the pixel, use the setRGB method of BufferedImage.

Here is a function that converts from HSV representation to RGB representation:

// Input h in [0,359], s in [0,255], v in [0,255]
// Output r,g,b in [0,255]
fun hsvtorgb(h: Int, s: Int, v: Int): Triple<Int, Int, Int> {
  if (s == 0) {
    // no color, just grey
    return Triple(v, v, v)
  } else {
    val sector = h / 60
    val f = (h % 60) 
    val p = v * ( 255 - s ) / 255
    val q = v * ( 15300 - s * f ) / 15300
    val t = v * ( 15300 - s * ( 60 - f )) / 15300
    return when(sector) {
      0 -> Triple(v, t, p)
      1 -> Triple(q, v, p)
      2 -> Triple(p, v, t)
      3 -> Triple(p, q, v)
      4 -> Triple(t, p, v)
      else -> Triple(v, p, q)
    }
  }
}

Compile and run your program like this:

$ ktc rainbow.kt
$ kt RainbowKt 180

Here is the output for a few different v-values:

Rainbow output for v = 180
Rainbow output for v = 120
Rainbow output for v = 60

Animating the color

Now read the section "Updating the display" of the cs109ui documentation, and change the program as follows: It no longer takes a command line parameter. Instead the v-value starts with v = 255, but then it continuously changes until it reaches v = 0. The program should terminate automatically after that.

Change the v-value by one every time you call show, and wait for 100 milliseconds. You should also change the title of the window so that it always shows the current v-value.

How good is your color vision?

Let's now write a program that can test your color vision. It displays a window like this:

Color vision tester window

There are 16 squares with a randomly chosen color. 15 squares have the same color, one is slightly different. The user should enter the coordinates of the square with the different color ("2b" would be the correct answer in this case). Here is a sample dialog:
$ ktc colorguess.kt 
$ kt ColorguessKt
Which square has a different color? (x to exit) 3a
That is correct
You answered 1 of 1 tests correctly.
Which square has a different color? (x to exit) 1b
That is correct
You answered 2 of 2 tests correctly.
Which square has a different color? (x to exit) 3a
That is correct
You answered 3 of 3 tests correctly.
Which square has a different color? (x to exit) 2b
That is correct
You answered 4 of 4 tests correctly.
Which square has a different color? (x to exit) 1d
That is correct
You answered 5 of 5 tests correctly.
Which square has a different color? (x to exit) 3b
That is not correct.  Square 4c has a different color.
Press Enter for the next question>
You answered 5 of 6 tests correctly.
Which square has a different color? (x to exit) 2d
That is not correct.  Square 2c has a different color.
Press Enter for the next question>
You answered 5 of 7 tests correctly.
Which square has a different color? (x to exit) 1c
That is correct
You answered 6 of 8 tests correctly.
Which square has a different color? (x to exit) x

Note that when the answer is correct, the program immediately displays the next test. When the answer is not correct, however, we need to give the user the chance to look at the colors again after revealing the correct answer—that's why the program says "Press Enter for the next question".

Your program should have one command line parameter, an integer that we will call delta. It indicates the distance between the different color and the standard color. If no command line argument is given, use the value delta = 20.

The following function generates a random color in HSV space:

fun randomHSV(): Triple<Int, Int, Int> {
  return Triple(random.nextInt(360),
  	        128 + random.nextInt(128),
		128 + random.nextInt(128))
}

(Note that I'm excluding colors that are too dark or too grayish.)

The special color differs only in its hue from the standard color (saturation and value are the same). Flip a coin (for instance, using random.nextInt(2)). With probability \(1/2\), add delta to the hue, otherwise add 360 - delta to the hue (don't forget to do this operation modulo 360).

Keep showing colors to the user until the user types "x".

Here is an example for delta = 5. Can you distinguish the different color?

Color vision tester window for delta = 5

Bonus: Use mouse to select answer

Change your program so that instead of using the keyboard, the user should select the different color by clicking on the square.

Read the section "Mouse input" of the cs109ui documentation.

Your program should not use the terminal at all, all input and output should be through the graphical user interface.

Simon gameCS109 Programming ProjectsImage processingColors!