Functional Problem Solving (CSC 151 2014F) : Assignments
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] - [FAQ] [Teaching & Learning] [Grading] [Rubric] - [Calendar]
Current: [Assignment] [EBoard] [Lab] [Outline] [Reading]
Sections: [Assignments] [EBoards] [Examples] [Handouts] [Labs] [Outlines] [Readings]
Reference: [Setup] [VM] [Errors] - [Functions A-Z] [Functions By Topic] - [Racket] [Scheme Report (R5RS)] [R6RS] [TSPL4]
Related Courses: [Davis (2013F)] [Rebelsky (2014S)] [Weinman (2014F)]
Misc: [Submit Questions] - [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] - [Issue Tracker (Course)]
Due: 10:30 p.m., Tuesday, 7 October 2014
Summary: You will explore color types and some novel color transformations.
Purposes: To practice conditionals and have some fun with the HSV color representation.
Collaboration: If you have been assigned to a group, you must work with your assigned partners on this assignment. The partner assignments are available at http://www.cs.grinnell.edu/~rebelsky/Courses/CSC151/2014F/partners/assignment.05.html. You may discuss this assignment with anyone, provided you credit such discussions when you submit the assignment.
Wrapper (Prologue): Individually read through this assignment and make sure that you understand what is required. Then use the form available at http://bit.ly/151hw5pro to indicate (a) how long you think this assignment will take and (b) what you think will be the most challenging aspect of this assignment.
Wrapper (Epilogue): When you are done with the assignment, fill out the form available at http://bit.ly/151hw5epi to indicate (a) how long the assignment took, (b) what the most challenging part of the assignment was, and (c) something important you learned from doing the assignment. If you find that the assignment took much less or much more time than you expected, also include (d) a note as to what might have led to that difference.
Submitting:
Email your answer to <grader-151-01@cs.grinnell.edu>
. The subject of your email
should have the form CSC 151.01 Assignment 5: Conditionals
and
should contain your answers to all parts of the assignment. Scheme code
should be in the body of the message.
Warning: So that this assignment is a learning experience for everyone, we may spend class time publicly critiquing your work.
a. Write a predicate, (
, that returns is-color?
value
)#t
when value
is either an RGB color or a color
name recognized by MediaScript. In all other cases, it should return
#f
.
You can use the predicates irgb?
and
color-name?
, which are already defined, to help
you. You should not use the predicate color?
; we
want you to write your own version.
b. Write your own version of color-to-irgb
,
which is a very useful procedure.
Your procedure should have the following behavior:
If given an RGB color, it returns that color unchanged.
If given a color name, it returns the result of calling
color-name->irgb
on that color name.
If given any other type of value, it returns #f
.
You should not use the built-in color->irgb
procedure; we want you to write your own version.
As we learned in the reading on design and color representing colors in terms of hue, saturation, and value is an alternative to RGB representation. Hue represents the pure color (e.g., red, blue, yellow, green, or a combination of one of these). Saturation represents the "colorfulness" of the hue in the color. For instance, a completely saturated color would be a pure hue (like red), while a less saturated color might appear just as bright but somewhat faded (perhaps rose or pink). Value, then represents the brightness or darkness of the color.
As shown below, hue is represented as an angle, or a point on a circle. Thus, the values 0-360 sweep through colors red (0 degrees), yellow (60 degrees), green (120 degrees), cyan (180 degrees), blue (240 degrees), magenta (300 degrees), and back to red (at 360 or 0 degrees).
There are a variety of transformations that can take an RGB color and give an HSV representation. In this problem, we'll focus on just extracting the hue.
Before we describe how to calculate hue, we need some basic values
to refer to. Let
(red
, green
, blue
)
refer to the red, green, and blue components of an RGB color,
respectively. The chroma
of a color is the
largest of the RGB components minus the smallest of the RGB
components. For example, the chroma of (128,64,50) is 128-50, or 78;
the chroma of (0,255,0) is 255-0, or 255. The chroma of
(255,255,255) is 255-255, or 0.
The raw hue can then be calculated as follows:
green
-blue
)/chroma
if red
is a largest component
blue
-red
)/chroma
) + 2
if green
is a largest component
red
-green
)/chroma
) + 4
if blue
is a largest component
chroma
=0 the hue is undefined, because all the
components are the same and we would have a gray. In this case,
one convention is to set the hue to 0.
Note that the numerators of the fractions make some intuitive
sense. For example, if the red component is largest, and the green
component is larger than the blue component, then we should move
counter-clockwise (positive), toward green. And, as we'd hope, the
(green
-blue
) is positive.
Similarly, if the red component is largest and the blue component is
larger than the green component, then we should move counter-clockwise
(negative), toward blue. And, as we'd hope, the
(green
-blue
) is negative.
The raw hue as given above produces a value between -1 and 6 (corresponding to the 6 cardinal colors described above). Why would we end up with a negative number? Well, we just saw that colors in which red dominates that have a larger blue component shift by a negative value. If the raw hue is negative, we should add 6 to get us back to a positive representation. The final result is converted to the range 0-360 by multiplying by 60 degrees (which is 360/6).
What happens if chroma
is not 0, and two of
the components are both the largest? If the formula is
well-designed, it shouldn't matter. But is it? Let's design
a quick test.
a. Write three functions, reddish-hue
,
greenish-hue
, and blueish-hue
, that
take as input an integer-encoded IRGB color and return the computed
hue. For example, (blueish-hue (irgb 255 0 255))
should return 5, because the chroma is 255,
(red
-green
) is
255, 255/255 is 1, and 1 + 4 is 5.
b. Write a test suite, hue-equality-tests
that confirms
the assertion that when a color has two equal RGB components, it
doesn't matter which of the two corresponding computations we use.
(define hue-equality-tests (test-suite "tests of different mechanisms for computing hues" (test-case "red = blue; red > green" (check-= (reddish-hue (irgb 255 0 255)) (blueish-hue (irgb 255 0 255)) 0) (check-= (reddish-hue (irgb 1 0 1)) (blueish-hue (irgb 1 0 1)) 0))))
c. Using the algorithm given above, write a
procedure, (
, that takes an RGB color and produces
its hue. For example,
irgb->hue-angle
irgb
)
>
(irgb->hue-angle (color->irgb "red"))
0
>
(irgb->hue-angle (color->irgb "yellow"))
60
>
(irgb->hue-angle (color->irgb "green"))
120
>
(irgb->hue-angle (color->irgb "cyan"))
180
>
(irgb->hue-angle (color->irgb "blue"))
240
>
(irgb->hue-angle (color->irgb "magenta"))
300
>
(irgb->hue-angle (color->irgb "pink"))
7340/21
>
(round (irgb->hue-angle (color->irgb "pink")))
350
Note: You do not need to use the procedures you wrote for part a, although you may find them helpful. You may also find it usefl to write other procedures to decompose your implementation into managable, meaningful units. Please be sure to give your variables and procedures meaningful names.
Being able to manipulate the hue in a color can actually be quite
useful. MediaScheme can convert an HSV color into an integer-encoded
RGB color with the
procedure
(
,
where hsv->irgb
hsv-list
)hsv-list
is a three-element list
containing the hue, saturation, and value components of a HSV
color. You can create that list with the list
procedure. For example, to create a magenta-like color with
50% saturation and 25% value, we would use
(
or
hsv->irgb
(list 5 1/2 1/4))(
.
hsv->irgb
(list 5 .5 .25))
MediaScheme can also extract the saturation and value from an RGB color
with the procedures (
and irgb->saturation
irgb-color
)(
.
irgb->value
irgb-color
)
a. Write a procedure, (
, that
takes an integer-encoded RGB color and a hue value (in the range 0-360) as
parameters and creates
a new integer-encoded RGB color using the given hue with the saturation
and value of irgb-change-hue
irgb-color
hue
)irgb-color
.
b. Write a procedure, (
that finds the
true complement of irgb-true-complement
irgb-color
)irgb-color
,
one that is 180 degrees away on the color wheel with the same saturation
and value.
Color transformations based on hue be can visually interesting.
![]() |
![]() |
![]() |
Original Image | Hue rotated 30 deg | Hue rotated 90 deg |
a. Using the procedures you have written so far, write a procedure
(
that takes an integer-encoded RGB color and an angle as parameters
and produces a new integer-encoded RGB color where the HSV equivalent
has a hue rotated by irgb-rotate-hue
irgb-color
angle
)angle
degrees, a number
between 0-360.
Hint: If the rotated angle is greater than 360,
be sure to wrap around properly (e.g.,
using modulo
) to get the correct hue angle.
b. Write an expression as concisely as possible that will rotate the
hues in an entire image (say, called picture
) by 30 degrees.
Warning: When you
apply irgb-rotate-hue
thousands of times (as you
will in an image of non-trivial size), it is likely to take some
time. If you conduct experiments during development, do those
experiments on small images.
Write and document your own RGB color transform that transforms the hue of its input color conditionally using a manner of your own choosing. For instance, you may choose to shift colors close to blue more toward green, leaving the rest unchanged.
Your 6P documentation should include a description of the effect of
your transform in English. We should be able to apply your transform
using image-variant
or
image-transform!
.
Design, document, and implement a Color Scheme Generation Toolkit. Your toolkit should consist of a suite of related procedures. Each procedure will take an integer-encoded RGB color as a parameter and produce a list of colors forming a coherent color scheme. Some procedures may need to take additional parameters: You decide what those parameters will be. You will find the procedures related to hue, saturation, and value very useful.
You should at least write procedures to do the following:
In exercise 2b, you used a series of tests to convince yourself that when a color had two equal largest components, it did not matter which of two formulae you used to compute the hue. But, as you've seen in the past, an incomplete test suite can sometimes convince you that something works when it doesn't. In the exercise above, incorrect implementations of all three procedures could also pass the test. For example, if all three procedures always return 0, they would return the same value.
What's the alternative if you can't be perfectly confident in your tests? One option is to write more tests. For example, we could test each formulae separately on some known values.
But the gold standard is a proof of correctness (or, in this case,
equality). Prove that
((blue
-red
)/chroma
)
+ 2 is the same as
((red
-green
)/chroma
)
+ 4 when blue
and green
are equal and larger than red
.