Skip to main content

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.

A darker version of the standard kitten image (image-variant kitten irgb-correct-2.2)

A lighter version of the standard kitten image (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.