Denoising Methods in Image Preprocessing (Python OpenCV Introduction)

I. Why Denoising?

Images often suffer from noise during acquisition or transmission, such as:
- Gaussian Noise: Random bright spots resembling “salt grains” (high-frequency noise, common in sensors);
- Salt-and-Pepper Noise: Black and white specks (e.g., camera sensor dust, 0 or 255 pixel values due to transmission errors);
- Poisson Noise: Random noise related to image brightness (common in low-light environments).

Noise blurs image details and reduces accuracy in subsequent tasks (e.g., object detection, face recognition). Denoising is a core step in image preprocessing, aiming to remove interference while preserving useful information.

II. Python OpenCV Setup

First, install OpenCV, NumPy, and Matplotlib:

pip install opencv-python numpy matplotlib

Core operations:
- Read image: cv2.imread() (default BGR format, convert to RGB for display);
- Display image: cv2.imshow() (requires cv2.waitKey() and cv2.destroyAllWindows());
- Utility tools: np.array for noise generation, matplotlib for visualization.

III. Classic Denoising Methods & Code Implementation

1. Mean Filtering (Simple Averaging)

Principle: A small window (e.g., 3×3) covers the image, and the average of all pixels in the window replaces the center pixel.
Characteristics: Simple and fast but blurs edges (due to averaging), suitable for Gaussian noise (high-frequency random noise).

import cv2
import numpy as np
import matplotlib.pyplot as plt

# Read image (example: replace 'input.jpg' with your image path)
img = cv2.imread('input.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # Convert to RGB for matplotlib

# Generate Gaussian noise (simulate noise)
noise = np.random.normal(0, 20, img.shape).astype(np.uint8)
noisy_img = cv2.add(img, noise)  # Overlay noise

# Mean filtering (3×3 kernel)
mean_denoised = cv2.blur(noisy_img, (3, 3))  # Kernel size must be integers

# Visual comparison
plt.figure(figsize=(12, 6))
plt.subplot(131), plt.imshow(img_rgb), plt.title('Original')
plt.subplot(132), plt.imshow(noisy_img), plt.title('Noisy')
plt.subplot(133), plt.imshow(mean_denoised), plt.title('Mean Filter')
plt.show()
2. Median Filtering (Salt-and-Pepper Noise Solution)

Principle: Replace the center pixel with the median (middle value after sorting) of window pixels, which is insensitive to extreme values (e.g., 0/255 noise points).
Characteristics: Excellent for salt-and-pepper noise, strong edge preservation, kernel size must be odd (e.g., 3, 5).

# Generate salt-and-pepper noise
def add_salt_pepper_noise(img, prob=0.02):
    noisy = np.copy(img)
    h, w = noisy.shape[:2]
    for i in range(h):
        for j in range(w):
            if np.random.random() < prob:
                noisy[i, j] = 0 if np.random.random() < 0.5 else 255  # 50% chance black/white
    return noisy

noisy_salt = add_salt_pepper_noise(img_rgb)  # Process after converting to RGB
median_denoised = cv2.medianBlur(noisy_salt, 3)  # 3×3 kernel

# Visualization
plt.figure(figsize=(12, 6))
plt.subplot(131), plt.imshow(img_rgb), plt.title('Original')
plt.subplot(132), plt.imshow(noisy_salt), plt.title('Salt & Pepper Noise')
plt.subplot(133), plt.imshow(median_denoised), plt.title('Median Filter')
plt.show()
3. Gaussian Filtering (Intelligent Weighted Averaging)

Principle: Use a Gaussian distribution kernel (highest weight at the center) to average pixels, smoothing noise while preserving edges.
Characteristics: Smoother than mean filtering, suitable for Gaussian noise, requires kernel size (odd) and standard deviation sigma.

# Gaussian filtering (3×3 kernel, sigmaX=1)
gaussian_denoised = cv2.GaussianBlur(noisy_img, (3, 3), sigmaX=1)

# Visualization
plt.figure(figsize=(12, 6))
plt.subplot(131), plt.imshow(noisy_img), plt.title('Noisy')
plt.subplot(132), plt.imshow(cv2.cvtColor(gaussian_denoised, cv2.COLOR_BGR2RGB)), plt.title('Gaussian Filter')
plt.show()
4. Bilateral Filtering (Denoising + Edge Preservation)

Principle: Combines spatial distance (weighting by window proximity) and color similarity (higher weight for similar colors), preserving edges while removing noise.
Characteristics: Computationally expensive but effective for “high-frequency noise” with clear edges, ideal for scenes requiring edge preservation (e.g., faces, landscapes).

# Bilateral filtering (diameter=9, color sigma=75, space sigma=75)
bilateral_denoised = cv2.bilateralFilter(noisy_img, 9, 75, 75)

# Visualization
plt.figure(figsize=(12, 6))
plt.subplot(131), plt.imshow(noisy_img), plt.title('Noisy')
plt.subplot(132), plt.imshow(cv2.cvtColor(bilateral_denoised, cv2.COLOR_BGR2RGB)), plt.title('Bilateral Filter')
plt.show()

IV. Method Selection Guide

Noise Type Recommended Method Kernel Size Key Advantage
Gaussian Noise Gaussian Filter 3×3/5×5 Weighted averaging, edge preservation
Salt-and-Pepper Median Filter 3×3/5×5 Robust to extreme values, speck removal
Mixed Noise Gaussian → Median 3×3→3×3 Combines noise characteristics
High-Frequency Noise Bilateral Filter 5×5/9×9 Removes noise while preserving contours/textures

V. Summary

  • Mean Filter: Simple and fast but blurs edges;
  • Median Filter: “Salt-and-pepper noise killer” with strong edge preservation;
  • Gaussian Filter: Balances noise reduction and edge retention;
  • Bilateral Filter: Advanced denoising with edge preservation, suitable for high-precision tasks.

Beginners should start with Gaussian and Median Filters, choosing based on noise type (e.g., Gaussian for dark photos, Median for surveillance with speckles). Experiment with Bilateral Filter for detail optimization!

Exercise: Test different kernel sizes (e.g., 5×5) to observe denoising effects, and compare how the sigma parameter affects Gaussian filtering!

Xiaoye