Functional Problem Solving (CSC 151 2013F) : Labs
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] [FAQ] [IRC] [Teaching & Learning] [Grading]
Current: [Assignment] [EBoard] [Lab] [Outline] [Partners] [Reading]
Sections: [Assignments] [EBoards] [Examples] [Handouts] [Labs] [Outlines] [Partners] [Readings]
Reference: [Setup] - [Functions A-Z] [Functions By Topic] - [Racket] [Scheme Report (R5RS)] [R6RS] [TSPL4]
Related Courses: [Davis (2013F)] [Rebelsky (2010F)] [Weinman (2012F)]
Misc: [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] [Issue Tracker (Course)]
Summary: In this laboratory, you will explore techniques for building and modifying images by iterating over the positions in an image.
Reference:(image-compute
pos2color
width
height)
pos2color
(a function of the form (lambda (col row) color))
to compute the color at each position in the image. compute
As you learned in the reading, one of the simplest ways to use
is to create an image
of a uniform color. For example, we might make a small pink image with
image-compute
(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
with a negative
width or height?
image-compute
e. Check your answer experimentally.
f. What do you think will happen if you provide
with something other
than a function for the first parameter?
image-compute
g. Check your answer experimentally.
h. What do you think will happen if you provide
with a function
that returns a non-color?
image-compute
i. Check your answer experimentally.
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.
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:
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, ( that creates
a horiz-black-to-blue
width height)width-by-height image
with a horizontal blend from black to blue.
b. Write a procedure, ( that creates
a horiz-blue-to-black
width height)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, (
that creates
a horiz-blue-blend
width height
initial final)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.
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.
Consider the following instructions.
(define stripe-colors
(list (rgb-new 255 0 0)
(rgb-new 255 255 0)
(rgb-new 0 255 0)
(rgb-new 0 255 255)
(rgb-new 0 0 255)))
(image-compute
(lambda (pos) (list-ref stripe-colors (modulo (position-col pos) 5)))
100 100)
a. What do you expect these instructions to do?
b. Check your answer experimentally.
c. Extend that code to use seven colors instead of five. That is, you'll need to add two values to the list (presumably, by redefining the list) and use a different modulus.
d. As you should have observed, this makes a sequence of vertical
stripes, each of width one pixel. We can make the stripes wider
by computing the quotient of the column and the desired width.
Try expanding your columns to a width of 5 and then 10. (Note that in
order to use the result as a parameter to modulo
and then in list-ref, we need to guarantee
that it is an integer. Hence, you should compute the quotient with
quotient rather than /.
e. Predict the result of the following instructions, and then try executing them.
(define canvas (image-show (image-new 200 200)))
(region-compute-pixels!
canvas
100 0 100 100
(lambda (col row)
(list-ref stripe-colors (modulo (quotient col 10) 5))))
(region-compute-pixels!
canvas
0 100 100 100
(lambda (col row)
(list-ref stripe-colors (modulo (quotient row 10) 5))))
(region-compute-pixels!
canvas
100 100 100 100
(lambda (col row)
(list-ref stripe-colors
(modulo (quotient (+ row col) 10) 5))))
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.
You may find it appropriate to do an extra problem (which you can do in any order), an exploration, or any combination.
Consider the final image from exercise 5. Suppose we wanted to make a similar, but larger, version of the image. To do so, we'd certainly need to change the width and height of the image and the ending column and row.
Do we need to change the .025 and .020? We can,
but it depends on how we define “similar”.
If you change .025 and .020, you might scale
them similarly to how you scale the image. For example, if we double the
width and height of the image, we might write
(image-compute
(lambda (col row)
(rgb-new 0
(* 128 (+ 1 (sin (* pi 0.0125 col))))
(* 128 (+ 1 (sin (* pi 0.010 row))))))
80 100)
a. What do you expect to have happen if you use the preceding code to create a larger, similar, image?
b. Check your answer experimentally.
c. What do you expect to have happen if you restore the .025 and .020 to the preceding code and then rerun it?
d. Check your answer experimentally.
a. Generalize the circle drawing code from above to a procedure,
(
that creates a
red-circle image-width
image-height circle-radius
center-col circle-row)image-width-by-image-height
image consisting of a red circle of the specified radius, centered at
the specified position.
b. Clearly, we might want to add circles to existing images, and not
just compute new images that contain circles.
Write a procedure, (,
that draws a red circle of
radius draw-red-circle!
image
col
row
radius)radius
centered at (col,row).
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. (How do you overlay rectangle? You
use a cond to choose what rectangle to draw.)
b. Create an image you find aesthetically pleasing by overlaying computed-color rectangles on top of each other.
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.
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] [FAQ] [IRC] [Teaching & Learning] [Grading]
Current: [Assignment] [EBoard] [Lab] [Outline] [Partners] [Reading]
Sections: [Assignments] [EBoards] [Examples] [Handouts] [Labs] [Outlines] [Partners] [Readings]
Reference: [Setup] - [Functions A-Z] [Functions By Topic] - [Racket] [Scheme Report (R5RS)] [R6RS] [TSPL4]
Related Courses: [Davis (2013F)] [Rebelsky (2010F)] [Weinman (2012F)]
Misc: [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] [Issue Tracker (Course)]
Samuel A. Rebelsky, rebelsky@grinnell.edu
Copyright (c) 2007-2013 Janet Davis, Samuel A. Rebelsky, and Jerod Weinman. (Selected materials are copyright by John David Stone or Henry Walker and are used with permission.)

This work is licensed under a Creative Commons Attribution 3.0 Unported License. To view a copy of this
license, visit http://creativecommons.org/licenses/by-nc/3.0/
or send a letter to Creative Commons, 543 Howard Street, 5th Floor,
San Francisco, California, 94105, USA.