HW 3: Color Transformations and Image Filters
Due: Tuesday, February 7 by 10:30pm
Summary: In this assignment, you will explore mechanisms for transforming colors and see how those mechanisms can then be applied to images. Our primary focus is on color transformations.
Purposes: To give you more experience with colors and color transformations. To give you more experience writing your own functions. To have a bit of fun.
Collaboration: You must work with assigned partners on this assignment. You may discuss this assignment with anyone, provided you credit such discussions when you submit the assignment.
Submitting: Email your answer to csc151-01-grader@grinnell.edu. The title of your email should have the form [CSC 151.01] Assignment 3 and should contain your answers to all parts of the assignment. Scheme code should be in the body of the message. You should not attach any images; we should be able to re-create them from your code.
Warning: So that this assignment is a learning experience for everyone, we may spend class time publicly critiquing your work.
Background
You have recently begun to explore the RGB color model as well as functions that transform RGB colors. You have seen a wide variety of built-in color transformations, including irgb-complement
, irgb-lighter
, and irgb-redder
. You have also started to might write your own color transformations. You have learned a variety of mechanisms for writing color transformations.
- You can use the composition operator, to combine other unary transformations into a single transformation. For example, you might write a procedure that cuts the high components with the following code.
(define irgb-limit-high (compose irgb-darker irgb-darker irgb-lighter irgb-lighter))
- You can use the
section
procedure to fill in one parameter of a binary color operation. For example, you might write a procedure that decreases the red component by 64 with the following code.
(define irgb-decrease-red (section irgb-subtract <> (irgb 64 0 0)))
- You can use a generalized lambda expression to write your transformation, using a pattern something like the following.
(define irgb-transform
(lambda (color)
(irgb (function-to-compute-new-red-component color)
(function-to-compute-new-green-component color)
(function-to-compute-new-blue-component color))))
For example, to decrease each of the components by 32, you might write:
(define irgb-subtract-32
(lambda (color)
(irgb (- (irgb-red color) 32)
(- (irgb-green color) 32)
(- (irgb-blue color) 32))))
As you may have noted, by using image-variant
and a color transformation, we have effectively written a simple image filter, akin to those that come with Adobe Photoshop and other image editing applications.
In this assignment, you will build some color transformations and explore their utility as image filters.
Assignment
Problem 1: Extreme components
Topics: RGB colors, Color transformations, Clever numeric computation
Write a procedure, (
irgb-extreme
color)
, that takes one parameter,
an integer-encoded RGB color, and turns each component to 255 if it is
at least 128 and to 0 if it is less than 128.
> (irgb->string (irgb-extreme (irgb 0 64 200)))
"0/0/255"
> (irgb->string (irgb-extreme (irgb 128 130 0)))
"255/255/0"
Hint: Some ideas for this problem appear in a recent lab.
Problem 2: Dominant components
Topics: RGB colors, Color transformations, Clever numeric computation
Write a procedure, (irgb-dominant-component color)
, that takes
one parameter, an integer-encoded RGB color, and produces a new color
in which each component is 255 if it is the largest component (or tied
for largest) and 0 otherwise.
> (irgb->string (irgb-dominant-component (irgb 0 5 0)))
"0/255/0"
> (irgb->string (irgb-dominant-component (irgb 200 199 199)))
"255/0/0"
> (irgb->string (irgb-dominant-component (irgb 10 0 10)))
"255/0/255"
Hint: You should be able to do this with a clever combination of
max
, division, rounding, and multiplication.
Problem 3: Flattening
Topics: RGB colors, Color transformations, Clever numeric computation
A common technique for manipulating images is known as “flattening” the image. In general, we flatten an image by restricting the values of each component to multiples of a certain value. For example, we might ensure that the components are each multiples of 16, 32, or 64. (We’ll use 255 instead of 256 for the highest multiple.)
How do we convert each component to the appropriate multiple? Consider the case of multiples of 32. If we divide the component by 32, round, and then multiply by 32, we’ll get the nearest multiple of 32. For example,
> (* 32 (round (/ 11 32)))
0
> (* 32 (round (/ 21 32)))
32
> (* 32 (round (/ 71 32)))
64
> (* 32 (round (/ 91 32)))
96
> (* 32 (round (/ 211 32)))
224
> (* 32 (round (/ 255 32)))
256
As the last example suggests, we may sometimes get a number outside of
the range 0..255. Fortunately, the irgb
and irgb-new
functions treat
256 (and any reasonable number greater than 256) the same as 255.
Write a procedure, (
irgb-flatten-64
irgb-color)
, that flattens an
IRGB color by converting each component to the nearest multiple of 64.
You may then want to see the effect this procedure has on various images.
> (define kitten (image-load "/home/rebelsky/Desktop/kitten.jpg"))
> (image-show kitten)
> (image-show (image-variant kitten irgb-flatten-64))
Hint: The sample code for computing nearest multiples of 32 should help.
Problem 4: Cycling Through Colors
Topics: irgb colors, writing procedures, section, compose
As you have seen, when we apply the typical color transformation, such
as irgb-darker
or irgb-redder
, we eventually reach a limit of 0 or
255. But we can get some interesting effects by “wrapping around”
at the end. For example, here’s the output from a function that adds 90
to a number, wrapping when we hit 255.
> (cyclic-add-90 75)
165 ; 75 + 90 = 165
> (cyclic-add-90 165)
255 ; 165 + 90 = 255
> (cyclic-add-90 166)
0 ; 166 + 90 = 256, wrap around to 0
> (cyclic-add-90 167)
1 ; 167 + 90 = 257, wrap around to 1
> (cyclic-add-90 255)
89 ; we wrap around because we hit 255
> (cyclic-add-90 89)
179 ; 89 + 90 = 179
> (cyclic-add-90 179)
13 ; 179 + 90 = 269, 269 - 256 = 13
As you might expect, cyclic-add-90
can be written in a variety of ways, combining addition and remainder.
(define cyclic-add-90
(lambda (val)
(remainder (+ val 90) 256)))
(define cyclic-add-90 (compose (section remainder <> 256) (section + <> 90)))
Write a procedure, (irgb-cyclic-add color1 color2)
, that takes two
colors as input and produces a new color formed by the cyclic addition
of the corresponding components of the two colors.
Problem 5: Gamma correction
Topics: RGB colors, Color transformations, Brightness
Because humans do not perceive brightness linearly, some image formats modify the meaning of the stored values’ brightness scale (0-255) to better cover the range of sensitivities with a nonlinear transformation.
The typical transformation is commonly called a Gamma
correction,
for the name of the parameter used to determine the extent of
rescaling. In particular, when a color component brightness
value is on the real-valued scale of 0-1 (rather than our
discrete 0-255 scale), the transformation is given by V_out =
(expt V_in gamma)
. You can read more about this transformation at
Wikipedia
if you’re especially curious, or simply forge ahead with the assignment if you’re
not.
In this problem, you will implement a series of steps to do this gamma correction on an image.
a. Write a procedure, (transform-value component gamma)
, that
takes a color component value (i.e., a single number in the range 0-255),
and applies the gamma correction described above. Note that you’ll
need to rescale the component to the range 0-1 (by dividing) before you
exponentiate and rescale it back to 0-255 (by multiplying) afterward.
b. Write a procedure, (irgb-correct irgb-color gamma)
, that applies
transform-value
to each component of irgb-color
using gamma
.
Since image-variant
expects a single-parameter procedure, we might
build particular versions of irgb-correct
for different gammas.
(define irgb-correct-2.2 (section irgb-correct <> 2.2))
(define irgb-correct-0.45 (section irgb-correct <> 0.45))
You can explore the power of irgb-correct
by applying one of these to every pixel in an image.
(image-variant kitten irgb-correct-2.2)
(image-variant kitten irgb-correct-0.45)
Problem 6: Make your own
Topics: Color transformations
Design your own color transformation and explore its application to an image or images of your choice. You should only turn in the transformation; we will explore its effect on various images. As you might expect, particularly interesting or clever transformations are likely to earn extra credit. More straightforward transformations will still earn full credit.
Important Evaluation Criteria
We will judge your solutions on their correctness, concision, and cleverness.