1.1. Image Filtering#

Adapt from CMU 16-385 Computer Vision and this Youtube series

Part 1: What is an image?#

import cv2
import numpy as np
from matplotlib import pyplot as plt
from skimage import io as io_url
from skimage.util import random_noise
frame = io_url.imread('../images/scotty.jpg')
frame = np.float32(frame) / 255

plt.imshow(frame)
<matplotlib.image.AxesImage at 0x2b9daf40>
../../../_images/2d3e34f1c986dcf37ffe59f8da312ca219a121c201becc450dad8a6c87ec621d.png
fig = plt.figure(figsize=(12, 12));
fig.subplots_adjust(hspace=0.4, wspace=0.4);

ax = fig.add_subplot(1, 3, 1);
ax.set_title('Red');
ax.imshow(frame[:,:,0], cmap="gray");
ax.set_xticks([]); ax.set_yticks([]);

ax = fig.add_subplot(1, 3, 2);
ax.set_title('Green');
ax.imshow(frame[:,:,1], cmap="gray");
ax.set_xticks([]); ax.set_yticks([]);

ax = fig.add_subplot(1, 3, 3);
ax.set_title('Blue');
ax.imshow(frame[:,:,2], cmap="gray");
ax.set_xticks([]); ax.set_yticks([]);
../../../_images/a3c5159a8208f730ac5f0fdb8414779cdabf454d6b7d5aea2100c4858ec9e2db.png
x = range(frame.shape[0]);
y = range(frame.shape[1]);

X, Y = np.meshgrid(y, x);

fig = plt.figure();
ax = plt.axes(projection='3d');
ax.plot_surface(X, Y, frame[:,:,0], cmap='jet');
../../../_images/37d0565b4897fffa8c9f83f92cfe5bea9234d1fa6ce83bdf64e2ef1fe08174bf.png

Part 2: Point processing#

Hide code cell source
fig = plt.figure(figsize=(16, 8));
fig.subplots_adjust(hspace=0.1, wspace=0.1);

ax = fig.add_subplot(2, 4, 1);
ax.set_title('Original');
ax.imshow(frame);
ax.set_xticks([]); ax.set_yticks([]);

ax = fig.add_subplot(2, 4, 2);
ax.set_title('Darken');
ax.imshow(np.clip(frame - 0.5, 0, 1));
ax.set_xticks([]); ax.set_yticks([]);

ax = fig.add_subplot(2, 4, 3);
ax.set_title('Lower contrast');
ax.imshow(frame / 2);
ax.set_xticks([]); ax.set_yticks([]);

ax = fig.add_subplot(2, 4, 4);
ax.set_title('Non-linear lower contrast');
ax.imshow(frame**(1/3));
ax.set_xticks([]); ax.set_yticks([]);

ax = fig.add_subplot(2, 4, 5);
ax.set_title('Invert');
ax.imshow(1 - frame);
ax.set_xticks([]); ax.set_yticks([]);

ax = fig.add_subplot(2, 4, 6);
ax.set_title('Lighten');
ax.imshow(np.clip(frame + 0.5, 0, 1));
ax.set_xticks([]); ax.set_yticks([]);

ax = fig.add_subplot(2, 4, 7);
ax.set_title('Raise contrast');
ax.imshow(np.clip(frame * 2, 0, 1));
ax.set_xticks([]); ax.set_yticks([]);

ax = fig.add_subplot(2, 4, 8);
ax.set_title('Non-linear raise contrast');
ax.imshow(frame**2);
ax.set_xticks([]); ax.set_yticks([]);
../../../_images/00486aa07581736f77b219820335ba74b5ae56bf90a55cbec193f6567124e9ec.png

Part 3: Linear shift-invariant image filtering#

Box filter and Sharpening filter#

fig = plt.figure(figsize=(8,8));
fig.subplots_adjust(hspace=0.1, wspace=0.1);

# Box filter
N = 10;
g = np.ones((N,N))/(N**2);
image = cv2.filter2D(frame,-1,g);

ax = fig.add_subplot(1,2,1);
ax.set_title('Box filter');
plt.imshow(image,cmap='gray');
ax.set_xticks([]); ax.set_yticks([])

# Sharpening filter
N = 3;
g = -np.ones((N,N))/(N**2);
g[(N-1)//2,(N-1)//2] += 2;
image = cv2.filter2D(frame,-1,g);

ax = fig.add_subplot(1,2,2);
ax.set_title('Sharpening filter');
plt.imshow(image,cmap='gray');
ax.set_xticks([]); ax.set_yticks([]);
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
../../../_images/b1ff8a51daae0cebd0a93f4401c0703ddb3c809e5758b0df2d4b3d71c0b04d60.png

Gaussian filter#

img = io_url.imread('images/Hopper.jpg',0)
fig = plt.figure(figsize=(12, 12));
fig.subplots_adjust(hspace=0.1, wspace=0.1);

# corrupted by gaussian noise
mean, sigma = 0,0.25
noise = np.random.normal(mean, sigma, img.shape)
img_gaussian = img/255 + noise
img_gaussian = np.clip(img_gaussian,0,1)
img_gaussian = np.uint8(img_gaussian*255)

ax = fig.add_subplot(1,2,1);
ax.set_title('corrupted by gaussian noise')
plt.imshow(img_gaussian,cmap='gray');
ax.set_xticks([]); ax.set_yticks([]);

width = 11
img_blur = cv2.GaussianBlur(img_gaussian,(width,width),0);
ax = fig.add_subplot(1,2,2);
ax.set_title('gaussian filter');
plt.imshow(img_blur,cmap='gray');
ax.set_xticks([]); ax.set_yticks([]);
../../../_images/2c496a41928a9aee93714a1eb76438114fe29cd7cd232896cf09dc12656ce38c.png

Median filter (nonlinear)#

Gaussian filtering is good at smoothing additive, zero-mean noise (assuming nearby pixels share the same value)
Pepper and sault (Impulse) noise break this assumption

im_arr = np.array(img)
noise_img = random_noise(im_arr, mode='salt')
noise_img = np.uint8(noise_img*255)
gaussian = cv2.GaussianBlur(noise_img,(9,9),0);
median = cv2.medianBlur(noise_img,5)

fig = plt.figure(figsize=(12, 12));
fig.subplots_adjust(hspace=0.1, wspace=0.1);

ax = fig.add_subplot(1,2,1);
ax.set_title('gaussian filter')
plt.imshow(gaussian,cmap='gray');
ax.set_xticks([]); ax.set_yticks([]);

ax = fig.add_subplot(1,2,2);
ax.set_title('median filter')
plt.imshow(median,cmap='gray');
ax.set_xticks([]); ax.set_yticks([]);
../../../_images/65689287729252b3560593b0033cd05c115bc4377139f1b9b38a3f582ceb493e.png

Demo of Image Kernels#

More image kernels!