Lab: Local Operators
CSC 295 - Computer Vision - Weinman
- Summary:
- We explore local pixel operations including gamma, bias,
and gain adjustments along with the more interesting histogram equalization.
- Due:
- Monday 2/08
Deliverables
- Script containing the commands used to process the images and generate
the figures in your report as a single .m file.
- (5 points) Gamma corrected image and observations from A.4
- (10 points) Bias altered image, bias amount, and observations from
A.6
- (10 points) Gain altered image, gain amount, and observations from
A.8
- (10 points) Histogram from B.7
- (10 points) Observations from B.8
- (10 points) Plot of cumulative distribution function, D.3
- (10 points) Histogram-equalized image, D.8
- (10 points) Histogram and observations from D.9
- (15 points) Professionalism of write-up
Note: You may wish to include several images in one figure box (i.e.,
the gamma, bias, and gain adjusted images) for both compactness and
ease of comparision. For example, see Figure 3.1 (p. 102) of Szeliski.
Extra
- (5 points) Plot of equalizing and linear transforms, Extra 4
- (5 points) Partially equalized image, Extra 5
Preparation
- Make sure you have understood the first part of Szeliski Section 3.1.4
"Histogram equalization"
Exercises
A. Pixel Transforms
While this first portion of the lab will call on you to make some
observations, you should 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.
- Matlab has a default search path for some demo images. One of these
is the cameraman.tif. Load this image using imread.
- 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 the Matlab exercises.)
- 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). For instance A*B
will multiply matrices A and B if it is appropriate
to do so, while A.*B will multiply the corresponding entries
in A and B.)
-
Display, inspect, and save this image. What differences
do you notice, if any?
- 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 noticeably increase the brightness.
-
Display, inspect, and save this image. What
(non-obvious) differences do you notice, if any? (E.g., don't just
say "the image is brighter")
- Create a version of the cameraman image with a gain adjustment
to noticeably increase the contrast.
-
Display, inspect, and save this image. What
non-obvious differences do you notice, if any?
B. Computing Histograms
-
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.
- 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, which we can convert our
image 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(:)));
- How many bins are used? Where (roughly) are they located?
- If you pass a second vector argument to hist, it will use
the values in the vector as the histogram bin centers. Since 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), since the result is a simple
bar chart.
- What if you want to save these values (counts, actually) for processing?
You can assign the result to a variable
-
Xhist = hist(...
Save the histogram using 0-255 as the bins in a variable.
- 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.
-
Use xlabel and ylabel to give
appropriate titles to the axes and save this plot using the print
command you learned in the previous lab.
-
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.
- Use the following commands to create a faint image of a square with
a hole in it.
-
S = zeros(128,'uint8'); % Black background
S(32:96,32:96) = 2; % Square
S(48:80,48:80) = 1; % Hole
- 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).
- 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. This will be
so that imshow interprets them correctly.
- Recall that nearly anything can be used as an index to an array, even
another vector or a matrix. Thus, we can use S as the index
into the array map. What will be the result of the following
expression?
-
S2 = map(S);
Verify your answer.
- There is one caveat: the values in S 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 S in order to index properly (that is, without
getting an error). What should the following produce?
-
S2 = map(double(S)+1);
Display the result. Does it look as you appear? Note that we need
to cast S to a double (which is different from converting
an image using im2double) so that values don't get clipped
at 255.
- 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. 111) displays the histogram of each
color channel. The plot in (c) contains the cumulative distribution
function, 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 cumulative distribution function thus increases
slowly because there is not very much to add. Our end goal is to use
this function to transform the histogram so that it is flat (given
a cumulative distribution function that is a straight line ramp).
- 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 from your histogram counts.
- Plot the cumulative distribution function using the plot(X,Y)
command. (Don't forget to specify the correct x-coordinates.)
-
Save this plot using the print command.
(Don't forget to label your axes!)
- 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?
- 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).
- Your scaled cumulative distribution function is likely a double
(confirm this). Since we want to use this scaled version as a map
like we did in Part C, we will need to cast these values using uint8.
Do this to your new map.
- 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.
-
Display, inspect, and save your image. What
new things do you notice, if any?
-
Display, inspect, and save the histogram of
your new image. Does it have the properties you expect?
Extra Credit: Blending Maps
- 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.
- 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).
- 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.
-
Save your plot. How do the two maps
compare?
-
Display, inspect, and save the image
using this blended map. How does it compare to the first equalized
image? The original image?
Copyright © 2010 Jerod
Weinman.
This work is licensed under a Creative
Commons Attribution-Noncommercial-Share Alike 3.0 United States License.