Quiz 2

Image Processing: Gradients, Filtering, Edge Detection, Frequency Domain, Histograms

762 words
4 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Image Processing: Gradients, Filtering, Edge Detection, Frequency Domain, Histograms ## 🎯 Learning Objectives - Compute image gradients and apply edge detection (Sobel, Canny) - Understand convolution filtering in spatial domain - Apply Fourier transform for frequency domain analysis - Use histogram equalization...

Image Processing: Gradients, Filtering, Edge Detection, Frequency Domain, Histograms

🎯 Learning Objectives

  • Compute image gradients and apply edge detection (Sobel, Canny)
  • Understand convolution filtering in spatial domain
  • Apply Fourier transform for frequency domain analysis
  • Use histogram equalization for contrast enhancement
  • Bridge classical image processing with deep learning

📋 Prerequisites

  • CNN Fundamentals (Week 1): Convolution operation
  • Basic calculus: Partial derivatives, gradients

1. 📖 Core Content

1.1 Intuition: Why Classical IP for DL?

Deep learning learns filters from data, but classical image processing provides:
  • Preprocessing: Normalize illumination, enhance contrast
  • Feature engineering: Edge features for medical/industrial imagery
  • Data augmentation: Filter-based augmentation
  • Understanding: Gradient-based explanations (Saliency maps)

1.2 Image Gradients and Edge Detection

python
# runnable
import cv2
import numpy as np
# Load image
img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
# Sobel gradients (x and y directions)
grad_x = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3)
grad_y = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3)
# Gradient magnitude and direction
magnitude = np.sqrt(grad_x**2 + grad_y**2)
direction = np.arctan2(grad_y, grad_x)
# Canny edge detection
edges = cv2.Canny(img, threshold1=50, threshold2=150)
print(f"Edge pixels: {np.sum(edges > 0)} of {edges.size}")

1.3 Frequency Domain Analysis

python
# runnable
import numpy as np
import cv2
img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
# Fourier transform
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)  # Center low frequencies
magnitude_spectrum = np.log(np.abs(fshift) + 1)
# High-pass filter (edge enhancement)
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
mask = np.ones((rows, cols), np.uint8)
r = 30  # Radius to block low frequencies
mask[crow-r:crow+r, ccol-r:ccol+r] = 0
fshift_filtered = fshift * mask
img_filtered = np.fft.ifft2(np.fft.ifftshift(fshift_filtered))
img_filtered = np.real(img_filtered)
print(f"High-pass filtered: preserves edges, removes smooth regions")

1.4 Histogram Equalization

python
# runnable
import cv2
import numpy as np
img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
# Global histogram equalization
equalized_global = cv2.equalizeHist(img)
# CLAHE (adaptive, prevents noise amplification)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
equalized_clahe = clahe.apply(img)
print(f"Original intensity range: [{img.min()}, {img.max()}]")
print(f"Equalized range: [{equalized_global.min()}, {equalized_global.max()}]")

1.5 Classical Filters in Deep Learning Pipelines

python
# runnable
import torch
import torch.nn.functional as F
# Sobel filter as PyTorch layer
class SobelFilter(torch.nn.Module):
    def __init__(self):
        super().__init__()
        # Sobel kernels
        sobel_x = torch.tensor([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1](/courses/bsda5006/notes/%5B-1%2C%200%2C%201%5D%2C%20%5B-2%2C%200%2C%202%5D%2C%20%5B-1%2C%200%2C%201)], dtype=torch.float32)
        sobel_y = torch.tensor([[-1, -2, -1], [0, 0, 0], [1, 2, 1](/courses/bsda5006/notes/%5B-1%2C%20-2%2C%20-1%5D%2C%20%5B0%2C%200%2C%200%5D%2C%20%5B1%2C%202%2C%201)], dtype=torch.float32)
        self.register_buffer('kernel_x', sobel_x.view(1, 1, 3, 3))
        self.register_buffer('kernel_y', sobel_y.view(1, 1, 3, 3))
    def forward(self, x):
        # x: (B, C, H, W), process each channel independently
        B, C, H, W = x.shape
        x = x.view(B*C, 1, H, W)
        grad_x = F.conv2d(x, self.kernel_x, padding=1)
        grad_y = F.conv2d(x, self.kernel_y, padding=1)
        magnitude = torch.sqrt(grad_x**2 + grad_y**2)
        return magnitude.view(B, C, H, W)

1.6 Why This Matters

Classical image processing is not obsolete — it's foundational. Modern architectures like Gabor filters in early vision layers, Fourier-based token mixing (FNet), and histogram-based preprocessing in medical imaging all build on these principles.

2. 📐 Key Formulas / Concepts

OperationFormulaApplication
Sobel XGx=[101202101]IG_x = \begin{bmatrix}-1&0&1\\-2&0&2\\-1&0&1\end{bmatrix} * IVertical edge detection
Sobel YGy=[121000121]IG_y = \begin{bmatrix}-1&-2&-1\\0&0&0\\1&2&1\end{bmatrix} * IHorizontal edge detection
Gradient magnitude$\G\
Fourier transformF(u,v)=f(x,y)ej2π(ux/M+vy/N)F(u,v) = \sum\sum f(x,y)e^{-j2\pi(ux/M + vy/N)}Frequency analysis
Histogram equalizationT(r)=0rp(w)dwT(r) = \int_0^r p(w)dwContrast enhancement

3. ⚠️ Common Pitfalls

Pitfall 1: Applying Filters Before Normalization

Mistake: Applying Sobel/Canny to unnormalized uint8 images without scaling. Why: The filter responses depend on intensity ranges. A bright image produces larger gradients than a dark one with the same edge content. Fix: Normalize image intensity (e.g., [0, 1]) before applying filters, or use gradient ratios.

Pitfall 2: Using Fourier Transform on Non-Periodic Images

Mistake: Applying FFT without windowing (Hamming/Hann). Why: The FFT assumes the image is periodic. Image boundaries create high-frequency artifacts (spectral leakage). Fix: Apply a window function before FFT: img_windowed = img * np.hanning(rows).reshape(-1, 1) * np.hanning(cols).

4. 📝 Practice Questions

Q1: An image has poor contrast — 80% of pixels are between [100, 120] out of [0, 255]. Which technique improves it?
Histogram equalization is designed for this. It redistributes pixel intensities to use the full [0, 255] range:
python
import cv2
equalized = cv2.equalizeHist(img)
For extreme cases (like this), use CLAHE (adaptive histogram equalization) which operates on local tiles and prevents noise amplification:
python
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
result = clahe.apply(img)

5. 🔗 Cross-References

Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.