Skip to content

Latest commit

 

History

History
460 lines (347 loc) · 16 KB

File metadata and controls

460 lines (347 loc) · 16 KB

Convolution, Filters, and Feature Maps in Python

Slide 1: Introduction to Convolution

Convolution is a fundamental operation in image processing and deep learning. It involves sliding a small matrix (filter) over an input image to produce a feature map. This process helps in detecting various features like edges, textures, and patterns.

import numpy as np
import matplotlib.pyplot as plt

def convolve2d(image, kernel):
    i_height, i_width = image.shape
    k_height, k_width = kernel.shape
    output = np.zeros((i_height - k_height + 1, i_width - k_width + 1))
    
    for i in range(output.shape[0]):
        for j in range(output.shape[1]):
            output[i, j] = np.sum(image[i:i+k_height, j:j+k_width] * kernel)
    
    return output

# Example image and kernel
image = np.random.rand(10, 10)
kernel = np.array([[1, 0, -1], [2, 0, -2], [1, 0, -1]])

# Apply convolution
result = convolve2d(image, kernel)

# Visualize
plt.subplot(131), plt.imshow(image), plt.title('Original Image')
plt.subplot(132), plt.imshow(kernel), plt.title('Kernel')
plt.subplot(133), plt.imshow(result), plt.title('Convolved Image')
plt.show()

Slide 2: Understanding Filters

Filters, also known as kernels, are small matrices used in convolution operations. They act as feature detectors, emphasizing certain characteristics in the input image. Different filters can detect various features such as edges, blurs, or sharpness.

import numpy as np
import matplotlib.pyplot as plt

# Define different filters
edge_detect = np.array([[-1, -1, -1],
                        [-1,  8, -1],
                        [-1, -1, -1]])

sharpen = np.array([[0, -1,  0],
                    [-1, 5, -1],
                    [0, -1,  0]])

blur = np.array([[1/9, 1/9, 1/9],
                 [1/9, 1/9, 1/9],
                 [1/9, 1/9, 1/9]])

# Visualize filters
plt.subplot(131), plt.imshow(edge_detect), plt.title('Edge Detection')
plt.subplot(132), plt.imshow(sharpen), plt.title('Sharpen')
plt.subplot(133), plt.imshow(blur), plt.title('Blur')
plt.show()

Slide 3: Applying Different Filters

Let's apply the filters we defined to a sample image and observe the results. This will help us understand how different filters affect the input image.

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

def apply_filter(image, kernel):
    return convolve2d(image, kernel)

# Load a sample image
image = np.array(Image.open('sample_image.jpg').convert('L'))

# Apply filters
edge_result = apply_filter(image, edge_detect)
sharpen_result = apply_filter(image, sharpen)
blur_result = apply_filter(image, blur)

# Visualize results
plt.figure(figsize=(12, 8))
plt.subplot(221), plt.imshow(image, cmap='gray'), plt.title('Original')
plt.subplot(222), plt.imshow(edge_result, cmap='gray'), plt.title('Edge Detection')
plt.subplot(223), plt.imshow(sharpen_result, cmap='gray'), plt.title('Sharpened')
plt.subplot(224), plt.imshow(blur_result, cmap='gray'), plt.title('Blurred')
plt.show()

Slide 4: Feature Maps

Feature maps are the output of applying convolution operations to an input image. They highlight specific features detected by the filter, creating a new representation of the original image that emphasizes certain characteristics.

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import convolve2d

# Create a simple image with a vertical line
image = np.zeros((10, 10))
image[:, 4:6] = 1

# Define a vertical edge detection filter
vertical_edge = np.array([[-1, 0, 1],
                          [-1, 0, 1],
                          [-1, 0, 1]])

# Apply convolution
feature_map = convolve2d(image, vertical_edge, mode='valid')

# Visualize
plt.subplot(131), plt.imshow(image), plt.title('Original Image')
plt.subplot(132), plt.imshow(vertical_edge), plt.title('Vertical Edge Filter')
plt.subplot(133), plt.imshow(feature_map), plt.title('Feature Map')
plt.show()

Slide 5: Multiple Feature Maps

In convolutional neural networks, we often use multiple filters to create several feature maps. Each filter detects different features, allowing the network to learn various aspects of the input image.

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import convolve2d

# Create a simple image
image = np.random.rand(20, 20)

# Define multiple filters
filters = [
    np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]),  # Edge detection
    np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]]) / 9,  # Blur
    np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])  # Sobel x
]

# Apply filters and create feature maps
feature_maps = [convolve2d(image, f, mode='valid') for f in filters]

# Visualize
plt.figure(figsize=(15, 5))
plt.subplot(141), plt.imshow(image), plt.title('Original Image')
for i, fm in enumerate(feature_maps, start=2):
    plt.subplot(1, 4, i), plt.imshow(fm), plt.title(f'Feature Map {i-1}')
plt.show()

Slide 6: Padding in Convolution

Padding is a technique used to preserve the spatial dimensions of the input image after convolution. It involves adding extra pixels around the edges of the input image before applying the convolution operation.

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import convolve2d

def pad_image(image, pad_width):
    return np.pad(image, pad_width, mode='constant')

# Create a sample image
image = np.random.rand(10, 10)

# Create a filter
filter = np.array([[1, 0, -1],
                   [2, 0, -2],
                   [1, 0, -1]])

# Pad the image
padded_image = pad_image(image, pad_width=1)

# Apply convolution
result_no_pad = convolve2d(image, filter, mode='valid')
result_with_pad = convolve2d(padded_image, filter, mode='valid')

# Visualize
plt.subplot(221), plt.imshow(image), plt.title('Original Image')
plt.subplot(222), plt.imshow(padded_image), plt.title('Padded Image')
plt.subplot(223), plt.imshow(result_no_pad), plt.title('No Padding')
plt.subplot(224), plt.imshow(result_with_pad), plt.title('With Padding')
plt.show()

Slide 7: Strided Convolution

Strided convolution involves moving the filter over the input image with a step size (stride) greater than 1. This reduces the spatial dimensions of the output feature map and can help in downsampling the image.

import numpy as np
import matplotlib.pyplot as plt

def strided_convolution(image, kernel, stride):
    i_height, i_width = image.shape
    k_height, k_width = kernel.shape
    output_height = (i_height - k_height) // stride + 1
    output_width = (i_width - k_width) // stride + 1
    output = np.zeros((output_height, output_width))
    
    for i in range(0, output_height):
        for j in range(0, output_width):
            output[i, j] = np.sum(image[i*stride:i*stride+k_height, j*stride:j*stride+k_width] * kernel)
    
    return output

# Create a sample image and kernel
image = np.random.rand(10, 10)
kernel = np.array([[1, 0, -1], [2, 0, -2], [1, 0, -1]])

# Apply strided convolution
result_stride1 = strided_convolution(image, kernel, stride=1)
result_stride2 = strided_convolution(image, kernel, stride=2)

# Visualize
plt.subplot(131), plt.imshow(image), plt.title('Original Image')
plt.subplot(132), plt.imshow(result_stride1), plt.title('Stride 1')
plt.subplot(133), plt.imshow(result_stride2), plt.title('Stride 2')
plt.show()

Slide 8: Dilated Convolution

Dilated convolution, also known as atrous convolution, involves inserting spaces between kernel elements. This increases the receptive field without increasing the number of parameters, allowing the network to capture multi-scale information.

import numpy as np
import matplotlib.pyplot as plt

def dilated_convolution(image, kernel, dilation):
    i_height, i_width = image.shape
    k_height, k_width = kernel.shape
    dilated_k_height = k_height + (k_height - 1) * (dilation - 1)
    dilated_k_width = k_width + (k_width - 1) * (dilation - 1)
    output = np.zeros((i_height - dilated_k_height + 1, i_width - dilated_k_width + 1))
    
    for i in range(output.shape[0]):
        for j in range(output.shape[1]):
            output[i, j] = np.sum(image[i:i+dilated_k_height:dilation, j:j+dilated_k_width:dilation] * kernel)
    
    return output

# Create a sample image and kernel
image = np.random.rand(15, 15)
kernel = np.array([[1, 0, -1], [2, 0, -2], [1, 0, -1]])

# Apply dilated convolution
result_dilation1 = dilated_convolution(image, kernel, dilation=1)
result_dilation2 = dilated_convolution(image, kernel, dilation=2)

# Visualize
plt.subplot(131), plt.imshow(image), plt.title('Original Image')
plt.subplot(132), plt.imshow(result_dilation1), plt.title('Dilation 1')
plt.subplot(133), plt.imshow(result_dilation2), plt.title('Dilation 2')
plt.show()

Slide 9: Convolution in Color Images

When working with color images, convolution is applied to each color channel separately. This allows us to detect features in different color spaces and preserve color information.

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

def convolve_color(image, kernel):
    r, g, b = image[:,:,0], image[:,:,1], image[:,:,2]
    return np.stack([convolve2d(r, kernel), convolve2d(g, kernel), convolve2d(b, kernel)], axis=2)

# Load a color image
image = np.array(Image.open('color_image.jpg'))

# Define a sharpening filter
sharpen = np.array([[0, -1, 0],
                    [-1, 5, -1],
                    [0, -1, 0]])

# Apply convolution
result = convolve_color(image, sharpen)

# Clip values to valid range
result = np.clip(result, 0, 255).astype(np.uint8)

# Visualize
plt.subplot(121), plt.imshow(image), plt.title('Original Image')
plt.subplot(122), plt.imshow(result), plt.title('Sharpened Image')
plt.show()

Slide 10: Real-life Example: Edge Detection in Medical Imaging

Edge detection is crucial in medical image analysis for identifying organ boundaries or detecting anomalies. Let's apply edge detection to a brain MRI scan.

import numpy as np
import matplotlib.pyplot as plt
from skimage import io, color
from scipy.signal import convolve2d

# Load and preprocess the MRI image
mri_image = io.imread('brain_mri.jpg')
mri_gray = color.rgb2gray(mri_image)

# Define Sobel filters for edge detection
sobel_x = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])
sobel_y = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])

# Apply edge detection
edges_x = convolve2d(mri_gray, sobel_x, mode='same', boundary='symm')
edges_y = convolve2d(mri_gray, sobel_y, mode='same', boundary='symm')
edges = np.sqrt(edges_x**2 + edges_y**2)

# Visualize results
plt.figure(figsize=(12, 4))
plt.subplot(131), plt.imshow(mri_image), plt.title('Original MRI')
plt.subplot(132), plt.imshow(mri_gray, cmap='gray'), plt.title('Grayscale MRI')
plt.subplot(133), plt.imshow(edges, cmap='gray'), plt.title('Detected Edges')
plt.show()

Slide 11: Real-life Example: Texture Analysis in Material Science

Convolution and feature maps are essential in material science for analyzing textures and structures. Let's apply different filters to a microscopic image of a material surface.

import numpy as np
import matplotlib.pyplot as plt
from skimage import io, color
from scipy.signal import convolve2d

# Load and preprocess the material image
material_image = io.imread('material_surface.jpg')
material_gray = color.rgb2gray(material_image)

# Define filters for texture analysis
edge_detect = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]])
texture_1 = np.array([[1, -1, 1], [-1, 0, -1], [1, -1, 1]])
texture_2 = np.array([[-1, 2, -1], [2, -4, 2], [-1, 2, -1]])

# Apply filters
result_edge = convolve2d(material_gray, edge_detect, mode='same', boundary='symm')
result_texture1 = convolve2d(material_gray, texture_1, mode='same', boundary='symm')
result_texture2 = convolve2d(material_gray, texture_2, mode='same', boundary='symm')

# Visualize results
plt.figure(figsize=(15, 5))
plt.subplot(141), plt.imshow(material_image), plt.title('Original Image')
plt.subplot(142), plt.imshow(result_edge, cmap='gray'), plt.title('Edge Detection')
plt.subplot(143), plt.imshow(result_texture1, cmap='gray'), plt.title('Texture Filter 1')
plt.subplot(144), plt.imshow(result_texture2, cmap='gray'), plt.title('Texture Filter 2')
plt.show()

Slide 12: Visualizing Convolutional Layers

In deep learning, convolutional layers apply multiple filters to create feature maps. Let's visualize this process using a simple neural network.

import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D

# Create a simple convolutional model
model = Sequential([
    Conv2D(16, (3, 3), activation='relu', input_shape=(64, 64, 1)),
    MaxPooling2D((2, 2)),
    Conv2D(32, (3, 3), activation='relu'),
    MaxPooling2D((2, 2))
])

# Generate a random input image
input_image = np.random.rand(1, 64, 64, 1)

# Get the output of each layer
layer_outputs = [layer.output for layer in model.layers]
activation_model = tf.keras.models.Model(inputs=model.input, outputs=layer_outputs)
activations = activation_model.predict(input_image)

# Plot the feature maps
for i, activation in enumerate(activations):
    plt.figure(figsize=(12, 6))
    for j in range(min(16, activation.shape[-1])):
        plt.subplot(4, 4, j+1)
        plt.imshow(activation[0, :, :, j], cmap='viridis')
        plt.axis('off')
    plt.suptitle(f'Feature Maps of Layer {i+1}')
    plt.show()

Slide 13: Convolution in Signal Processing

Convolution is not limited to image processing; it's also crucial in signal processing. Let's apply convolution to a 1D signal for noise reduction.

import numpy as np
import matplotlib.pyplot as plt

# Generate a noisy signal
t = np.linspace(0, 10, 1000)
signal = np.sin(t) + np.random.normal(0, 0.2, t.shape)

# Define a simple moving average filter
window_size = 20
filter = np.ones(window_size) / window_size

# Apply convolution
smoothed_signal = np.convolve(signal, filter, mode='same')

# Plot results
plt.figure(figsize=(12, 6))
plt.plot(t, signal, label='Noisy Signal', alpha=0.7)
plt.plot(t, smoothed_signal, label='Smoothed Signal', linewidth=2)
plt.legend()
plt.title('Noise Reduction using Convolution')
plt.xlabel('Time')
plt.ylabel('Amplitude')
plt.show()

Slide 14: Convolution in Natural Language Processing

Convolution can be applied to text data for tasks like sentiment analysis or text classification. Here's a simplified example using character-level convolution.

import numpy as np

def char_to_index(char):
    return ord(char) - ord('a') if char.isalpha() else 26

def text_to_matrix(text, max_length=10):
    matrix = np.zeros((max_length, 27))  # 26 letters + 1 for non-alphabetic
    for i, char in enumerate(text[:max_length].lower()):
        matrix[i, char_to_index(char)] = 1
    return matrix

def convolve1d(text_matrix, kernel):
    return np.sum(text_matrix[:len(kernel)] * kernel)

# Example usage
text = "hello world"
text_matrix = text_to_matrix(text)
kernel = np.random.rand(3, 27)  # 3-gram kernel

result = convolve1d(text_matrix, kernel)
print(f"Convolution result: {result}")

Slide 15: Additional Resources

For those interested in diving deeper into convolution, filters, and feature maps, here are some valuable resources:

  1. "Convolutional Neural Networks for Visual Recognition" - Stanford CS231n course materials (http://cs231n.github.io/)
  2. "Deep Learning" by Ian Goodfellow, Yoshua Bengio, and Aaron Courville (https://www.deeplearningbook.org/)
  3. "A guide to convolution arithmetic for deep learning" by Vincent Dumoulin and Francesco Visin (arXiv:1603.07285)
  4. "Convolution and Feature Maps" - Towards Data Science article (https://towardsdatascience.com/convolution-and-feature-maps-2dea88a35e11)
  5. "Understanding Convolutions" by Christopher Olah (http://colah.github.io/posts/2014-07-Understanding-Convolutions/)

These resources provide in-depth explanations, mathematical foundations, and practical applications of convolution in various domains of machine learning and signal processing.