Project 2: Fun with Filters and Frequencies - Joe Zou

Lots of fun having in this project!

Part 1: Fun with Filters

Part 1.1: Finite Difference Operator

In order to compute the partial derivatives in x and y, we can convolve the image with the humble finite difference operators Dx,Dy\bold{D_x},\bold{D_y} such that

Dx=[11],Dy=[11]\bold{D_x}=\begin{bmatrix}1&-1\end{bmatrix}, \bold{D_y}=\begin{bmatrix}1\\-1\end{bmatrix}

Next, we can combine these partial derivatives to compute the gradient magnitude image through the equation

gradient=(dx)2+(dy)2\bold{gradient} = \sqrt{(dx)^2+(dy)^2}

Finally, we can obtain an edge image by applying a minimum threshold to the gradient such that noisy edges are removed.

In this part, I calculate the partial derivatives, gradient magnitude image, and edge image through the methods described above.

original cameraman image
dx_gradient
edge_image

dy_gradient
combined_gradient

Part 1.2: Derivative of Gaussian (DoG) Filter

In this subpart, I apply the method described in Part 1.1 on a blurred version of the original image to obtain a gradient and edge image with less noise using two methods:

Method 1: Blur Image first

This is the naive method where we first blur the image with a gaussian kernel, then apply the operation described in Part 1.1 to obtain the results:

blurred cameraman (gaussian_kernel_size = 11)

dx_gradient of blurred image
edge_image of blurred image
dy_gradient of blurred image
gradient of blurred image

Comparing the edge_image of the original vs blurred images, we can see that the edge_image with blurring has less jagged edges and noise - best demonstrated by comparing the leftmost camera legs.

Method 2: Combine kernels first

In the second method, we first convolve the gaussian kernel with the finite difference operators, and then convolve the resulting kernel for each direction with the original image.

d_x_blur
dx_gradient using method 2
edge_image using method 2
d_y_blur
dy_gradient using method 2
gradient using method 2

A visual inspection comparing the gradients of method 1 and method 2 show no noticeable differences which is expected.

Part 2: Fun with Frequencies

Part 2.1: Image "Sharpening"

We know that blurring an image with a gaussian kernel will give us the low frequencies of the image. Now, if we subtract the blurred image from the original image, we can obtain an image of the high frequencies in the image. In this part, we will obtain the high frequencies of the image and increase them by a multiplier α\alpha to make images appear "sharper". These operations can be combined into a single convolution called the unsharp mask filter: f((1α)eαg)f*((1-\alpha)e-\alpha g), where ff is the image, ee is the unit impulse kernel(kernel of 0s with 1 in the center), gg is a gaussian kernel, and α\alpha is the sharpen amount.

In this part, I apply the unsharp mask filter on some images. Here are some results:

Taj

original taj image

blurred taj image
high frequencies of taj image
sharpened taj image

Badluckbrian

original badluckbrian
sharpened badluckbrian

Finally to evaluate this method of sharpening images, I have blurred an image of the campanile and will try to sharpen it again using the unsharp mask filter.

original campanile
blurred campanile
high frequencies of blurred campanile
sharpened result of blurred campanile

From the sharpened result of the blurred image, we can see that the result is now closer to the original campanile picture than the blurred version which is expected. The result isn't completely like the original however, as a visual comparison reveals that the sharpened result still appears a little blurry.

Part 2.2: Hybrid Images

Applying a gaussian kernel to blur an image acts like a low-pass filter on the image. Knowing this, we can also subtract an image by its blurred result to obtain an operation like a high-pass filter. In this section, I combine the low-frequencies of one image with the high-frequencies of another to form hybrid images that change in interpretation based on the viewer's distance. Specifically, these images will appear like one thing up close and something different from a distance. Here are some hybrid images I've generated:

Messi Goat

messi

Meme Galore

goat
goat + messi
troll
badluckbrian
meme galore

Coolcat Lion

coolcat
lion
lion + coolcat

Fourier Transform Analysis for "Coolcat Lion"

We can gain some insight into the process of generating hybrid images using visualizations of the Fourier transforms. Here are the log magnitude plots of the Fourier transforms. We can see that the low frequencies are removed for the high pass transform and high frequencies are removed for the low pass transform.

original coolcat
high pass coolcat
original lion
low pass lion
hybrid image

Bells & Whistles for Part 2.2: I incorporated color in both the high-frequency and low-frequency components. I think overall the hybrid images look best when the low-frequency component has color and the high frequency one doesn't.

Part 2.3: Gaussian and Laplacian Stacks

A gaussian stack of height nn is a stack of images where every layer is obtained by applying a gaussian filter to the previous layer - with layer 0 being the original image. After constructing a gaussian stack, we can also construct a laplacian stack where LiL_i is layer ii of the laplacian stack and GiG_i is layer ii of the gaussian stack:

Li={GiGi+1, if i<n,Gi, if =nL_i = \begin{cases}G_i - G_{i+1}, \text{ if } i<n,\\G_i,\text{ if =n}\end{cases}

I generated gaussian and laplacian stacks with n=5n=5 for the oraple and then applied a gaussian stack of masks to create two sets of masked gaussian and laplacian stacks.

original oraple image

Oraple Gaussian Stacks

apple layer 0
apple layer 3
apple layer 5
orange layer 0
orange layer 3
orange layer 5
oraple layer 0
oraple layer 3
oraple layer 5

Oraple Laplacian Stacks

apple layer 0
apple layer 3
apple layer 5
orange layer 0
orange layer 3
orange layer 5
oraple layer 0
oraple layer 3
oraple layer 5

Part 2.4: Multiresolution Blending

In this section, I combine two laplacian stacks of different images with inverse masks to create hybrid images. I used photoshop to create the masks and align the images in order to create better looking results. Here are some example results:

Apple + Orange = Oraple

apple
orange
oraple mask
oraple

Tank + Truck = Trank?

tank
truck
trank mask
trank result

Night + Sun = A sunny night

night
sun

irregular mask
A sunny night

Detailed Gaussian + Laplacian Stack for "A sunny night"

Here is a detailed breakdown of the gaussian and laplacian stacks that are used to create one of my example results.

night gaussian layer 0
night gaussian layer 3
night gaussian layer 5
night laplacian layer 0
night laplacian layer 3
night laplacian layer 5
sun gaussian layer 0
sun gaussian layer 3
sun gaussian layer 5
sun laplacian layer 0
sun laplacian layer 3
sun laplacian layer 5

Bells & Whistles for Part 2.4: I also implemented the second part of the project with color. I think this turned out really well and looks especially good for the "A sunny night" example.

What I learned

How to do all of the methods described above as I didn't know how to do most of this stuff. More specifically, I think part 2 was especially interesting as it showed me how to think about images in terms of it's representation in the frequency domain.

I also learned about some weird interactions between using cv2.imread vs plt.imread and skio.imsave as cv2.imread ended up storing the channels in reverse order, so I had to perform an additional np.flip operation in my main.py file for part2.2(I spent 30 minutes debugging this).