Real-world images are full of visual noise and artifacts. Filtering is the process of applying mathematical kernels to clean and simplify visual data.
1Spatial Convolution
Welcome back. We've talked about what an image is mathematically. But real-world data is messy. Camera sensors introduce static, bad lighting creates grain, and lenses distort reality. Today, we learn the mathematics of cleaning: Spatial Filtering.
At the heart of filtering is a process called 'Convolution'. We create a tiny, tiny matrix called a 'Kernel' (usually 3x3 or 5x5). We slide this kernel over the entire image, pixel by pixel. At every stop, it calculates a new value for the center pixel based on its neighbors.
# Convolution Anatomy
# Kernel = Tiny Weight Matrix (e.g., 3x3)
# Operation = Slide kernel over image
# Result = New center pixel based on neighbors2The Box Blur (Mean Filter)
Let's look at the simplest kernel: The Box Blur (or Mean Filter). It's a matrix where every number is a fraction. If it's a 3x3 kernel, it has 9 pixels.
It simply adds up all 9 pixels in the neighborhood and divides by 9. It replaces the center pixel with the exact mathematical average. While Box Blur is easy, it's destructive. It treats the pixel 5 units away exactly the same as the pixel right next to the center. This creates an ugly, boxy effect.
import cv2
import numpy as np
# Creating a 3x3 Mean Filter manually
kernel_3x3 = np.ones((3, 3), np.float32) / 9.0
# Applying it using cv2.filter2D
blurred = cv2.filter2D(image, -1, kernel_3x3)3Gaussian Blurring
Enter the Gaussian Blur. This is the industry standard. A Gaussian Kernel uses a 3D mathematical bell curve.
The center pixel is given the highest weight, and the pixels further away are given much smaller weights. The result is a smooth, highly natural-looking blur that reduces static noise while preserving the rough shapes of objects. Notice the kernel size must ALWAYS be an odd number (3, 5, 7...).
# Notice the kernel size must ALWAYS be an odd number
gaussian_blur = cv2.GaussianBlur(image, (5, 5), 0)
# Center receives the highest weight
# Edges receive the lowest4Combating Extreme Outliers
But what if your camera sensor fails and introduces 'Salt and Pepper' noise? These are literally random pure white and pure black pixels scattered across your image.
If you use a Box or Gaussian blur on pure white pixels, you just smear the white out into a blurry white halo. This is because averaging a pure 255 (white) value with normal pixels mathematically ruins the local area.
import cv2
# Image is ruined with random black and white dots
noisy_image = cv2.imread('salt_pepper.png')
# Gaussian Blur will just smear the dots
bad_fix = cv2.GaussianBlur(noisy_image, (7, 7), 0)5The Median Filter Magic
The ultimate weapon against this is the Median Filter. It does NOT do any averaging math. Instead, it looks at all pixels in a kernel, sorts them from lowest to highest, and just picks the middle number.
This completely ignores the extreme white (255) and black (0) outliers. There's one golden rule for all OpenCV kernel sizes (like (3,3) or (5,5) or (11,11)): They must always be ODD numbers. Why? Because a kernel must have a strict geometric center pixel to place its calculated result into. An even 4x4 matrix doesn't have a true center.
# The non-linear hero: Median Blur
# Takes a single odd integer for kernel size (e.g., 5)
median_clean = cv2.medianBlur(noisy_image, 5)
# Salt and pepper noise vanishes perfectly