Recently, I was working on an image processing project where I needed to apply various filters to detect edges and blur certain areas. The scipy.signal.convolve2d function became my go-to tool for these operations. In this article, I’ll share how to effectively use this powerful function for image processing in Python.
Whether you’re working on computer vision applications, signal processing, or data analysis, understanding 2D convolution is essential. So let’s get in!
2D Convolution
2D convolution is a mathematical operation that applies a kernel (or filter) to an input image, creating an output image that highlights or transforms certain features.
Think of it as sliding a small matrix (the kernel) over an image and calculating weighted sums at each position. This process is fundamental to many image processing techniques.
Use scipy.signal.convolve2d
Now, I will explain to you the methods to use scipy.signal.convolve2d.
Method 1 – Basic 2D Convolution
Let’s start with a simple example of applying a blur filter to an image:
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
from matplotlib.image import imread
import os
# Use the correct path
image_path = 'sample_image.jpg'
# Check if the file exists
if not os.path.exists(image_path):
raise FileNotFoundError(f"Image not found: {image_path}")
# Load the image
image = imread(image_path)
# Convert to grayscale if it is RGB (3 channels)
if image.ndim == 3:
image = np.mean(image, axis=2)
# Create a simple blur kernel
kernel = np.ones((5, 5)) / 25
# Apply convolution
filtered_image = signal.convolve2d(image, kernel, mode='same', boundary='wrap')
# Display results
plt.figure(figsize=(10, 5))
plt.subplot(121)
plt.imshow(image, cmap='gray')
plt.title('Original Image')
plt.axis('off')
plt.subplot(122)
plt.imshow(filtered_image, cmap='gray')
plt.title('Blurred Image')
plt.axis('off')
plt.tight_layout()
plt.show()I executed the above example code and added the screenshot below.

In this example, I’m using a 5×5 averaging kernel to blur the image. The ‘same’ mode ensures that our output image has the same dimensions as the input.
Read Python SciPy Gamma
Method 2 – Edge Detection with Convolution
Edge detection is another common application of 2D convolution:
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
from matplotlib.image import imread
import os
# Load an image (grayscale conversion)
image_path = r'C:\Users\Public\sample_image.jpg'
if not os.path.exists(image_path):
raise FileNotFoundError(f"Image not found: {image_path}")
image = imread(image_path)
if image.ndim == 3:
image = np.mean(image, axis=2)
# Create Sobel operators 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 convolution
edges_x = signal.convolve2d(image, sobel_x, mode='same', boundary='symm')
edges_y = signal.convolve2d(image, sobel_y, mode='same', boundary='symm')
# Combine the results
edges = np.sqrt(edges_x**2 + edges_y**2)
edges = edges / edges.max() # Normalize
# Plot the results
plt.figure(figsize=(15, 5))
plt.subplot(131)
plt.imshow(image, cmap='gray')
plt.title('Original Image')
plt.axis('off')
plt.subplot(132)
plt.imshow(edges_x, cmap='gray')
plt.title('Horizontal Edges')
plt.axis('off')
plt.subplot(133)
plt.imshow(edges, cmap='gray')
plt.title('Combined Edges')
plt.axis('off')
plt.tight_layout()
plt.show()I executed the above example code and added the screenshot below.

This code detects edges in both horizontal and vertical directions using Sobel operators, then combines them to highlight all edges in the image.
Check out Python SciPy ttest_ind
Method 3 – Understand Convolution Modes
The mode parameter in convolve2d is critical for controlling how the operation handles the image boundaries:
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
# Example demonstrating different convolution modes
kernel = np.ones((3, 3)) / 9 # Simple 3x3 averaging filter
# Create a small test image
test_image = np.zeros((8, 8))
test_image[2:6, 2:6] = 1 # White square in the middle
# Convolution modes
modes = ['full', 'same', 'valid']
results = []
for mode in modes:
results.append(signal.convolve2d(test_image, kernel, mode=mode))
# Display results
plt.figure(figsize=(15, 5))
plt.subplot(1, 4, 1)
plt.imshow(test_image, cmap='gray')
plt.title('Original')
plt.axis('off')
for i, mode in enumerate(modes):
plt.subplot(1, 4, i + 2)
plt.imshow(results[i], cmap='gray')
plt.title(f'Mode: {mode}')
plt.axis('off')
plt.tight_layout()
plt.show()I executed the above example code and added the screenshot below.

The different modes work as follows:
- ‘full’: Returns the full convolution, including boundary effects
- ‘same’: Returns an output the same size as the input
- ‘valid’: Returns only the parts of the convolution that are computed without zero-padded edges
Read Python SciPy Derivative of Array
Method 4 – Separable Convolutions for Efficiency
For certain kernels that can be separated into row and column components, we can optimize our computation:
# Gaussian kernel (can be separated)
def gaussian_kernel(size, sigma):
"""Generate a 2D Gaussian kernel"""
x, y = np.mgrid[-size//2 + 1:size//2 + 1, -size//2 + 1:size//2 + 1]
g = np.exp(-((x**2 + y**2)/(2.0*sigma**2)))
return g / g.sum()
# Generate a 15x15 Gaussian kernel
kernel_2d = gaussian_kernel(15, 3)
# Applying full 2D convolution
start_time = time.time()
result_2d = signal.convolve2d(image, kernel_2d, mode='same')
time_2d = time.time() - start_time
# Separate the kernel (for Gaussian, we can just use the same 1D kernel for both directions)
kernel_x = gaussian_kernel(15, 3)[7:8, :] # Middle row
kernel_y = gaussian_kernel(15, 3)[:, 7:8] # Middle column
# Apply separable convolution
start_time = time.time()
temp = signal.convolve2d(image, kernel_x, mode='same')
result_separable = signal.convolve2d(temp, kernel_y, mode='same')
time_separable = time.time() - start_time
print(f"2D convolution time: {time_2d:.4f} seconds")
print(f"Separable convolution time: {time_separable:.4f} seconds")
print(f"Speedup: {time_2d/time_separable:.2f}x")Separable convolutions can be significantly faster, especially for larger kernels, making them valuable for real-time applications.
Check out Python SciPy Load Mat File
Practical Applications of 2D Convolution
Let me explain to you the practical applications of 2D convolution.
Image Sharpening
Enhance edges and fine details in images by emphasizing intensity differences using a sharpening filter.
# Create a sharpening kernel
sharpen_kernel = np.array([[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]])
# Apply the sharpening filter
sharpened = signal.convolve2d(image, sharpen_kernel, mode='same', boundary='symm')
# Clip values to valid range for display
sharpened = np.clip(sharpened, 0, 1)
# Display results
plt.figure(figsize=(10, 5))
plt.subplot(121)
plt.imshow(image, cmap='gray')
plt.title('Original Image')
plt.subplot(122)
plt.imshow(sharpened, cmap='gray')
plt.title('Sharpened Image')
plt.show()Emboss Effect
Simulate a 3D relief by highlighting edges with directional shading to give the image a textured appearance.
# Create an emboss kernel
emboss_kernel = np.array([[-2, -1, 0],
[-1, 1, 1],
[0, 1, 2]])
# Apply the emboss filter
embossed = signal.convolve2d(image, emboss_kernel, mode='same', boundary='symm')
# Normalize for better visualization
embossed = embossed - embossed.min()
embossed = embossed / embossed.max()
# Display results
plt.figure(figsize=(10, 5))
plt.subplot(121)
plt.imshow(image, cmap='gray')
plt.title('Original Image')
plt.subplot(122)
plt.imshow(embossed, cmap='gray')
plt.title('Embossed Image')
plt.show()Performance Considerations
When working with convolve2d, keep these tips in mind:
- Use separable kernels when possible for significant speed improvements
- Consider using FFT-based convolution for large images (signal.fftconvolve)
- For simple operations on RGB images, process each channel separately
- The ‘valid’ mode is faster than ‘same’ or ‘full’, but produces smaller output
For large images or when performance is critical, you might want to explore GPU-accelerated alternatives like CuPy or TensorFlow’s convolution operations.
I hope you found this article helpful! Whether you’re developing image filters, feature detection algorithms, or signal processing applications, scipy’s convolve2d function provides a powerful and flexible foundation for your projects.
Other Python articles you may also like:

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.