Laboratory: Building Images by Iterating Over Positions
Summary:
In this laboratory, you will explore techniques for building and modifying
images by iterating over the positions in an image.
Reference:
Exercises
Exercise 1: Simple Images
As you learned in the reading, one of the simplest ways to use
image-compute is to create an image
of a uniform color. For example, we might make a small pink image with
(define image-color (color-name->rgb "hotpink"))
(image-show (image-compute (lambda (col row) image-color)
30 10))
a. Confirm that these instructions work as advertised.
b. Using a similar instruction, make a larger pink image.
c. Using a similar instruction, make a larger black image.
d. What do you think will happen if you provide
image-compute with a negative
width or height?
e. Check your answer experimentally.
f. What do you think will happen if you provide
image-compute with something other
than a function for the first parameter?
g. Check your answer experimentally.
h. What do you think will happen if you provide
image-compute with a function
that returns a non-color?
i. Check your answer experimentally.
Exercise 2: Color Blends
a. The reading claims that the following instructions will create
an image the provides a blend from black to red. Confirm that
the claim is correct.
(image-compute
(lambda (col row)
(rgb-new (* col 2) 0 0))
129 65)
b. What do you expect the image to look like if we use a larger width
(say 257) and height (say 129)?
c. Check your answer experimentally.
d. What do you expect the image to look like if we use a smaller width
(say 65) and height (say 33)?
e. Check your answer experimentally.
f. As you may have noted, when we used the 129x65 formula for a bigger
image, the rightmost pixels were all red. Write an expression to create
a 257x129 image that contains a full horizontal black-to-red blend.
g. As you may have noted, when we used the 129x65 formula for a smaller
image, we didn't make it very far from black.
Write an expression to create a 65x33 image that contains a
full black-to-red blend.
h. Write an expression to build a 129x65 image that has a vertical blend
from black to purple.
Exercise 3: Two-Dimensional Color Blends
In the previous problem, you made images that showed blends ranging
over a single dimension, either horizontally or vertically. However, we can
certainly blend colors in both dimensions.
a. The reading provided one such blend in which the red component increased
as you move horizontally from left to right and the blue component increased
as you move vertically from top to bottom. Verify that this procedure
works as advertised.
(image-compute
(lambda (col row)
(rgb-new (* col 2) 0 (* row 4)))
129 65)
b. Rewrite this expression so that the blue component decreases (from 255
to 0) as you move from the top to the bottom of the image.
c. Of course, the components can depend upon both the row and the column.
Write an expression that generates a 65x64 image that contains a
diagonal blend from black to red
in a 65x64 image. Your result should look something like the following:
Exercise 4: Generalizing Color Ranges
One thing that a good programmer does is generalize her code, so that it
works in a variety of situations. The color range code we've written so
far is fairly specific to the image size (and even the image placement).
For example, let's consider the computation of a horizontal black-blue
blend in a 33x17 image. The core part of that code is likely to read as
follows:
(image-compute
(lambda (col row) (rgb-new 0 0 (* 8 col)))
33 17)
Where do each of the numbers come from? The 33 is the width and the 17
is height. (In case you haven't noticed by now, many blend computations
are easier if we make a dimension one more than a power of 2, so that the
number of steps is a power of two.) The two zero values represent
the red and green components. Where does the 8 come from? It's 256
divided by the number of steps from 0 to 256. If the width were 65
(64 steps), we would use 256/65 = 4.
a. Write a procedure, (horiz-black-to-blue
width height) that creates
a width-by-height image
with a horizontal blend from black to blue.
b. Write a procedure, (horiz-blue-to-black
width height) that creates
a width-by-height image
with a horizontal blend from blue to black.
c. In each of these procedures, the red and green components stay
constant and the blue component ranges from some value (0 in the
first case, 256 in the second) to some other value (256 in the first
case, 0 in the second). We can generalize these two procedures by
making the initial and final blue component values parameters.
Write a procedure, (horiz-blue-blend
width height
initial final)
that creates
a width-by-height image
with a horizontal blend from (0,0,initial)
to (0,0,final).
d. Rewrite horiz-black-to-blue and
horiz-blue-to-black in terms of
horiz-blue-blend.
Exercise 5: More Complex Computations
You may recall a more complex computation of colors from the reading, one that
used sin to determine values. Here's a simplified version of
that code:
(image-compute
(lambda (col row)
(rgb-new 0
(* 128 (+ 1 (sin (* pi 0.025 col))))
0))
40 50)
a. What range of values does (* pi 0.025 col)
compute?
b. What range of values does (sin ...)
compute?
c. What range of values does (+ 1 (sin ...)) compute?
d. What range of values does (* 128 (+ 1 (sin ...)))
compute?
e. Given that analysis, what kind of image do you expect the preceding code to
draw?
f. Check your answer experimentally.
g. The reading had a somewhat more complex set of instructions.
(image-compute
(lambda (col row)
(rgb-new 0
(* 128 (+ 1 (sin (* pi 0.025 col))))
(* 128 (+ 1 (sin (* pi 0.020 row))))))
40 50)
Explain why there might be a .020 rather than a .025 in the computation of
the blue component.
h. Predict the appearance of the computed image.
i. Check your answer experimentally.
Exercise 6: Rectangles
Suppose we have an existing image. There are at least three ways
that we can add a rectangular region to the image by computing the
pixels of that region.
We can iterate over the whole image, using rgb-transparent
outside of the rectangle and the desired color inside the rectangle.
(This strategy mimics the technique described in the reading for
building a new image, except that we use rgb-transparent
rather than the background color.)
We can interate over the rectangular region, setting the pixel at each
position in the region to the color.
We can select the rectangular region (e.g., with
image-select-rectangle!) and then
iterate over the selection.
Let's explore each of these in a bit more depth. For the examples,
we'll use 10 as the left edge of the rectangle, 15 as the top, 20
as the width, and 40 as the height. (Note that the right edge is
at 30 (10+20) and the bottom edge is at 55 (15 + 40).
a. Create a new white 100x100 image, called canvas, on which
you can experiment.
b. Determine whether the following successfully uses
image-compute-pixels! to compute a red rectangle.
(image-compute-pixels!
canvas
(lambda (col row)
(if (and (<= 10 col 30) (<= 15 row 55))
(rgb-new 255 0 0)
rgb-transparent)))
c. Determine whether the following successfully uses
region-compute-pixels! to compute a blue rectangle.
(region-compute-pixels!
canvas
10 15 20 40
(lambda (col row)
(rgb-new 0 0 255)))
d. Determine whether the following successfully uses
selection-compute-pixels! to compute a black
rectangle.
(image-select-rectangle! canvas REPLACE 10 15 20 40)
(selection-compute-pixels!
canvas
(lambda (col row)
(rgb-new 0 0 0)))
e. At least one of these techniques has a subtle flaw. Identify and
correct the flaw.
f. Once that flaw is corrected, which of these techniques do you most prefer,
and why? Be prepared
to share your choice and rationale with your peers.
g. Using the technique of your choice, write a procedure,
(compute-rectangle! image
left top
width height
color)
that fills in the specified rectangle.
Exercise 7: Circles, Circles, and More Circles
Consider the following code from the reading.
(image-compute
(lambda (col row)
(if (<= (+ (square (- col 40)) (square (- row 50)))
(square 30))
(rgb-new 255 0 0)
(rgb-new 0 0 0)))
145 91)
a. Confirm that the code does, in fact, draw a red circle on a black
background.
b. What do you expect to have happen if we change the 40 to 10 and the 50
to 70?
c. Check your answer experimentally.
d. What do you expect to have happen if we change the 30 to 60?
e. Check your answer experimentally.
f. As the reading suggested, instead of just using
(rgb-new 255 0 0), we can substitute a procedure
that computes colors based on the position. Try doing so.
Explorations
Choose any, all, or none of these explorations.
Exploration 1: Simulating Depth
As Professor Kluber suggested when he visited, one way we can simulate depth
in an image is by overlaying one thing over another.
a. Create an image you find aesthetically pleasing by overlaying fixed-color
rectangles on top of each other.
b. Create an image you find aesthetically pleasing by overlaying
computed-color rectangles on top of each other.
Exploration 2: Complex Color Computations Continued
In one of the exercises in this lab, you used trigonometric functions to
compute color values. Clearly, we can use these functions, and others,
in a variety of ways. For example, we need not linearly scale the row
and column, or can scale them in a way to get different ranges. Similarly,
we can choose functions other than sin to compute results.
In the end, all that we care is that we end up with each component value
in the range 0 .. 255.
Experiment with a variety of functions and multipliers to find a combination
that you find pleasing.
For example, consider the original computation of the green component
(* 128 (+ 1 (sin (* pi 0.025 col))))
We might replace the 0.25 with another number. We might
replace the sin with cos. We might
cube the result of that multiplication with
(expt (* 0.025 col 3)
We might even square the result of the sine computation.
Exploration 3: Fun with Kittens
a. Make your own copy of the kitten image. We'd suggest that you save it as
/home/username/Desktop/kitten.png.
b. Load, name, and show that image.
(define kitten
(image-show (image-load "/home/username/Desktop/kitten.png")))
c. Verify that the code for adding a screen works as advertised.
d. Try adding different screens to the image. You might try different
colors, color blends rather than fixed colors, different formulae for
deciding whether or not to draw the screen color, or whatever.