Lab: Local Operators

CSC 262 - Computer Vision - Weinman



Summary:
We explore local pixel operations including gamma, bias, and gain adjustments along with the more interesting histogram equalization.

Deliverables

Note: You may wish to use subplot to include several images in one figure box (i.e., the gamma-, bias-, and gain-adjusted images) for ease of comparision. For example, see Figure 3.2 (p. 110) of Szeliski.

Extra

Preparation

Exercises

A. Pixel Transforms

This first portion of the lab will call on you to make some basic observations; try not to spend too much time on them just now. You will want to make sure you have plenty of class time to work through the remaining technical material. Once you have all the technical aspects done, you can further explore values and their effects and reflect on the results for your analysis.
  1. Matlab has a default search path for some demo images. One of these is the cameraman.tif. Load this image using imread.
  2. The image is currently in an 8-bit format (values 0-255), which we'll need for later. However, we'll also need a double version. Create a copy that has double values in 0-1. (You learned how to do this in earlier labs.)
  3. Create a version of this image (using the double representation) that uses the gamma correction suggested by Equation (3.7) in Szeliski and his suggested value for gamma, 2.2.
    Recall that you must prepend a "." to explictly vectorize an operator (such as exponentiation) so that you don't get a matrix operator (such as matrix exponentiation).
  4. Display and inspect this image. What differences do you notice, if any?
  5. Equation (3.3) in Szeliski suggests a contrast and brightness adjustment via a linear transformation. Create a version of the cameraman image with a bias adjustment to visibly increase the brightness.
  6. Display and inspect this image. What (non-obvious) differences do you notice, if any? (E.g., don't just say "the image is brighter")
  7. Create a version of the cameraman image with a gain adjustment only (no bias) to visibly increase the contrast.
  8. Display and inspect this image. What non-obvious differences do you notice, if any?

B. Computing Histograms

  1. Matlab has a built-in function for helping to visualize histograms of images called imhist. Use this to display a histogram of the original (8-bit) cameraman image.
  2. More often we will be creating histograms of quantities besides raw images, so it is useful to know about the more general hist function for creating histograms. Use this to display a histogram of the image. For example,
    hist(X(:));
    Note that hist requires a vector; we can convert our image to a vector to using the (:) indexing notation. Also, some versions of Matlab don't like to use uint8 variables in hist, so you may need to convert the vector to a double, but keeping the values in the 0-255 range, as in
    hist(double(X(:)));
    Note: You should ignore Matlab's recommendation to use the histogram command; its interface is strictly less useful for the ease of our purposes.
  3. How many bins are used? Where (roughly) are they located?
  4. If you pass a second vector argument to hist, it will use the values in the vector as the histogram bin centers. Because the 8-bit image contains numbers 0-255, it is natural to use these as our bin centers. Create a histogram with the integers 0-255 as the bin locations. This should look similar to the histogram created in 1, except it does not show you the brightness along the bottom, only the brightness value (e.g numbers), because the result is a simple bar chart.
  5. What if you want to save these values (counts) for processing? Assign the result to a variable!
    Xhist = hist(...
    Save the histogram using 0-255 as the bins in a variable.
  6. The command bar(X,Y) graphs a bar chart of the values in the vector Y at the locations in the vector X (in the usual x vs. y fashion). Use this to generate your own graph of the histogram you just saved.
  7. Finally, use xlabel and ylabel to give appropriate titles to the axes; use title to label the graph.
  8. What brightness levels in the histogram appear to have the most pixels? Where do you expect to see the most detail emerge from the equalization enhancement?

C. Image Mapping

While adjusting the gain of an image increases the contrast, it may not necessarily allow us to see the most detail present in an image. Spreading out the brightness values so that they are used uniformly is often a useful of way doing this. First, we need to figure out how to "map" one brightness value to another.
  1. Use the following commands to create a faint image of a square with a hole in it.
    squareImg = zeros(128,'uint8');  % Black background
    squareImg(32:96,32:96) = 2;      % Square
    squareImg(48:80,48:80) = 1;      % Hole 
  2. Use imshow to display the image. It should be hard, if not impossible to see the three levels since they are all very close (0,1 and 2 on a 0-256 scale).
  3. These pixel values can be used as indices into another array. Use the following to create the 3-element brightness map
    map = uint8([0 ; 128 ; 255]);
    Notice how we have explicitly made these values 8-bit, so that imshow interprets them correctly.
  4. Recall that nearly anything can be used as an index to an array, even another vector or a matrix. Thus, we can use squareImg as the index into the array map. What will be the result of the following expression?
    squareImgTform = map(squareImg);
    Verify your answer. (You probably didn't get what you expect; if not, read on!)
  5. There is one caveat: the values in squareImg are 0, 1, and 2, while the valid indices of map should be 1, 2, and 3. Thus, we would need to add 1 to squareImg in order to index properly (that is, without getting an error). What should the following produce?
    squareImgTform = map(int16(squareImg)+1);
    Display the result. Does it look as you expect?
    Note: We need to convert squareImg to a wider integer type so we can add one (to serve as an index to map) without being clipped at 255.
  6. Experiment with a different set of values for map and construct a new image. Make sure you understand what is happening before proceeding.

D. Histogram Equalization

Figure 3.7(b) in Szeliski (p. 116) displays the histogram of each color channel. The plot in (c) contains the cumulative distribution function (or CDF), which is just the sum of all the values to the left of each point in the histogram. Thus, you see the blue curve ramp up very quickly because there are many values in the histogram to the left. As we move right (increasing in brightness) there are very few entries in the histogram. The CDF thus increases slowly because there is not very much to add. Our end goal is to use the CDF function to transform the histogram so that it is flat (yielding a CDF that is a diagonal, straight-line ramp).
  1. You can calculate the cumulative sum of the elements in a vector (as described above) using the function cumsum. Use this to create the cumulative distribution function (CDF) from your histogram counts.
  2. Plot the cumulative distribution function using the plot(X,Y) command. (Don't forget to specify the correct x-coordinates.) (Don't forget to label your axes!)
  3. What brightness range(s) have a steep slope? Diagonal slope? Nearly horizontal slope? How do these CDF regions match the histogram shape? What effect will they have on the image when the CDF is used as a transfer function?
  4. Next, we need to transform the cumulative distribution function into a proper mapping. That is, the entries should be brightness values in the range 0-255. What is the smallest value in your cumulative distribution function? What is the largest value?
  5. Create a scaled version of your cumulative distribution function so that the smallest value is zero but the largest value is 255 (the maximum brightness).
  6. Your scaled cumulative distribution function is likely a double (confirm this). Because we want to use this scaled version as a map like we did in Part C, we will need to cast these values using the conversion function uint8. Do this to your new map.
  7. With the same technique you learned in part C, use the original (8-bit) image as an index into your map (the scaled, 8-bit cumulative distribution function). The result should be an image that has undergone histogram equalization.
  8. Display and inspect your image. What new things do you notice, if any?
  9. Display and inspect the histogram of your new image. Does it have the properties you expect?

Extra Credit: Blending Maps

  1. Szeliski suggests that the result can be "flat" or "muddy" and suggests creating a linear blend between the cumulative distribution function and the identity transform (a straight line). Create a map that is the identity transform.
  2. Create a new transform function (map) that is the weighted average of your original map and your identity map (say, with an alpha of 0.75).
  3. Plot the original map and your blended map on the same axes (use hold on between plot commands). The following example demonstrates one way to change the color and line style of a plot
    plot(X,Y,'k--');
    In this case, the last argument indicates to use a black dashed line. You may examine other options by reading the help for the plot command.
  4. Display your plot. How do the two maps compare?
  5. Display and inspect the image using this blended map. How does it compare to the first equalized image? The original image?

Acknowledgments

The cameraman image is owned by MIT and licensed for use in Matlab demos by the Mathworks. There is an interesting lengthy history and layering of Matlab's default images.
Copyright © 2010, 2012, 2015, 2019, 2020, 2022 Jerod Weinman.
ccbyncsa.png