Lab: Edge Detection

CSC 262 - Computer Vision - Weinman



Summary:
We calculate image gradients to find edges at multiple scales, strengths, and orientations.

Deliverables

Extra

Note that to receive the full value of extra credit, your report must provide appropriate narrative context for the images you produce.

Preparation

Load the following file from the MathLAN and convert it from 8-bit to double values:
/home/weinman/courses/CSC262/images/bug.png

Exercises

A. Gradient Components

  1. Create a 1-D Gaussian kernel with variance 4 using gkern.
    gauss = gkern(4);
  2. We can also create a 1-D first derivative of Gaussian kernel with variance 4 by giving another argument to gkern that specifies how many times we want to take the derivative:
    dgauss = gkern(4,1);
    (For completeness, you could have given the argument 0 in the previous exercise to indicate taking the derivative zero times.)
  3. Recall that conv2 accepts two separable kernels for filtering: one to operate along rows and the other to operate along columns. Use your two Gaussian kernels to calculate the partial derivative of the bug image along the rows (that is, the horizontal partial derivative). Have it return an answer only for the valid portions of the convolution (the last parameter should be 'valid' rather than 'same'); this will avoid spurious effects at the image boundaries for the time being.
  4. Display your result as an image, remembering that the partial derivative may be positive or negative. Thus, you will need to tell imshow to relax its displaying conventions.
  5. Interpret your result. Where is it bright? Where is it dark? Where is it gray? In all three cases: why?
  6. Calculate the partial derivative of the image along the columns in a similar fashion. Display your result.
  7. Inspect your result, making similar observations as in A.5.

B. Gradient Magnitude

  1. Create an image representing the magnitude of the gradient at each pixel location. (Recall that the magnitude of a vector is the square root of the sum of the squares of its components.)
  2. Display and inspect your image. Where are the strongest responses? How do they correspond to the values of the partial derivatives?
  3. It is typical to place a threshold on the gradient magnitude so that the edge detection result is binary. Use a vectorized "greater than" operation on the gradient magnitude and display your thresholded image.
    You may wish to start with a threshold of 0.02 and adjust it to find what you think is a good threshold for a nice edge image.

C. Gradient Orientation

  1. As we discussed in class, use atan2 to create an image representing the orientation/direction of the gradient at each pixel location.
  2. Recall that the gradient orientation may be in the range [−pi,pi]. We can tell imshow to treat these as its bounds for display (black to white) explicitly, i.e.,
    imshow(X,[-pi pi]);
    Display your orientation image in this fashion.
  3. Black and white values are not very intuitive for interpreting orientation. Fortunately, Matlab has a built-in way of changing the way actual image values are mapped to display values. Much like you've done before manually, you can explicitly change the map using the command colormap with a map argument. The procedure hsv creates a circular color map that is useful for such visualizations. Apply this to your figure:1
    colormap(hsv); % Change the map of the 
                   % current figure to "hsv"
    colorbar;      % Add a color bar to the figure 
                   % to aid interpretation
  4. Spend some time analyzing the orientations. Where do the colors indicate the gradient points horizontally? "Diagonally?" Vertically? Be sure to distinguish direction (i.e., left versus right.) Do these reconcile with the image contents?

D. Gradient Orientation Revisited

Having the orientation displayed as a bright color where there is no strong edge is rather misleading. Instead, we'd like to be able to display no colors where there is no edge, and have the colors on the strong gradients indicate the orientation, as in Part C. We can do this by using an alternative color representation. Instead of thinking about the color contributions of red, green, and blue, components (the RGB color model), we can separate the color into three different components
Hue:
the pure chroma
Saturation:
the amount of color present
Value:
the perceived brightness
Like RGB, we can model HSV colors with three components, each in the range 0-1. Matlab knows how to convert an image in HSV colorspace into an RGB for display. We will use this to encode our orientation image in a more meaningful fashion.
Color will still be used to encode orientation, but we will use the saturation channel to encode the strength of the edge at each location. Thus, if there is no edge, there will be no saturation and thus no color. We can keep the value at a constant brightness, perhaps white.
  1. To represent the hue, rescale your previous orientation image so that instead of the range [−pi,pi] it has the range [0,1].
    Hint: To rescale a quantity x from [a,b] to [0,1], something you will do quite often, you can use the transform
    xrescale=(xa)/(ba).
  2. To represent the saturation, create a rescaled version of the gradient magnitude image so that the maximum value in the rescaled version is 1. Hint: Here we can simply divide by the largest value.
  3. To represent the value, create an image of all ones the same size as your other images.
  4. To create the final HSV image, concatenate these M×N matrices along the third dimension into one M×N×3 image using the cat procedure, i.e.,
    W = cat(3,X,Y,Z);
  5. Convert your new HSV image to an RGB image using hsv2rgb, i.e.,
    B = hsv2rgb(A);
  6. Display the result in a new figure and confirm that it is bright where there are edges, and the color matches the orientation. (Note: You cannot use colorbar and/or colormap with this image because it is not a single channel.)

E. Edge Detection and Scale

Now that you have analyzed all the parts, we want to investigate how detecting edges depends on the scale (i.e., Gaussian standard deviation) used to calculate the gradients.
  1. Place your commands for creating the gaussian kernels, partial derivatives, gradient magnitude, and weighted orientation (the RGB version from D.5) inside a for loop that calculates these for the following Gaussian variances: 1, 2, 4, 16, and 32. Store the scaled gradient magnitude (D.2) and weighted orientation images (D.5) each in a M×N×1×K and M×N×3×K array, respectively.
    Since the results for each variance are progressively smaller (as variance increases, the kernel size does as well leaving less valid output), place the result in the upper-left corner of the output array.
  2. The command
    montage(I,'Size',[nRows nCols]);
    displays an M×N×D×K image array I as a tight set of K < nRows*nCols images in a figure window. Using this command, visualize your gradient magnitude and weighted orientation images. (See doc montage for more details and display options.)
  3. We also need to threshold our edges so that we have binary detections. Inside your loop, add for loop over several scaled gradient magnitude thresholds: [24/256], [32/256], [48/256], [64/256], [96/256]. Store the thresholded edge results in a M×N×T×K array.
  4. Outside the loops, use reshape to size your edge array to be M×N×1×S where S=T×K.
  5. Use montage to display the (binary) thresholded images in a T×K grid. Make sure you understand which axis (horizontal or vertical) is varying the threshold and which is varying the kernel size.

F. Analysis

There should not be any more Matlab work for you do. All that remains is some analysis of your results.
  1. How do the magnitude images change as the scale increases?
  2. How do the orientation images change as the scale increases?
  3. How do the detection images change with scale and threshold? Note: these are not independent; consider them together. What happens as each changes? (For example consider the four extrema along both axes.)

Extra Credit: Thinning Edges

  1. Szeliski suggests that the resulting edges can be thinned by finding the zero-crossing of the Laplacian, which is the sum of second derivatives in the x and y directions. Explain in your own words why this strategy works.
  2. Recalling that you can get an arbitrary Gaussian derivative with gkern,
    filter = gkern(scalederiv)
    calculate the Laplacian of the image at some appropriate scale.
  3. Find the zero crossings of the image Laplacian by generalizing the following 1-D zero-crossing strategy:
    Aneg = A<=0; % Non-positive elements
    Apos = A>0; % Positive elements
    Aneg2pos = [0 Aneg(1:end-1)] & Apos; % (Right-shift negative) & positive
    Apos2neg = Aneg & [0 Apos(1:end-1)]; % (Right-shift positive) & negative
    Azcross = or(Aneg2pos, Apos2neg); % Crossing in either direction
  4. Use a threshold on the gradient magnitude to create an additional mask for reducing the number of zero-crossings displayed to only those corresponding to the strongest edge locations. You may choose the threshold so that it generates an image of reasonable quality.
    (You can optionally compare the results of your work to the output of the built-in Matlab procedure edge).

Acknowledgments

The bug image was captured by Jerod Weinman (with much regret, in his garden) and is Copyright 2007, licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.
Copyright © 2010, 2012, 2015, 2019, 2020, 2022 Jerod Weinman.
ccbyncsa.png

Footnotes:

1And say hello to Wonderland.