Project 2: Fun with Filters and Frequencies!

Harish Palani (CS 194-26)

1 Fun with Filters!

1.1 Finite Difference Operator

Here, we apply the finite difference operator as our filter in both the x and y directions, using cameraman.png (shown below) for testing.

<matplotlib.image.AxesImage at 0x21e22a62190>

The specific filters are Dx = [1, -1] and Dy = [[1], [-1]] — these can subsequently be used to convolve the original image, yielding the derivatives with respect to x and y shown below.

Text(0.5, 1.0, 'Gradient (with respect to y)')

Armed with these gradients, I used the formula np.sqrt(np.square(np.abs(dx)) + np.square(np.abs(dy))) to calculate the gradient magnitude. This was then binarized to yield the edge image shown below on the right, with a threshold of 0.12 selected to minimize noise.

Text(0.5, 1.0, 'Binarized Gradient Magnitude (thresh = 0.12)')

1.2 Derivative of Gaussian Filter

Though the above results are strong, they remain a bit noisy, with the edges in the binarized image not quite as well-defined as they could be. The Gaussian filter can be used as smoothing operator to resolve this, convolving the blurred version of cameraman.png shown below instead of the original. This blurred version has noticeably less detail than the original image, allowing for smoother isolation of edges by reducing the adverse impact of noise.

<matplotlib.image.AxesImage at 0x21e2405ceb0>

This yields the following gradient outputs, shown below in the x and y directions for both the Gaussian filter as well as the Derivative of Gaussian (DoG) filter. Comparing the binarized gradient magnitudes for both with that resulting from the finite difference operator, it's clear that these have stronger performance.

Text(0.5, 1.0, 'Derivative of Gaussian Filter — y direction')

1.3 Image Straightening

Here, I leveraged the natural preference of aligned images for horizontal and vertical edges to automate image straightening, examining rotated images at each angle within a pre-determined window and selecting that which best maximizes the edge heuristic.





As seen above, the results are quite strong across most test images — it even managed to straighten out the Leaning Tower of Pisa!

The algorithm appears to struggle slightly with the welcome sign in mississippi.jpg, however, with the final image not rotated quite as far as expected. This can likely be attributed to either noise from the trees in the background or the size of the image itself — this file was considerably smaller than the other three images shown, meaning less pixels were available to inform the final alignment decision.

2 Fun with Frequencies!

2.1 Image Sharpening

Here, we use the Gaussian filter once again to add greater weight to edges in an already blurry image, yielding a sharpening effect. This can be seen in taj.jpg, whose features (shown below) are noticeably sharper post-processing.

Text(0.5, 1.0, 'The Sharper Image™')

The same effect is seen with nyc.jpg below, showing perhaps the world's most famous skyscraper. Here, a higher alpha value is used to add more weight to the edges and deliver a sharper image — necessary since the original Empire State Building image on the left is more blurry than the Taj Mahal original above.

Text(0.5, 1.0, 'The Sharper Image™')

2.2 Hybrid Images

The Gaussian filter is once again utilized for this part, forming the basis of both the low pass and high pass filters used to generate hybrid images. These hybrids are simply sums of the low and high frequency components of the two input images, respectively.

Text(0.5, 1.0, 'FFT — Hybrid Image')
Text(0.5, 1.0, 'Hybrid Image')

After cropping, here's what the final hybrid image looked like!

<matplotlib.image.AxesImage at 0x21e255b6fa0>

For some fun bells and whistles, I also added color to enhance the effect. Color yielded the greatest improvements when used for the low-frequency component, adding a lot of life to the resulting hybrid image.

Text(0.5, 1.0, 'Colorized Hybrid Image')

Here's what it looks like cropped!

<matplotlib.image.AxesImage at 0x21e256ff130>

2.3 Gaussian and Laplacian Stacks

For demo purposes, I've first applied my Gaussian and Laplacian stacks to lincoln.jpg — as shown below, the renowned Dali painting of Lincoln and Gala that we examined in class.

<matplotlib.image.AxesImage at 0x21e25cfa460>

The Gaussian stack for lincoln.jpg:

The Laplacian stack for lincoln.jpg:

Applying these stacks to the DerekPicture.jpg and nutmeg.jpg hybrid image from part 2.2 above, we can validate those results. The Gaussian stack converges to DerekPicture.jpg while the Laplacian converges to nutmeg.jpg, demonstrating the process in sequence.

The Gaussian stack for the hybrid image:

The Laplacian stack for the hybrid image:

2.4 Multiresolution Blending

Here, I applied the algorithm as described in Burt and Adelson's 1983 paper to blend orange.jpeg and apple.jpeg as shown below. In doing so, I computed a spline at each band of image frequencies to ensure a smooth seam, yielding the so-called "orapple" shown below.

For bells & whistles, I added color to enhance the effect.

Text(0.5, 1.0, 'Orapple')

Final bells & whistles:

This project was super fun to work on! The coolest takeaway for me personally was figuring out the multi-resolution blending algorithm in part 2.4 — Burt and Adelson 1983 was a really fascinating read, and the resulting blended images were of much higher quality than I anticipated.