Computational Vision
U. Minn. Psy 5036

Assignment #2
Linear systems, neural systems & edge detection

Initialization

Off[General::spell1];
SetOptions[ArrayPlot,Mesh->False,AspectRatio->Automatic,PlotRange->All,ColorFunction->"GrayTones",DataReversed->True,ImageSize->Small];
SetOptions[ListPlot3D,Mesh->False,AspectRatio->Automatic,PlotRange->All];
(*Optional: Needs["LinearAlgebra`MatrixManipulation`"]*)

Goals: Learn: 
	1) how to use convolution for spatial filtering
	2) how to use the Fast Fourier Transform for spatial filtering
	3) how to extract edges from the outputs of model V1 simple cells

In Assignment 1 you learned how to model the performance of an ideal detector that had an exact template for a signal and which received images that were either noise or were signal plus noise. The noise pixel intensities were Gaussian, and the pixels intensities were picked independently of each other. Noise with independent pixel intensities is called "white noise".
The ideal observer takes the dot product of the input image with the template and uses this as a decision variable. This operation is used to model the rate of spike discharge of simple cell neurons in the mammalian visual cortex. The spike discharge rate would correspond to the decision variable.
In Assignment 2, you will build an edge detector based on a model of simple cells. You will use the dot product model of a linear visual neuron to spatially filter an input image. You will do this in two ways, and the results should be very similar: convolution, and through the Fast Fourier Transform. 
You will use the filtered images (one from the convolution method and one from the FFT method) to mark edges.

Your input image will look like this:

Your final product should mark the edges, and could look something like this:

ggrapes=Image[];

grapes = ImageData[ggrapes];
size=Dimensions[grapes][[1]]
hsize=size/2

Problems

Use convolution to apply a discrete (∇^2)G lateral inhibitory filter to grapes image; 2) locate zero crossings in filtered image

Problem 1: Make a low-pass Gaussian filter

Generate a size x size matrix that represents a 2D low-pass Gaussian filter with standard deviation that is two pixels wide. Put the peak at {hsize+1, hsize+1}. Call the array gaussfilter. You will use this in the FFT problem below. Use Image[] or ArrayPlot[] to show what gaussfilter looks like. It should look like:

Now extract a 13 x13 kernel from the middle (the central "bump").   Call this matrix gausskernel. You will use this in the convolution problem below. Use Image[] or ArrayPlot[] to show what gaussfilter looks like. It should look like:

Problem 2: Make a laplacian filter

Generate a size x size array  that represents a discrete Laplacian operator. Center the filter, so that -20 is at {33,33} (See hint below). Call the matrix laplacefilter. 
Big Hint: It is tricky to get a good approximation to a circularly symmetric operator on a discrete rectangular lattice. So I'll give you the specification: The center value should be -20, the left, right, above and below nearest neighbor values should be 4, and the diagonal elements should be 1.  Make sure that you define the matrix to be numerical (i.e. the numbers should be decimals, not integers).
Use Image[] or ArrayPlot[] to display laplacefilter. It should look like:

Extract the central 3 x 3 submatrix that represents a discrete Laplacian operator. Call it: laplacekernel. 
 (Consistent with the above hint, laplacekernel should be:{{1,4,1},{4,-20,4},{1,4,1}};
 Use Image[] or ArrayPlot[] to display laplacekernel. It should look like:

Problem 3: Make a  (∇^2)G operator

Use ListConvolve to make a (∇^2)G operator by convolving laplacekernel with gauskernel. Call the operator delsq. Display the result using Image[] or ArrayPlot[delsq]
Use the no overhang default for ListPlot and your resulting delsq should be an 11x11 matrix.

Problem 4: Use the (∇^2)G  operator in the space domain to the grapes image.

Use ListConvolve[] to produce a spatially filtered image of grapes. Call the array filteredgrapes. There are various ways of handling the overhang of the kernel with the image, such as by padding the original image. This time handle the overhang using cyclic convolution (see the documentation for ListConvolve). This will preserve the original size of the array. Adjust the third argument of ListConvolve to make sure that the resulting filtered image doesn't shift with respect to the original image. Use Image[filteredgrapes] or ArrayPlot[filteredgrapes] to show your results.

Problem 5: Find the edges by marking the zero-crossings

Generate an image where 1 marks the location of a zero-crossing in your filtered image of grapes, and has zeros everywhere else. There are a number of ways of doing this, devise one. 
Then superimpose the zerocrossings image on the original grapes image. For example, a simple way to superimpose them is:
                       ArrayPlot[zerocross + grapes]
Or use Image[]. But you might want to do something fancier. Your answer should look something like the plot shown at the top of this notebook.

Use the FFT to apply a discrete (∇^2)G lateral inhibitory filter to grapes image; 2) locate zero crossings in filtered image

Problem 6: Apply the (∇^2)G operator in the spatial frequency domain to the grapes image

Apply the (∇^2)G operator in the spatial frequency domain to the grapes image (also represented in the spatial frequency domain), and display the filtered result in the space domain.
You can do the filtering operation as follows: Multiply the Fourier transforms of the gaussian filter, the Laplacian operator filter, and the image. (Use Fourier[ ] to take the Fourier transforms of each 64x64 matrix, and multiply them together). Then you need InverseFourier[ ] to produce the filtered image in the space domain.
Use Chop[ ] on the final output of the inverse transform to make sure there aren't any tiny residual imaginary numbers. These can arise due to limits in numerical precision.
One can think of the resulting image as a "neural image" representing the outputs of an array of ganglion off-center cells. The displayed filtered image should look like the filtered image of grapes you produced in Problem 4.

Problem 7:  Find the edges by marking the zero-crossings (using the filtered image produced using the FFT method)

Apply your earlier zero-crossing detector to generate an image where 1 marks the location of a zero-crossing in your filtered image of grapes, and has zeros everywhere else. Then, as before, superimpose the zerocrossings image on the original grapes image. E.g.
                      Image[zerocross + grapes]
Again, make sure the edge map and the grapes image are in register.