Fundamentals of Computer Science I: Media Computing (CS151.02 2007F)

Anonymous Procedures and Fancier Filters

This reading is also available in PDF.

Summary: We examine how one writes procedures, particularly in the context of writing image filters. These procedures are anonymous in that we do not need to name them.

Contents:

Introduction

In the recent readings on transforming RGB colors and transforming images, you learned about some basic functions that transform colors and how to extend those functions to transform images. When use a function to transform a whole image, we call the process a filter for an image.

While the basic functions provide you with a wide variety of capabilities, they are still somewhat limited. For example, it is difficult or impossible to use them to convert an image to greyscale, to increment the red component by 21, and a huge variety of other things.

For such activities, we need to write our own filters. Writing those filters is the subject of this reading.

Computing New Colors

As you may recall, at the center of any filter (or at least any filter we've written so far) is a function that transforms one color to another. Let's think about how we might describe some of the color transformations we've learned so far.

If the original color, c, had been named with define, and our goal was simply to define a new name, newcolor, we could use the techniques that we've covered so far. In particular, when we say compute a new color we can use rgb.new and when we say the red component of c we can use (rgb.red c). Putting that together, we might write the following for rgb.complement.

(define c ...)
(define newcolor (rgb.new (- 255 (rgb.red c)) (- 255 (rgb.green c)) (- 255 (rgb.blue c))))

But that pair of defines aren't a function. That is, the defines do not constitute the kind of code that we can, for example, pass as a parameter to image.transform-pixel!, image.map!, or image.map. To write Scheme functions for each of these algorithms, we must also translate the a function that, given a color, c. In Scheme, you write that as

(lambda (c) ...)

For example, we could express the complement transformation as

(lambda (c) (rgb.new (- 255 (rgb.red c)) (- 255 (rgb.green c)) (- 255 (rgb.blue c))))

We can certainly use any name we want for the original color. For example, here's a definition of redder that uses nre (not red enough) as the name of that color.

(lambda (nre) (rgb.new (min 255 (+ 8 (rgb.red nre)) (rgb.green nre) (rgb.blue nre))))

Note that we have not given this version of the function a name. It is just a function that, when given a color, nre, computes a new color by adding eight to the red component and leaving the other two components unchanged. Since the function has no explicit name, we call it an anonymous function.

Making Filters with Anonymous Functions

Okay, what good are these anonymous functions? Well, we can use them in any procedure that expects another procedure as a parameter. In particular, we can use them with image.transform-pixel!, image.map!, and image.map. At present, we will use them most frequently with the mapping functions.

For example, here's a filter that sets the red component of every pixel in picture to 0.

(image.map! (lambda (c) (rgb.new 0 (rgb.green c) (rgb.blue c))) picture)

Similarly, here's a filter that sets the blue component to 0.

(image.map! (lambda (c) (rgb.new (rgb.red c) (rgb.green c) 0)) picture)

Here's a slightly more complex filter that sets the green component to the average of the green and blue components.

(imagemap! (lambda (c) (rgb.new (rgb.red c) (/ (+ (rbg.blue c) (rgb.green c)) 2) (rgb.blue c))) picture)

Functions Formalized

Okay, we've seen a bit about functions and how one might use them. What does the general case look like? In Scheme, we most typically specify a function by writing

That is, it looks like

(lambda (param0 param1 ... paramn) expression)

The expression can use any names given in the parameter list, as well as any other names known to Scheme, such as those given by previous define commands.

Although we have only written functions that transform colors (so far), in Scheme anything (more or less) can be a parameter to a function.

Detour: Why Lambda?

Using a Greek letter to mean function is a bit odd, but it's a tradition dating back to Alonzo Church, a mathematician who, in the early 20th century, studied how mathematicians think. (Church was also Rebelsky's great great grand-advisor.)

Anonymous No More: Naming Functions

Particularly when you use operations like image.map, which expect another function as a parameter, it is convenient to just plug in the description of a function when you want to do something. However, at other times, you will find it handy to name the functions you create. How do you name functions? The same way you name anything in Scheme, with define. For example, here's one of the sample color transformations, named appropriately.

(define no-red (lambda (c) (rgb.new 0 (rgb.blue c) (rgb.green c))))

We will return to the techniques and benefits of naming functions in a future reading and laboratory.

 

History

 

Disclaimer: I usually create these pages on the fly, which means that I rarely proofread them and they may contain bad grammar and incorrect details. It also means that I tend to update them regularly (see the history for more details). Feel free to contact me with any suggestions for changes.

This document was generated by Siteweaver on Mon Dec 3 09:53:18 2007.
The source to the document was last modified on Wed Sep 12 16:51:31 2007.
This document may be found at http://www.cs.grinnell.edu/~rebelsky/Courses/CS151/2007F/Readings/anonymous-procedure-reading.html.

You may wish to validate this document's HTML ; Valid CSS! ; Creative Commons License

Samuel A. Rebelsky, rebelsky@grinnell.edu

Copyright © 2007 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.