Image Filtering
Image Filtering¶
Overview¶
Image filtering is the process of transforming pixel values by considering neighboring pixels. Various effects such as noise removal, blur, and sharpening can be achieved. In this document, we'll learn from the concepts of kernels and convolution to various filter functions in OpenCV.
Difficulty: ββ (Beginner-Intermediate)
Learning Objectives:
- Understand kernel and convolution concepts
- Learn various blur filters (blur, GaussianBlur, medianBlur, bilateralFilter)
- Edge-preserving smoothing
- Implement custom filters and sharpening
Table of Contents¶
- Kernels and Convolution
- Average Blur - blur()
- Gaussian Blur - GaussianBlur()
- Median Blur - medianBlur()
- Bilateral Filter - bilateralFilter()
- Custom Filter - filter2D()
- Sharpening Filter
- Practice Problems
- Next Steps
- References
1. Kernels and Convolution¶
What is a Kernel?¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Kernel β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β A kernel (or filter, mask) is a small matrix that defines β
β the operation to apply to an image. Typically 3x3, 5x5, 7x7. β
β β
β Example: 3x3 average filter kernel β
β β
β 1/9 1/9 1/9 βββββ¬ββββ¬ββββ β
β β1/9β1/9β1/9β β
β 1/9 1/9 1/9 = βββββΌββββΌββββ€ β
β β1/9β1/9β1/9β β
β 1/9 1/9 1/9 βββββΌββββΌββββ€ β
β β1/9β1/9β1/9β β
β βββββ΄ββββ΄ββββ β
β β
β Kernel size meaning: β
β - Larger size considers wider area β
β - Large kernel = strong effect, slow processing β
β - Small kernel = weak effect, fast processing β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Convolution Operation¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Convolution Operation β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Apply kernel to each pixel of input image to calculate new valueβ
β β
β Input image 3x3 kernel Output β
β βββββ¬ββββ¬ββββ¬ββββ βββββ¬ββββ¬ββββ β
β β 1 β 2 β 3 β 4 β β1/9β1/9β1/9β β
β βββββΌββββΌββββΌββββ€ βββββΌββββΌββββ€ Result pixel: β
β β 5 β 6 β 7 β 8 β β1/9β1/9β1/9β (1+2+3+5+6+7+9+10+11)/9 β
β βββββΌββββΌββββΌββββ€ βββββΌββββΌββββ€ = 54/9 = 6 β
β β 9 β10 β11 β12 β β1/9β1/9β1/9β β
β βββββΌββββΌββββΌββββ€ βββββ΄ββββ΄ββββ β
β β13 β14 β15 β16 β β
β βββββ΄ββββ΄ββββ΄ββββ β
β β
β Process: β
β 1. Place kernel over image β
β 2. Multiply corresponding pixels β
β 3. Sum all results β
β 4. Move to next pixel and repeat β
β β
β Border handling: β
β - BORDER_CONSTANT: Fill with constant value (default 0) β
β - BORDER_REPLICATE: Replicate border pixels β
β - BORDER_REFLECT: Reflect at border β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Convolution Visualization¶
import cv2
import numpy as np
def visualize_convolution(img, kernel):
"""Visualize convolution process (for learning)"""
h, w = img.shape
kh, kw = kernel.shape
pad = kh // 2
# Add padding
padded = np.pad(img, pad, mode='constant', constant_values=0)
# Result array
result = np.zeros_like(img, dtype=np.float64)
# Convolution (slow version - for learning)
for y in range(h):
for x in range(w):
region = padded[y:y+kh, x:x+kw]
result[y, x] = np.sum(region * kernel)
return result
# Example
img = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
], dtype=np.float64)
kernel = np.ones((3, 3)) / 9 # Average filter
result = visualize_convolution(img, kernel)
print("Input:\n", img)
print("\nResult:\n", result)
2. Average Blur - blur()¶
Basic Usage¶
Average blur is the simplest blur filter, using the average value of the kernel area.
import cv2
img = cv2.imread('image.jpg')
# blur(src, ksize)
# ksize: kernel size in (width, height) format
blur_3x3 = cv2.blur(img, (3, 3))
blur_5x5 = cv2.blur(img, (5, 5))
blur_7x7 = cv2.blur(img, (7, 7))
blur_15x15 = cv2.blur(img, (15, 15))
cv2.imshow('Original', img)
cv2.imshow('3x3 Blur', blur_3x3)
cv2.imshow('5x5 Blur', blur_5x5)
cv2.imshow('15x15 Blur', blur_15x15)
cv2.waitKey(0)
cv2.destroyAllWindows()
Average Blur Kernel¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Average Blur Kernel β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β 3x3 average kernel: β
β βββββββ¬ββββββ¬ββββββ β
β β 1/9 β 1/9 β 1/9 β β
β βββββββΌββββββΌββββββ€ β
β β 1/9 β 1/9 β 1/9 β = 1/9 Γ [[1, 1, 1], β
β βββββββΌββββββΌββββββ€ [1, 1, 1], β
β β 1/9 β 1/9 β 1/9 β [1, 1, 1]] β
β βββββββ΄ββββββ΄ββββββ β
β β
β 5x5 average kernel: β
β All values are 1/25 β
β β
β Features: β
β - Simple and fast β
β - Edges also get blurred β
β - Effective for uniform noise removal β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
boxFilter()¶
A generalized version of blur().
import cv2
img = cv2.imread('image.jpg')
# normalize=True (default): Normalize kernel (average filter)
# normalize=False: Sum filter
blur_normalized = cv2.boxFilter(img, -1, (5, 5), normalize=True)
sum_filter = cv2.boxFilter(img, -1, (5, 5), normalize=False)
# Same as blur(img, (5, 5))
print(f"Difference: {np.sum(np.abs(cv2.blur(img, (5, 5)) - blur_normalized))}") # 0
3. Gaussian Blur - GaussianBlur()¶
What is Gaussian Filter?¶
Gaussian filter is a blur filter that gives more weight to the center. It produces a natural blur effect.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Gaussian Kernel β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Gaussian distribution (normal distribution, bell shape): β
β β
β β² β
β β ββββ β
β β ββββββββ β
β β ββββββββββ β
β β ββββββββββββ β
β βββββββββββββββ β
β ββββββββββββββββββββΆ β
β Weight decreases away from center β
β β
β 3x3 Gaussian kernel (approximate): β
β βββββββ¬ββββββ¬ββββββ β
β β 1 β 2 β 1 β β
β βββββββΌββββββΌββββββ€ Γ 1/16 β
β β 2 β 4 β 2 β β
β βββββββΌββββββΌββββββ€ β
β β 1 β 2 β 1 β β
β βββββββ΄ββββββ΄ββββββ β
β β
β Features: β
β - More natural result than average blur β
β - Often used for edge detection preprocessing β
β - Control blur strength with sigma (Ο) value β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Usage¶
import cv2
img = cv2.imread('image.jpg')
# GaussianBlur(src, ksize, sigmaX, sigmaY=0)
# ksize: Kernel size (must be odd)
# sigmaX: Standard deviation in X direction (0 = auto-calculate from kernel size)
# sigmaY: Standard deviation in Y direction (0 = same as sigmaX)
# Specify kernel size (sigma auto-calculated)
blur1 = cv2.GaussianBlur(img, (5, 5), 0)
# Specify sigma (kernel size auto-adjusted appropriately)
blur2 = cv2.GaussianBlur(img, (0, 0), 3) # sigma=3
# Specify both kernel size and sigma
blur3 = cv2.GaussianBlur(img, (7, 7), 1.5)
Relationship Between Sigma and Kernel Size¶
import cv2
import numpy as np
# Generate Gaussian kernel directly to check
def show_gaussian_kernel(ksize, sigma):
kernel = cv2.getGaussianKernel(ksize, sigma)
kernel_2d = kernel @ kernel.T # 1D to 2D
print(f"Kernel ({ksize}x{ksize}, sigma={sigma}):")
print(np.round(kernel_2d, 4))
print(f"Sum: {np.sum(kernel_2d):.4f}\n")
show_gaussian_kernel(3, 0) # sigma auto-calculated
show_gaussian_kernel(5, 0)
show_gaussian_kernel(5, 1.0)
show_gaussian_kernel(5, 2.0)
# Recommended: sigma = 0.3 * ((ksize - 1) * 0.5 - 1) + 0.8
Average Blur vs Gaussian Blur¶
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('image.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# Compare with same kernel size
ksize = 15
avg_blur = cv2.blur(img, (ksize, ksize))
gauss_blur = cv2.GaussianBlur(img, (ksize, ksize), 0)
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
axes[0].imshow(img_rgb)
axes[0].set_title('Original')
axes[1].imshow(cv2.cvtColor(avg_blur, cv2.COLOR_BGR2RGB))
axes[1].set_title('Average Blur')
axes[2].imshow(cv2.cvtColor(gauss_blur, cv2.COLOR_BGR2RGB))
axes[2].set_title('Gaussian Blur')
for ax in axes:
ax.axis('off')
plt.tight_layout()
plt.show()
4. Median Blur - medianBlur()¶
What is Median Filter?¶
Median filter uses the median value of the kernel area. Very effective for salt-and-pepper noise removal.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Median Filter Operation β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Input region: β
β ββββββ¬βββββ¬βββββ β
β β 10 β 20 β 30 β β
β ββββββΌβββββΌβββββ€ β
β β 40 β255 β 60 β β Center 255 is noise (salt) β
β ββββββΌβββββΌβββββ€ β
β β 70 β 80 β 90 β β
β ββββββ΄βββββ΄βββββ β
β β
β Sort values: 10, 20, 30, 40, 60, 70, 80, 90, 255 β
β Median: 60 (5th value) β
β β
β Result: β
β ββββββ¬βββββ¬βββββ β
β β β β β β
β ββββββΌβββββΌβββββ€ β
β β β 60 β β β Noise removed β
β ββββββΌβββββΌβββββ€ β
β β β β β β
β ββββββ΄βββββ΄βββββ β
β β
β Features: β
β - Very effective for salt-and-pepper noise β
β - Preserves edges relatively well β
β - Slower than average/Gaussian β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Usage¶
import cv2
import numpy as np
img = cv2.imread('image.jpg')
# Add salt-and-pepper noise (for testing)
def add_salt_pepper_noise(img, amount=0.05):
noisy = img.copy()
h, w = img.shape[:2]
num_pixels = int(amount * h * w)
# Salt (white)
for _ in range(num_pixels):
y, x = np.random.randint(0, h), np.random.randint(0, w)
noisy[y, x] = 255
# Pepper (black)
for _ in range(num_pixels):
y, x = np.random.randint(0, h), np.random.randint(0, w)
noisy[y, x] = 0
return noisy
noisy_img = add_salt_pepper_noise(img, 0.02)
# medianBlur(src, ksize)
# ksize: Only odd numbers allowed (3, 5, 7, ...)
median_3 = cv2.medianBlur(noisy_img, 3)
median_5 = cv2.medianBlur(noisy_img, 5)
# Compare: average blur, Gaussian blur
avg_blur = cv2.blur(noisy_img, (5, 5))
gauss_blur = cv2.GaussianBlur(noisy_img, (5, 5), 0)
cv2.imshow('Noisy', noisy_img)
cv2.imshow('Average Blur', avg_blur)
cv2.imshow('Gaussian Blur', gauss_blur)
cv2.imshow('Median Blur', median_5)
cv2.waitKey(0)
cv2.destroyAllWindows()
5. Bilateral Filter - bilateralFilter()¶
What is Bilateral Filter?¶
Bilateral filter smooths while preserving edges. Used for skin retouching, artistic effects, etc.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Bilateral Filter Principle β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Regular Gaussian filter: β
β - Only considers distance β edges also blurred β
β β
β Bilateral filter: β
β - Considers both distance (spatial) + color difference β
β - Only includes similar-colored pixels in average β
β - Preserves edges (where color difference is large) β
β β
β Example: β
β βββββββββββββββββββββββββββββββββββββββββββ β
β β 100 100 100 β 200 200 200 β β β
β β 100 100 100 β 200 200 200 β β Edge β β
β β 100 100 100 β 200 200 200 β β β
β βββββββββββββββββββββββββββββββββββββββββββ β
β β
β Gaussian: 100 and 200 mix to around 150 β
β Bilateral: 100 area stays 100, 200 area stays 200 β
β β
β Weight = spatial Gaussian Γ color Gaussian β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Usage¶
import cv2
img = cv2.imread('portrait.jpg')
# bilateralFilter(src, d, sigmaColor, sigmaSpace)
# d: Filter size (-1 = auto-calculate from sigmaSpace)
# sigmaColor: Sigma in color space (higher = average wider color range)
# sigmaSpace: Sigma in coordinate space (higher = consider wider area)
# Weak effect
bilateral_weak = cv2.bilateralFilter(img, 9, 50, 50)
# Medium effect
bilateral_medium = cv2.bilateralFilter(img, 9, 75, 75)
# Strong effect (painting-like)
bilateral_strong = cv2.bilateralFilter(img, 15, 100, 100)
# Very strong effect
bilateral_extreme = cv2.bilateralFilter(img, 15, 150, 150)
Skin Smoothing Example¶
import cv2
import numpy as np
def skin_smoothing(img, strength='medium'):
"""Skin smoothing effect"""
params = {
'weak': (5, 30, 30),
'medium': (9, 75, 75),
'strong': (15, 100, 100),
'extreme': (20, 150, 150)
}
d, sigmaColor, sigmaSpace = params.get(strength, params['medium'])
# Apply bilateral filter
smooth = cv2.bilateralFilter(img, d, sigmaColor, sigmaSpace)
# Blend with original (natural effect)
alpha = 0.7 # Blending ratio
result = cv2.addWeighted(smooth, alpha, img, 1 - alpha, 0)
return result
img = cv2.imread('portrait.jpg')
result = skin_smoothing(img, 'medium')
cv2.imshow('Original', img)
cv2.imshow('Smoothed', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
Blur Filter Comparison¶
import cv2
import time
import matplotlib.pyplot as plt
img = cv2.imread('image.jpg')
# Compare processing time
filters = []
start = time.time()
avg = cv2.blur(img, (9, 9))
filters.append(('Average', avg, time.time() - start))
start = time.time()
gauss = cv2.GaussianBlur(img, (9, 9), 0)
filters.append(('Gaussian', gauss, time.time() - start))
start = time.time()
median = cv2.medianBlur(img, 9)
filters.append(('Median', median, time.time() - start))
start = time.time()
bilateral = cv2.bilateralFilter(img, 9, 75, 75)
filters.append(('Bilateral', bilateral, time.time() - start))
# Visualization
fig, axes = plt.subplots(2, 2, figsize=(12, 12))
axes = axes.flatten()
for ax, (name, result, elapsed) in zip(axes, filters):
ax.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
ax.set_title(f'{name} ({elapsed*1000:.1f}ms)')
ax.axis('off')
plt.tight_layout()
plt.show()
6. Custom Filter - filter2D()¶
filter2D() Usage¶
filter2D() allows performing convolution with custom-defined kernels.
import cv2
import numpy as np
img = cv2.imread('image.jpg')
# filter2D(src, ddepth, kernel)
# ddepth: Output image depth (-1 = same as input)
# kernel: User-defined kernel
# Create and apply average filter manually
kernel_avg = np.ones((5, 5), np.float32) / 25
avg_custom = cv2.filter2D(img, -1, kernel_avg)
# Same result as blur()
avg_builtin = cv2.blur(img, (5, 5))
print(f"Difference: {np.sum(np.abs(avg_custom - avg_builtin))}") # 0
Various Custom Kernels¶
import cv2
import numpy as np
img = cv2.imread('image.jpg')
# 1. Emboss effect
kernel_emboss = np.array([
[-2, -1, 0],
[-1, 1, 1],
[ 0, 1, 2]
])
emboss = cv2.filter2D(img, -1, kernel_emboss) + 128
# 2. Edge detection (Laplacian)
kernel_laplacian = np.array([
[0, 1, 0],
[1, -4, 1],
[0, 1, 0]
])
laplacian = cv2.filter2D(img, -1, kernel_laplacian)
# 3. Sobel X (vertical edges)
kernel_sobel_x = np.array([
[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]
])
sobel_x = cv2.filter2D(img, -1, kernel_sobel_x)
# 4. Sobel Y (horizontal edges)
kernel_sobel_y = np.array([
[-1, -2, -1],
[ 0, 0, 0],
[ 1, 2, 1]
])
sobel_y = cv2.filter2D(img, -1, kernel_sobel_y)
Kernel Visualization Tool¶
import cv2
import numpy as np
import matplotlib.pyplot as plt
def apply_and_show_kernel(img, kernel, title):
"""Visualize kernel application result and kernel"""
result = cv2.filter2D(img, -1, kernel)
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
# Original
axes[0].imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
axes[0].set_title('Original')
axes[0].axis('off')
# Kernel visualization
im = axes[1].imshow(kernel, cmap='RdBu_r', vmin=-2, vmax=2)
axes[1].set_title(f'Kernel ({kernel.shape[0]}x{kernel.shape[1]})')
for i in range(kernel.shape[0]):
for j in range(kernel.shape[1]):
axes[1].text(j, i, f'{kernel[i,j]:.1f}',
ha='center', va='center', fontsize=10)
plt.colorbar(im, ax=axes[1])
# Result
axes[2].imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB))
axes[2].set_title(title)
axes[2].axis('off')
plt.tight_layout()
plt.show()
img = cv2.imread('image.jpg')
# Example: Emboss kernel
kernel_emboss = np.array([
[-2, -1, 0],
[-1, 1, 1],
[ 0, 1, 2]
], dtype=np.float32)
apply_and_show_kernel(img, kernel_emboss, 'Emboss')
7. Sharpening Filter¶
Sharpening Principle¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Sharpening Principle β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Sharpening = Original + (Original - Blur) β
β = Original + High-frequency component β
β = Edge enhancement β
β β
β Or directly with kernel: β
β β
β Basic sharpening kernel: β
β ββββββ¬βββββ¬βββββ β
β β 0 β -1 β 0 β β
β ββββββΌβββββΌβββββ€ β
β β -1 β 5 β -1 β Center = 5 (original weight) β
β ββββββΌβββββΌβββββ€ Surrounding = -1 (subtract blur) β
β β 0 β -1 β 0 β Sum = 1 (preserve brightness) β
β ββββββ΄βββββ΄βββββ β
β β
β Strong sharpening kernel: β
β ββββββ¬βββββ¬βββββ β
β β -1 β -1 β -1 β β
β ββββββΌβββββΌβββββ€ β
β β -1 β 9 β -1 β Center = 9 β
β ββββββΌβββββΌβββββ€ Surrounding = -1 Γ 8 = -8 β
β β -1 β -1 β -1 β Sum = 1 β
β ββββββ΄βββββ΄βββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Sharpening Implementation¶
import cv2
import numpy as np
img = cv2.imread('image.jpg')
# Method 1: Using kernel
kernel_sharpen = np.array([
[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]
])
sharpened1 = cv2.filter2D(img, -1, kernel_sharpen)
# Method 2: Strong sharpening kernel
kernel_sharpen_strong = np.array([
[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]
])
sharpened2 = cv2.filter2D(img, -1, kernel_sharpen_strong)
# Method 3: Unsharp Masking
def unsharp_mask(img, kernel_size=(5, 5), sigma=1.0, amount=1.0, threshold=0):
"""
Sharpening with unsharp masking
amount: Sharpening strength (1.0 = standard)
threshold: Edge detection threshold (noise prevention)
"""
# Blurred image
blurred = cv2.GaussianBlur(img, kernel_size, sigma)
# Original - Blur = Edges/Details
# sharpened = Original + amount Γ (Original - Blur)
sharpened = cv2.addWeighted(img, 1 + amount, blurred, -amount, 0)
if threshold > 0:
# Keep original for pixels with change below threshold
diff = cv2.absdiff(img, blurred)
mask = (diff < threshold).astype(np.uint8) * 255
sharpened = np.where(mask == 255, img, sharpened)
return sharpened
sharpened3 = unsharp_mask(img, amount=1.5)
Adaptive Sharpening¶
import cv2
import numpy as np
def adaptive_sharpening(img, amount=1.0):
"""
Adaptive sharpening - apply sharpening only to edge regions
"""
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Edge detection
edges = cv2.Canny(gray, 50, 150)
edges = cv2.dilate(edges, np.ones((3, 3), np.uint8), iterations=1)
# Blur
blurred = cv2.GaussianBlur(img, (5, 5), 1)
# Sharpening
sharpened = cv2.addWeighted(img, 1 + amount, blurred, -amount, 0)
# Apply sharpening only to edge regions
edges_3ch = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR) / 255.0
result = (sharpened * edges_3ch + img * (1 - edges_3ch)).astype(np.uint8)
return result
img = cv2.imread('image.jpg')
result = adaptive_sharpening(img, amount=2.0)
8. Practice Problems¶
Exercise 1: Noise Removal Comparison¶
Generate Gaussian noise and salt-and-pepper noise separately, and compare the removal effects with three blur filters (average, Gaussian, median). Perform quantitative comparison using PSNR values.
# Hint: Add Gaussian noise
def add_gaussian_noise(img, mean=0, var=100):
noise = np.random.normal(mean, var**0.5, img.shape)
noisy = np.clip(img + noise, 0, 255).astype(np.uint8)
return noisy
Exercise 2: Real-Time Blur Intensity Control¶
Write a program that can adjust blur intensity (kernel size) with a trackbar on webcam video. Allow selection between Gaussian blur and bilateral filter.
Exercise 3: Custom Emboss Directions¶
Design and test kernels that produce different emboss effects in 8 directions (up, down, left, right, and 4 diagonals).
Exercise 4: Advanced Sharpening¶
Implement an advanced sharpening function with the following features: 1. Sharpening strength control (amount) 2. Blur radius control (radius) 3. Threshold application - ignore small changes 4. Separate handling for highlights/shadows
Exercise 5: Miniature Effect (Tilt Shift)¶
Implement tilt-shift miniature effect using Gaussian blur and masks. Keep the center of the image sharp, with progressively more blur at top and bottom.
# Hint
def tilt_shift(img, focus_y, focus_height, blur_amount):
# Create gradient mask
# Blend blurred and original images using mask
pass
9. Next Steps¶
In 06_Morphology.md, you'll learn morphological operations such as erosion, dilation, opening/closing!
Next topics: - Structuring Element - Erosion and Dilation - Opening and Closing - Noise removal and object separation
10. References¶
Official Documentation¶
- blur() documentation
- GaussianBlur() documentation
- medianBlur() documentation
- bilateralFilter() documentation
Related Learning Materials¶
| Folder | Related Content |
|---|---|
| 04_Geometric_Transforms.md | Image preprocessing |
| 08_Edge_Detection.md | Edge detection after filtering |