Back to Labs

CVIP Lab

CVIP Lab – Edge Detection using OpenCV

Implement Sobel, Prewitt, and Canny edge detection operators using OpenCV and compare the results.

Objective

To implement edge detection using Sobel, Prewitt, and Canny operators in OpenCV and observe differences in edge maps for a given grayscale image. Edge detection is a fundamental operation in computer vision and image processing that identifies boundaries between different regions in an image.

This experiment helps students understand gradient-based edge detection methods, learn how different operators respond to image features, and compare the performance of various edge detection algorithms. Edge detection is crucial for object recognition, image segmentation, and feature extraction in computer vision applications.

Theory

Edge detection is based on the principle that edges correspond to rapid changes in image intensity. These changes can be detected by computing the gradient of the image. Different operators use different methods to approximate the gradient, resulting in varying edge detection performance.

  • Sobel operator: Uses two 3×3 kernels (Gx for horizontal edges, Gy for vertical edges) to approximate the gradient. The Sobel operator gives more weight to pixels closer to the center, making it less sensitive to noise than simple gradient operators. The magnitude of the gradient is computed as sqrt(Gx² + Gy²) or |Gx| + |Gy| for efficiency.
  • Prewitt operator: Similar to Sobel but with uniform weights in the kernels. It's simpler but more sensitive to noise. Prewitt operators are easier to understand and implement, making them good for educational purposes. They use 3×3 kernels with values of -1, 0, and 1.
  • Canny operator: Multi-stage algorithm that provides superior edge detection results. The algorithm includes: (1) Gaussian smoothing to reduce noise, (2) gradient calculation using Sobel operators, (3) non-maximal suppression to thin edges, (4) double thresholding to identify strong and weak edges, and (5) edge tracking by hysteresis to connect weak edges to strong edges. Canny produces cleaner, more continuous edges compared to simple gradient-based methods.

Algorithm Steps (Detailed)

  1. Read the input image – Load the image using cv2.imread() and convert to grayscale if it's a color image. Grayscale conversion simplifies processing and reduces computational complexity.
  2. Apply Gaussian blur – Use cv2.GaussianBlur() to reduce noise. Gaussian smoothing is essential before edge detection to minimize false edges caused by noise. Typical kernel size is 5×5 with standard deviation calculated automatically.
  3. Apply Sobel operator – Compute gradients in X and Y directions using cv2.Sobel() with appropriate parameters. Combine the gradients using cv2.magnitude() or by taking the absolute sum. Convert the result to 8-bit format for display.
  4. Apply Prewitt operator – Implement Prewitt kernels manually or use cv2.filter2D() with custom kernels. Prewitt can also be approximated using cv2.Sobel() with different kernel configurations, though true Prewitt uses uniform weights.
  5. Apply Canny edge detector – Use cv2.Canny() with two threshold values (low and high). The low threshold identifies weak edges, while the high threshold identifies strong edges. Typical values are 100 and 200, but they should be adjusted based on image characteristics.
  6. Display results – Show the original image, Sobel edges, Prewitt edges, and Canny edges side by side for comparison. Use cv2.imshow() or matplotlib for visualization.

Sample Python Code (Complete)


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

# Read and preprocess image
img = cv2.imread("image.jpg", 0)  # Read as grayscale
if img is None:
    print("Error: Could not read image")
    exit()

# Apply Gaussian blur to reduce noise
blur = cv2.GaussianBlur(img, (5, 5), 0)

# Sobel operator
sobelx = cv2.Sobel(blur, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(blur, cv2.CV_64F, 0, 1, ksize=3)
sobel = np.sqrt(sobelx**2 + sobely**2)
sobel = np.uint8(np.absolute(sobel))

# Prewitt operator (using custom kernels)
kernelx = np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]], dtype=np.float32)
kernely = np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1]], dtype=np.float32)
prewittx = cv2.filter2D(blur, cv2.CV_64F, kernelx)
prewitty = cv2.filter2D(blur, cv2.CV_64F, kernely)
prewitt = np.sqrt(prewittx**2 + prewitty**2)
prewitt = np.uint8(np.absolute(prewitt))

# Canny edge detector
edges_canny = cv2.Canny(blur, 100, 200)

# Display results
plt.figure(figsize=(12, 8))
plt.subplot(2, 2, 1), plt.imshow(img, cmap='gray')
plt.title('Original Image'), plt.axis('off')
plt.subplot(2, 2, 2), plt.imshow(sobel, cmap='gray')
plt.title('Sobel Edges'), plt.axis('off')
plt.subplot(2, 2, 3), plt.imshow(prewitt, cmap='gray')
plt.title('Prewitt Edges'), plt.axis('off')
plt.subplot(2, 2, 4), plt.imshow(edges_canny, cmap='gray')
plt.title('Canny Edges'), plt.axis('off')
plt.tight_layout()
plt.show()

Expected Results and Observations

After running the code, you should observe:

  • Sobel edges: Generally good edge detection with moderate noise sensitivity. Edges are reasonably sharp but may include some noise. Sobel performs well for most applications and is computationally efficient.
  • Prewitt edges: Similar to Sobel but typically more sensitive to noise. Edges may be slightly thicker and less precise. Prewitt is simpler but generally produces lower quality results than Sobel.
  • Canny edges: Cleanest and most continuous edges with minimal noise. Edges are thin and well-defined. Canny typically produces the best visual results but is more computationally expensive than Sobel or Prewitt.

Comparison Table

Operator Noise Sensitivity Edge Quality Computational Cost Best Use Case
Sobel Low to Medium Good Low General purpose edge detection
Prewitt Medium Fair Low Educational purposes, simple applications
Canny Very Low Excellent High High-quality edge detection, critical applications

Result

Attach screenshots comparing Sobel, Prewitt, and Canny edge maps. Comment on the sharpness of edges, noise sensitivity, edge continuity, and computational requirements. Discuss which operator would be best for different applications (real-time processing, high-quality analysis, etc.).

Viva Questions

  • What is the difference between Sobel and Prewitt operators?
  • Why is Gaussian blur applied before edge detection?
  • What are the advantages of Canny edge detector over Sobel?
  • How do you choose threshold values for Canny edge detection?
  • What is non-maximal suppression in Canny algorithm?

Frequently Asked Questions

Q1: Why do we convert images to grayscale for edge detection?

Grayscale simplifies processing by reducing the image to a single channel. Edge detection is based on intensity changes, which are easier to detect in grayscale. Color information isn't necessary for edge detection and adds computational complexity.

Q2: What happens if we don't apply Gaussian blur before edge detection?

Without blurring, noise in the image will be detected as edges, resulting in many false positives. Gaussian blur smooths the image, reducing noise while preserving important edges, leading to cleaner edge detection results.

Q3: How do I choose the right threshold values for Canny edge detection?

Threshold values depend on image characteristics. Start with a ratio of 1:2 or 1:3 between low and high thresholds. Adjust based on desired edge sensitivity – lower thresholds detect more edges (including noise), higher thresholds detect only strong edges. Experiment with different values and visually inspect results.