Change each pixel using its neighbours: smooth away noise, keep the edges, or bring them out.
Image filtering applies a mathematical operation to each pixel based on its neighbourhood.
Smoothing.
Sharpening.
Gradients, edges.
For other algorithms.
Key idea: output pixel = f(input pixel + its neighbours)
import cv2
import numpy as np
# simple averaging blur
blurred = cv2.blur(img, (5, 5))
# ans: a 5x5 kernel: averages 25 pixels
# what does the kernel size mean?
# (5, 5) means 5 rows x 5 columns
# ans: larger kernel = more blur
# blur with different kernel sizes
blur3 = cv2.blur(img, (3, 3))
blur7 = cv2.blur(img, (7, 7))
# ans: blur3 < blur7 (7x7 blurs more)
Gaussian kernel: weights the centre pixel more than the edges.
Advantages over the box filter:
# gaussian blur
gaussian = cv2.GaussianBlur(img, (5, 5), 0)
# ans: 5x5 kernel, sigma=0 (computed from the kernel size)
# what is sigma?
# ans: the standard deviation: it controls blur strength
# ans: larger sigma = more blur
# gaussian with a specific sigma
gaussian = cv2.GaussianBlur(img, (5, 5), sigmaX=2.0)
# ans: sigma=2.0 controls the spread of the gaussian
# kernel size must be odd
gaussian = cv2.GaussianBlur(img, (4, 4), 0)
# ans: ERROR! the kernel size must be odd (3, 5, 7, ...)
Replace each pixel with the median of its neighbourhood.
Advantage: excellent for salt-and-pepper noise: it ignores outliers.
Disadvantage: slower than linear filters.
# median blur (good for salt-and-pepper noise)
median = cv2.medianBlur(img, 5)
# ans: 5x5 window: the median of 25 pixels
# kernel size must be odd, and a single value
median = cv2.medianBlur(img, 7)
# ans: a 7x7 window
# why median for noise?
# ans: outliers (noise) don't affect the median
# ans: preserves edges while removing noise
Smooths while preserving edges.
Use case: noise reduction that keeps sharp edges, e.g. portrait smoothing.
# bilateral filter (edge-preserving)
bilateral = cv2.bilateralFilter(img, 9, 75, 75)
# ans: d=9 (diameter), sigmaColor=75, sigmaSpace=75
# what is d?
# ans: the diameter of the pixel neighbourhood
# what is sigmaColor?
# ans: the filter sigma in colour space (intensity difference)
# what is sigmaSpace?
# ans: the filter sigma in coordinate space (spatial distance)
# when to use bilateral?
# ans: noise reduction with edge preservation
Answer first, then press → to check.
What does smoothing do?
Averages each neighbourhood: reduces noise, blurs the image.
What is the difference between blur and Gaussian blur?
Gaussian weights the centre more, which looks more natural.
Which filter for salt-and-pepper noise?
The median filter: it removes outliers.
Why is the bilateral filter special?
It preserves edges while smoothing.
What is the kernel size?
The neighbourhood size, e.g. 3×3 or 5×5.
What does a larger kernel mean?
More smoothing, more blur, slower processing.
Why must the kernel size be odd?
It needs a centre pixel: a symmetric neighbourhood.
What is sigma in a Gaussian?
The standard deviation: it controls the blur strength.
What is the trade-off of smoothing?
It reduces noise but also blurs edges and details.
# apply a 3x3 averaging blur
blurred = cv2.blur(img, (3, 3)) # ans:
# apply a 7x7 gaussian blur
gaussian = cv2.GaussianBlur(img, (7, 7), 0) # ans:
# apply a median filter with kernel 5
median = cv2.medianBlur(img, 5) # ans:
# apply a bilateral filter
bilateral = cv2.bilateralFilter(img, 9, 75, 75) # ans:
# gaussian blur with sigma=3
gaussian = cv2.GaussianBlur(img, (0, 0), sigmaX=3) # ans:
# ans: kernel size (0, 0) is computed from sigma
# compare blur strengths
blur_small = cv2.blur(img, (3, 3))
blur_large = cv2.blur(img, (9, 9))
# ans: blur_large is much more blurred
# apply a median blur on grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
median = cv2.medianBlur(gray, 5) # ans:
# what happens with an even kernel size?
blurred = cv2.blur(img, (4, 4))
# ans: works for blur, but not for GaussianBlur / medianBlur
# which is faster: median or gaussian?
# ans: gaussian (a linear filter) is faster than median
# bilateral with a large sigmaColor?
bilateral = cv2.bilateralFilter(img, 9, 150, 75)
# ans: smooths more aggressively across similar colours
# bilateral with a large sigmaSpace?
bilateral = cv2.bilateralFilter(img, 9, 75, 150)
# ans: pixels farther away count more
# multiple blurs in sequence
blur1 = cv2.GaussianBlur(img, (5, 5), 0)
blur2 = cv2.GaussianBlur(blur1, (5, 5), 0)
# ans: double blur = more smoothing
# can you blur an already blurred image?
# ans: yes: the blur accumulates
# blur only one channel
img[:, :, 0] = cv2.blur(img[:, :, 0], (5, 5))
# ans: blurs only the blue channel