Fundamentals of Computer Science I: Media Computing (CS151.01 2008S)

Laboratory: Representing Images as Lists of Spots


Summary: In this laboratory, you will explore not only the basic list operations, but also some applications of those operations in working with images.

Preparation

a. Open two DrScheme windows, one that is blank (for the work today) and one with your library file (created in the first DrScheme lab). If you don't have a library file (typically named /home/username/Desktop/library.scm), create one.

b. Add the following procedures from the reading to your library window: spot-new, spot-col, spot-row, spot-color, spot-nudge-right, spot-nudge-up, image-render-spot!, and image-render-scaled-spot!.

c. Save your updated library.

d. Add the following as the first line of your work window.

(load "/home/username/Desktop/library.scm")

e. In the interactions pane of your work window, create a new 100x100 image and name it canvas.

Exercises

Exercise 1: Some Simple Lists

a. Call the cons procedure to build a list of the value "red". The result of your call should be ("red").

b. Call the cons procedure to build a list of the value 5 followed by the value "red". The result of your call should be (5 "red"). Note that you will need to call cons twice to build this list.

c. Call the cons procedure to build a list of the value 2, followed by the value 5, followed by "red". The result of your call should be (2 5 "red"). Note that you will need to call cons three times to build this list.

d. Build the same list as in step c, using list rather than cons.

Exercise 2: Extracting Information from Lists

Consider the following list definition, which you can enter in the interactions pane of your work window.

(define letters (list 'a 'b 'c 'd 'e 'f 'g 'h 'i))

a. What do you expect the result of (car letters) to be? Check your answer experimentally.

b. What do you expect the result of (cdr letters) to be? Check your answer experimentally.

c. What do you expect the result of (car (cdr letters)) to be? Check your answer experimentally.

d. What do you expect the result of (cdr (cdr letters)) to be? Check your answer experimentally.

e. What do you expect the result of (cdr (car letters)) to be? Check your answer experimentally.

f. Write an expression that gets the sixth element of letters. (That is, your expression should extract the f.)

Exercise 3: Other List Operations

a. Create the list ("red" "orange" "yellow") and name it roy. Create the list ("green" "blue") and name it gb.

b. Determine what happens when you reverse roy with (reverse roy).

c. Determine what happens when you append the two lists together with (append roy gb).

d. Determine what happens when you append the two lists together with (append gb roy).

Exercise 4: It's So cons-fusing

As you may recall, the cons procedure takes two parameters, a value and a list. It builds a new list by prepending the value to another list. However, it is also possible to apply cons to two non-list values. (You should not regularly do so at this point in your career, but some accidentally apply cons in this different way, so we want you to see what happens.)

Consider the following:

(define one-two (cons 1 2))
(define won-too (list 1 2))
(define want-to (cons 1 (cons 2 null)))

a. Enter these definitions in the interactions pane of your work window and then ask for the values of one-two, won-too, and want-to. Explain how they are and are not similar.

b. What do you expect to have happen when you apply the list? predicate to each. Check your answer experimentally.

c. What do you expect to have happen when you call reverse on each? Check your answer experimentally.

d. What do you expect to have happen if you try to get the car and the cdr of each of those values? Check your answer experimentally.

e. What do you expect to have happen if you append each of these list-like things to the list (3 4), as in the following example?

> (append one-two (list 3 4))
?
> (append won-too (list 3 4))
?
> (append want-to (list 3 4))
?

Check your answer experimentally.

f. What do you expect to have happen if you append the list (0 0) to each of these two lists, as in the following example?

> (append (list 0 0) one-two)
?
> (append (list 0 0) won-too)
?
> (append (list 0 0) want-to)
?

If you are confused by any of the results, please look at the notes on this problem.

Exercise 5: Playing with Spots

We claimed that the reading and the lab were about representing images as lists of spots. However, up to this point, we've just worked with lists. Let's consider some procedures that work with spots. As you may recall, we've decided to represent each spot as a three element list, where the first element is the column, the second the row, and the third the color.

a. Look at the definition of spot-new. What do you expect the output of the following command to be?

> (spot-new 10 10 "red")

b. Create a spot, named s1, that is at position (5,2) and is blue.

c. Look at the definition of spot-nudge-right. Then consider the following definition.

> (define s2 (spot-nudge-right s1))

What do you expect the value of s1 to be after that definition? What do you expect the value of s2 to be after that definition? Check your answers experimentally.

d. Look at the definition of spot-nudge-up. Then consider the following definition.

> (define s3 (spot-nudge-up (spot-nudge-right s1)))

What do you expect the value of s1 to be after that definition? What do you expect the value of s3 to be after that definition? Check your answers experimentally.

e. What do you expect the value of s4 to be after the following definition?

> (define s4 (spot-nudge-up (spot-nudge-up (spot-nudge-up s1))))

Check your answer experimentally.

Exercise 6: Nudging Spots

a. As you've just noticed, it is possible to nudge a spot so far up that its row becomes less than 0. At times, we might find such behavior inappropriate. Rewrite spot-nudge-up so that you cannot nudge a spot up higher than row 0.

Hint: Remember that we learned about bounding numbers in a previous lab.

b. Is it possible to make a similar change to spot-nudge-right? If so, summarize (in English) what that change would like like. If not, explain why not.

c. You may have noted that we seem to have failed to define spot-nudge-left and spot-nudge-down. Write them now.

Exercise 7: Rendering Spots

a. Consider the definition of image-render-spot!. Explain what the purpose of this procedure seems to be. (The purpose of a procedure explains what a procedure does, rather than how.)

b. What do you expect the result of the following commands to be?

> (image-render-spot! canvas s1)
> (context-update-displays!)

Check your answer experimentally. Note that you may have to zoom in to see.

c. Consider the definition of image-scaled-render-spot!. Explain what the purpose of this procedure seems to be. (The purpose of a procedure explains what a procedure does, rather than how.)

d. What do you expect the result of the following commands to be?

> (image-scaled-render-spot! canvas s1 10)
> (image-scaled-render-spot! canvas s1 20)
> (image-scaled-render-spot! canvas (spot-nudge-right s1) 20)
> (image-scaled-render-spot! canvas (spot-nudge-down s1) 20)
> (image-scaled-render-spot! canvas (spot-nudge-up (spot-nudge-up s1)) 20)

Check your answer experimentally.

Exercise 8: Flipping Spots

Consider the following procedure, which you should add to your library.

(define spot-flip
  (lambda (spot)
    (list (cadr spot) (car spot) (caddr spot))))

a. Determine what the procedure seems to do by creating a few spots and looking at the result of flipping those spots and/or by looking at what happens when you display spots and their flipped versions. For example,

> (define r1 (spot-new 10 1 "red"))
> (define b1 (spot-new 10 1 "blue"))
> (define r2 (spot-new 5 5 "red"))
> (define b2 (spot-new 5 5 "blue"))
> (define r3 (spot-new 6 17 "red"))
> (define b3 (spot-new 6 17 "blue"))
> (spot-flip b1)
> (spot-flip b2)
> (spot-flip b3)
> (image-render-scaled! canvas r1)
> (image-render-scaled! canvas (spot-flip b1))
> (image-render-scaled! canvas r2)
> (image-render-scaled! canvas (spot-flip b2))
> (image-render-scaled! canvas r3)
> (image-render-scaled! canvas (spot-flip b3))

b. As you've just determined, spot-flipflips” a spot along the diagonal where row equal column. That is, in fact, the intended purpose of this procedure. Critique its design. In what ways does it succeed and in what ways does it fail?

Exercise 9: Changing the Representation

We started by representing spots as lists of three items: row, column, and color. Upon further reflection, it might be better to group the row and column into their own sublist, which makes the output a little clearer.

(define spot-new
  (lambda (col row color)
    (list color (list col row))))
> (spot-new 4 2 "red")
("red" (4 2))

But is it safe to make this change? If we change the underlying representation, we need to change spot-col, spot-row, and spot-color

a. Rewrite those three functions to use the new representation. For example, spot-color should take the car of a spot, and spot-row should take the the car of the cadr.

b. Test your code by entering the following expressions and seeing if you get the same results.

> (define y1 (spot-new 1 2 "yellow"))
y1
> (spot-row y1)
2
> (spot-col y1)
1
> (spot-color y1)
"yellow"

c. What effect do you expect your changes to have on spot-nudge-up and spot-nudge-right?

d. Check your answers by entering the following

> (spot-col (spot-nudge-up y1))
2
> (spot-row (spot-nudge-up y1))
0
> (spot-color (spot-nudge-up y1))
"yellow"
> (spot-col (spot-nudge-right y1))
3
> (spot-row (spot-nudge-right y1))
1
> (spot-color (spot-nudge-right y1))
"yellow"

e. What effect do you expect your changes to have on image-render-spot! and image-scaled-render-spot!?

f. Check your answer experimentally.

g. What effect do you expect your changes to have on spot-flip?

h. Check your answer experimentally.

i. It is likely that you discovered that spot-flip no longer works. Rewrite it so that it not only works, but will survive a future change to representation.

For Those With Extra Time

Extra 1: Drawings, Revisited

You may have noted that almost all of the time we used the drawings-as-values model, we named the drawing we created. We can, of course, also look at those values. Consider the following:

> drawing-unit-circle
(drawing ellipse 255 "" -0.5 -0.5 1 1)
> drawing-unit-square
(drawing rectangle 255 "" -0.5 -0.5 1 1)
> (drawing-hscale (drawing-vscale drawing-unit-circle 10) 20)
(drawing ellipse 255 "" -10 -5 20 10)
> (drawing-outline (drawing-scale drawing-unit-square 100) "Circle (09)")
(drawing rectangle 255 "Circle (09)" -50 -50 100 100)
> (drawing-recolor drawing-unit-circle "red")
(drawing ellipse -16776961 "" -0.5 -0.5 1 1)
> (drawing-recolor drawing-unit-circle "yellow")
(drawing ellipse -65281 "" -0.5 -0.5 1 1)

As this example suggests, drawings are currently represented as eight element lists. The first element is always the symbol drawing. The second element is either the symbol ellipse or the symbol rectangle. The third element is some strange number that seems to correspond to the color. We can safely assume that 255 represents the color black. The fourth is a string that represents the brush. (When it's an empty string, we seem to get a filled drawing.) The sixth is the left edge, the sixth is the top edge, the seventh is the width, and the eighth is the height.

As you discovered earlier, it's dangerous to rely on the internal representation when you write procedures. However, let's suppose for the moment that you were willing to do so.

Write and test a procedure, (drawing-make-ellipse left top width height), that creates a new, filled, black ellipse with the specified edges and size.

Notes

Notes on Exercise 4: It's So cons-fusing

As you might guess, won-two is the list (1 2). As you might not have guessed, one-two is the value (1 . 2). That value looks much like a list, but it has a period in the middle. The period is a signal to you that the value is not a list. Since one-two is not a list, it is not possible to reverse it or to append it to another list. However, like the typical implementation of cons, the typical implementation of append does not confirm that its second parameter is a list. And, like cons, when given a non-list as a second parameter, append returns a non-list. In this case, append returns (0 0 1 . 2). Once again, the period indicates “hey, that's not a list”. Why does Scheme permit these non-lists? Because they are a generalization of lists (or at least of the techniques by which we process lists). As we'll see later in the semester, these non-lists can be quite useful.

Creative Commons License

Samuel A. Rebelsky, rebelsky@grinnell.edu

Copyright (c) 2007-8 Janet Davis, Matthew Kluber, and Samuel A. Rebelsky. (Selected materials copyright by John David Stone and Henry Walker and used by permission.)

This material is based upon work partially supported by the National Science Foundation under Grant No. CCLI-0633090. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation.

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