CSC 370

Grayscale & Color Image Processing

 

This assignment has three parts: photo enhancement, chroma-keying, and image convolution. Do at least one of the first two sections, plus the third.

Photo Enhancement

You already saw some simple ways to process grayscale images in previous assignments: lightening and darkening in HSV color space. These apply relatively crude operations that shift the shades in an image according to mathematical functions. You'll now get to experiment with histogram equalization, which takes into account the image itself when determining how things should be shifted.

Matlab has several functions for computing and working with histograms. First of all, hist (and the related histc) can be used to display the histogram of an image, or to return the histogram values in a vector. (To display that vector as a histogram, use bar.) For example, the following code applied to the image at right produces the histogram graph shown below. The shades are fairly well spread throughout the full range from black to white. The dark leaves in the foreground are responsible for the peak near zero, while the light sky and gables are responsible for the peak near one.

>> img = imread('ggarden.jpg');
>> img = double(img)/255;  % convert from uint8.
>> hist(img(:),256)

For image restoration, the histeq function performs histogram equalization. It only works on gray images (or single color planes). It can match any desired histogram profile, if the desired profile is provided as a second argument. (By default, if no second argument appears, it will match a uniform profile.) Histogram equalization can improve image quality in ways that seem almost magic, but it doesn't work with every image.

To Do: Apply histogram equalization to the three images below. The first (lincoln.jpg) is a daguerreotype (old photographic process) of Abraham Lincoln, the second (badexposure.jpg) was taken of a backlit building, resulting in contrast problems, and the third (wrenches.jpg) contains a mostly uniform background. Print out copies of the original and equalized image. (You may use the subplot function to fit more than one image in a figure window, then use the file menu in the figure window to print. Or save the figure as an image and paste it into a word processor.) When you are done, write a short explanation about why equalization affects each image the way it does. You may want to refer to the histogram of the original image in your explanation.

Note that histogram equalization applies to grayscale images, but the second image is RGB. You could convert it to grayscale, but that would lose the color information. The proper thing to do would be to convert to HSV, equalize the V channel, and then convert back to RGB. Also, the first image has more problems than poor equalization. You can remove some of the scratches by applying a median filter (medfilt2) before equalizing.

lincoln.jpg

badexposure.jpg

wrenches.jpg

Chroma-keying

Chroma-keying, also called blue-screening, is familiar mostly from TV weather forecasts. The weather forecaster stands in front of a blue screen, which allows his or her body to be plucked out of the image and placed infront of the weather map as a background. Although blue is the most common screen color, others may be used as well. (Blue was chosen because it is dissimilar from human skin and most clothing.)

You can use Matlab to do your own chroma-keying. The wrench image above will be used as a simple example. The following commands pluck the wrenches out of the image and place them on a new background (white in this case). The first step is to create a mask, a binary image that represents the boundaries/extent of some object or objects of interest. In doing so, the example below takes advantage of the fact that the wrenches are darker than the surrounding background. Note that the variable mask is an example of what's called a logical matrix in Matlab, because it results from a boolean operation. If you examine it closely, you will see that it consists of a matrix of boolean values, represented as zeros and ones. Logical matrices can be used in Matlab to pick out specific elements from another vector or matrix of the same size, as shown below. This is another way of selecting individual elements, more selectively than using colon notation.

>> img = imread('wrenches.jpg');  % read wrench image
>> img = double(img)/255;         % convert to double-precision format
>> mask = (img < 0.6);            % form mask
>> imshow(mask)                   % look at it
>> img2 = ones(size(img));        % make all-white image
>> img2(mask) = img(mask);        % copy wrench pixels only onto white image
>> imshow(img2)                   % look at result

If you look closely at the mask, you will see that it is imperfect, with a few pixel sized holes here and there in the middle of the wrenches. There's also a dark smudge that contaminates part of the background. These could be cleaned up using morphological operations -- imdilate, imerode, imopen, imclose, strel, and bwmorph are some of the relevant Matlab functions -- but we will not pursue that here.

To Do: Take the blue screen image of yourself, generate a mask that selects yourself out of the image, and then use that to place yourself artificially in another photo of some exotic locale (tropical beach, the moon, etc.). Turn in a print of the photo plus the code that produced it. (Grayscale print is fine.)

Some hints: The blue screen pixels will probably be easiest to identify in HSV color space, where they will have hue (first component) near .66 and high saturation (second component near 1). Pick appropriate cutoff thresholds to generate a good mask. You may find it useful to generate two masks, one based on hue and the other based upon saturation, and combine them using the & (and) or | (or) operators. When you have your mask, go back to RGB space and copy the masked pixels one plane at a time into the new image. You may have to adjust the image sizes to match; recall what we have learned about cropping and interpolation.

Convolution

Although Matlab has a function to do convolution (conv2), it is worth understanding exactly how it works. For this reason, you are asked in this assignment to implement your own function to do convolution, myconv2.m. You may use Matlab's other matrix-processing functions to simplify the implementation. Pseudo-code appears below, along with suggested Matlab functions:

  1. Determine dimensions nrow and ncol of image, and square radius r of kernel. (Use size.)
  2. Allocate space for output image. (Use zeros.)
  3. Double loop over all interior pixels. To avoid edge effects, you may skip a strip of width r around the edge of the image. Alternately, you may use padarray to expand the original image by r pixels on all sides, and keep track of the offset compared with the original image.
    1. Take the element-by-element product of the kernel with the portion of the input image defined by a square of radius r around the current pixel.
    2. Sum up these numbers and store them in the current pixel of the output image.

V. Here's a chance to try out a few more filters. You may use conv2 for this part. Compare the output of the following two filters on the boy.png image (don't forget to divide by the number shown):

1 6 15 20 15 6 1
6 36 90 120 90 36 6
15 90 225 300 225 90 15
20 120 300 400 300 120 20
15 90 225 300 225 90 15
6 36 90 120 90 36 6
1 6 15 20 15 6 1
/4096
1 2 1
2 4 2
1 2 1
/16
0 0 1
0 0 0
0 0 0

Finally, what do you think the filter at right will do? Try it out and see -- first pad the boy image with a margin of zeros using padarray (you should start with a grayscale image in img.) Now run it on the padded image 20 times in a row and then look at the result, using the 'same' option in conv2 to preserve the image size. (Take the output from one filtering and feed it into the next, as shown below.) Explain why it does what it does.

img2 = padarray(img,[25 25]);
for i = 1:20
    img2 = conv2(img2,filter3,'same');
    imshow(img2);
    drawnow;
end;