Kernels & Convolution

What is a Kernel?

A kernel (or filter) is a small matrix used to apply effects to an image.

Examples:

Size: Usually small (3×3, 5×5, 7×7) and odd-sized
Purpose: Define how to combine neighborhood pixels

What is Convolution?

Convolution is sliding a kernel over an image and computing weighted sums.

Process:

  1. Place kernel on image region
  2. Multiply corresponding elements
  3. Sum all products
  4. Result = new pixel value
  5. Slide kernel to next position

Formula: Output(x,y) = Σ Kernel(i,j) × Image(x+i, y+j)

Convolution Example

Result: One output pixel value = -60

Edge Handling

Problem: Kernel extends beyond image border

Solutions:

  • Zero padding: Add zeros around border
  • Border replication: Repeat edge pixels
  • Reflection: Mirror border pixels
  • Wrap around: Opposite edge wraps

OpenCV default: Reflection (cv2.BORDER_REFLECT_101)

Custom Convolution in OpenCV

  1. import cv2
  2. import numpy as np
  3. # define a 3x3 identity kernel
  4. kernel = np.array([[0, 0, 0],
  5. [0, 1, 0],
  6. [0, 0, 0]], dtype=np.float32)
  7. # apply convolution
  8. result = cv2.filter2D(img, -1, kernel)
  9. #ans: -1 means output same depth as input
  10. # identity kernel returns original image
  11. #ans: center weight=1, others=0, no change

Box Blur Kernel

  1. # 3x3 averaging kernel
  2. kernel = np.ones((3, 3), dtype=np.float32) / 9
  3. #ans: all weights = 1/9, sums to 1
  4. # apply box blur
  5. blurred = cv2.filter2D(img, -1, kernel)
  6. #ans: same as cv2.blur(img, (3, 3))
  7. # 5x5 box blur kernel
  8. kernel = np.ones((5, 5), dtype=np.float32) / 25
  9. result = cv2.filter2D(img, -1, kernel)
  10. #ans: averages 25 pixels, more blur

Sharpening Kernel

  1. # sharpen kernel (enhances edges)
  2. kernel = np.array([[ 0, -1, 0],
  3. [-1, 5, -1],
  4. [ 0, -1, 0]], dtype=np.float32)
  5. #ans: center=5, neighbors=-1, enhances differences
  6. sharpened = cv2.filter2D(img, -1, kernel)
  7. #ans: edges become more pronounced
  8. # why does this sharpen?
  9. #ans: amplifies center, subtracts neighbors (enhances edges)

Edge Detection Kernels

  1. # horizontal edge detection (Prewitt)
  2. kernel_h = np.array([[-1, -1, -1],
  3. [ 0, 0, 0],
  4. [ 1, 1, 1]], dtype=np.float32)
  5. #ans: detects horizontal edges (top-bottom transition)
  6. # vertical edge detection
  7. kernel_v = np.array([[-1, 0, 1],
  8. [-1, 0, 1],
  9. [-1, 0, 1]], dtype=np.float32)
  10. #ans: detects vertical edges (left-right transition)
  11. edges_h = cv2.filter2D(gray, -1, kernel_h)
  12. edges_v = cv2.filter2D(gray, -1, kernel_v)
  13. #ans: apply to grayscale for best results

Gaussian Kernel

  1. # 5x5 gaussian kernel approximation
  2. kernel = np.array([[1, 4, 6, 4, 1],
  3. [4, 16, 24, 16, 4],
  4. [6, 24, 36, 24, 6],
  5. [4, 16, 24, 16, 4],
  6. [1, 4, 6, 4, 1]], dtype=np.float32) / 256
  7. #ans: weights decrease from center (gaussian distribution)
  8. gaussian = cv2.filter2D(img, -1, kernel)
  9. #ans: similar to cv2.GaussianBlur but custom kernel

Kernel Normalization

Why normalize? Keep output in valid range (0-255)

Formula: Divide by sum of kernel weights

  1. # unnormalized kernel
  2. kernel = np.array([[1, 2, 1],
  3. [2, 4, 2],
  4. [1, 2, 1]], dtype=np.float32)
  5. # sum of weights
  6. kernel_sum = kernel.sum() # = 16
  7. #ans: sum = 1+2+1+2+4+2+1+2+1 = 16
  8. # normalize
  9. kernel_norm = kernel / kernel_sum
  10. #ans: ensures output stays in range

Exercises - Part 1 (Concepts)

  1. # what does convolution do?
  2. #ans: slides kernel over image, computes weighted sums
  3. # why odd kernel sizes?
  4. #ans: needs center pixel for symmetry
  5. # what is identity kernel?
  6. kernel = np.array([[0, 0, 0],
  7. [0, 1, 0],
  8. [0, 0, 0]])
  9. #ans: returns original image (no change)
  10. # what does sum of weights=1 ensure?
  11. #ans: preserves brightness, no amplification

Exercises - Part 2 (Concepts)

  1. # what detects vertical edges?
  2. #ans: kernel with [-1, 0, 1] pattern horizontally
  3. # what is cv2.filter2D ddepth parameter?
  4. result = cv2.filter2D(img, -1, kernel)
  5. #ans: -1 means same depth as source
  6. # difference between blur and sharpen kernels?
  7. #ans: blur averages (positive weights), sharpen enhances (negative neighbors)
  8. # why apply edge detection on grayscale?
  9. #ans: simpler, one channel, intensity changes are edges

Exercises - Part 3 (Coding)

  1. # create 3x3 identity kernel
  2. #ans: kernel = np.array([[0, 0, 0],
  3. #ans: [0, 1, 0],
  4. #ans: [0, 0, 0]], dtype=np.float32)
  5. # apply identity kernel
  6. #ans: result = cv2.filter2D(img, -1, kernel)
  7. # create 3x3 box blur kernel
  8. #ans: kernel = np.ones((3, 3), dtype=np.float32) / 9
  9. #ans: result = cv2.filter2D(img, -1, kernel)

Exercises - Part 4 (Coding)

  1. # create sharpen kernel
  2. #ans: kernel = np.array([[ 0, -1, 0],
  3. #ans: [-1, 5, -1],
  4. #ans: [ 0, -1, 0]], dtype=np.float32)
  5. # apply sharpen
  6. #ans: sharpened = cv2.filter2D(img, -1, kernel)
  7. # create horizontal edge kernel
  8. #ans: kernel = np.array([[-1, -1, -1],
  9. #ans: [ 0, 0, 0],
  10. #ans: [ 1, 1, 1]], dtype=np.float32)

Exercises - Part 5 (Coding)

  1. # create emboss kernel
  2. #ans: kernel = np.array([[-2, -1, 0],
  3. #ans: [-1, 1, 1],
  4. #ans: [ 0, 1, 2]], dtype=np.float32)
  5. #ans: embossed = cv2.filter2D(gray, -1, kernel)
  6. # create outline kernel
  7. #ans: kernel = np.array([[-1, -1, -1],
  8. #ans: [-1, 8, -1],
  9. #ans: [-1, -1, -1]], dtype=np.float32)
  10. #ans: outline = cv2.filter2D(img, -1, kernel)

Exercises - Part 6 (Mixed)

  1. # normalize a custom kernel
  2. kernel = np.array([[1, 2, 1],
  3. [2, 4, 2],
  4. [1, 2, 1]], dtype=np.float32)
  5. #ans: kernel_norm = kernel / kernel.sum()
  6. #ans: sum = 16, so divide by 16
  7. # what is the sum after normalization?
  8. #ans: 1.0 (preserves brightness)
  9. # create strong sharpen (center=9)
  10. #ans: kernel = np.array([[ 0, -1, 0],
  11. #ans: [-1, 9, -1],
  12. #ans: [ 0, -1, 0]], dtype=np.float32)

Exercises - Part 7 (Mixed)

  1. # 5x5 average kernel
  2. #ans: kernel = np.ones((5, 5), dtype=np.float32) / 25
  3. # left edge detection
  4. #ans: kernel = np.array([[1, 0, -1],
  5. #ans: [2, 0, -2],
  6. #ans: [1, 0, -1]], dtype=np.float32)
  7. #ans: this is Sobel-X kernel
  8. # combine two edge detections
  9. edges_h = cv2.filter2D(gray, -1, kernel_h)
  10. edges_v = cv2.filter2D(gray, -1, kernel_v)
  11. #ans: edges = cv2.addWeighted(edges_h, 0.5, edges_v, 0.5, 0)
  12. #ans: combines horizontal and vertical edges

Exercises - Part 8 (Advanced)

  1. # motion blur kernel (horizontal)
  2. #ans: kernel = np.zeros((5, 5), dtype=np.float32)
  3. #ans: kernel[2, :] = 1/5
  4. #ans: horizontal motion blur effect
  5. # apply convolution with border handling
  6. #ans: result = cv2.filter2D(img, -1, kernel, borderType=cv2.BORDER_CONSTANT)
  7. # create custom gaussian-like kernel
  8. #ans: kernel = np.array([[1, 2, 1],
  9. #ans: [2, 4, 2],
  10. #ans: [1, 2, 1]], dtype=np.float32) / 16

Google tag (gtag.js)