Monday, 22 September 2025

Math ABC: Edge Detection using Vector Dot Product (Convolution)

Filtering is essentially a feature-detection method, whereby a template—​called a kernel in the parlance of filtering—​is matched against portions of a time series signal, and the result of filtering is another time series that indicates how much the characteristics of the signal match the characteristics of the kernel. Kernels are carefully constructed to optimize certain criteria, such as smooth fluctuations, sharp edges, particular waveform shapes, and so on.

The mechanism of filtering is to compute the dot product between the kernel and the time series signal. But filtering usually requires local feature detection, and the kernel is typically much shorter than the entire time series. Therefore, we compute the dot product between the kernel and a short snippet of the data of the same length as the kernel. This procedure produces one time point in the filtered signal (Figure 4-2), and then the kernel is moved one time step to the right to compute the dot product with a different (overlapping) signal segment. Formally, this procedure is called convolution.



References

Cohen, Mike X. Practical Linear Algebra for Data Science (p. 89). O'Reilly Media. Kindle Edition. 


Code by Grok

import numpy as np
import matplotlib.pyplot as plt

# Generate a simple 1D signal (e.g., a step function with noise)
np.random.seed(42)  # For reproducibility
x = np.arange(0, 100)
signal = np.concatenate([np.ones(40) * 10, np.ones(20) * 50, np.ones(40) * 20])
signal += np.random.normal(0, 0.5, 100)  # Add some noise

# Define the edge detection kernel
kernel = np.array([-1, 0, 1])  # Simple edge detection kernel

# Perform convolution using vector dot product
def convolve(signal, kernel):
    n = len(signal)
    k = len(kernel)
    half_k = k // 2
    result = np.zeros(n)
    
    # Pad the signal to handle boundaries
    padded_signal = np.pad(signal, (half_k, half_k), mode='edge')
    
    # Compute convolution via dot product
    for i in range(n):
        window = padded_signal[i:i+k]
        result[i] = np.dot(window, kernel)
    
    return result

# Apply edge detection
edges = convolve(signal, kernel)

# Plotting
plt.figure(figsize=(12, 6))

# Plot original signal
plt.subplot(2, 1, 1)
plt.plot(x, signal, label='Original Signal', color='blue')
plt.title('Original Signal')
plt.xlabel('Index')
plt.ylabel('Amplitude')
plt.grid(True)
plt.legend()

# Plot edge detection result
plt.subplot(2, 1, 2)
plt.plot(x, edges, label='Edge Detection (Kernel [-1, 0, 1])', color='red')
plt.title('Edge Detection Result')
plt.xlabel('Index')
plt.ylabel('Edge Strength')
plt.grid(True)
plt.legend()

# Adjust layout and display
plt.tight_layout()
plt.show()


No comments:

Post a Comment