How to resolve the algorithm Canny edge detector step by step in the Python programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Canny edge detector step by step in the Python programming language

Table of Contents

Problem Statement

Write a program that performs so-called canny edge detection on an image.

A possible algorithm consists of the following steps:

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Canny edge detector step by step in the Python programming language

Canny Edge Detection

This Python code implements the Canny edge detection algorithm, which is used to extract edges from images. Here's a detailed explanation:

  1. Import Necessary Libraries:

    • numpy for numerical operations
    • scipy.ndimage.filters for image filtering
    • scipy.misc for image input and output
  2. CannyEdgeDetector Function:

    • Inputs:
      • im: Input grayscale image as a NumPy array
      • blur (optional): Gaussian blur strength (default: 1)
      • highThreshold (optional): Upper threshold for edge detection (default: 91)
      • lowThreshold (optional): Lower threshold for edge detection (default: 31)
    • Steps:
      • Gaussian Blur: Applied to reduce noise in the input image (im).
      • Sobel Filters: Used to compute horizontal (im3h) and vertical (im3v) gradients.
      • Gradient and Direction: Calculated from the Sobel gradients.
      • Quantization: The gradient direction theta is quantized into five discrete values (0, 1, 2, 3, 4).
      • Non-Maximum Suppression: Suppresses pixels along edges that are not the local maxima in their direction.
      • Double Thresholding: Performs hysteresis thresholding to determine the final edge pixels.
        • Weak pixels: gradSup > lowThreshold
        • Strong pixels: gradSup > highThreshold
      • Edge Tracing with Hysteresis: Traces the edges based on the weak and strong pixels.
  3. Main Function:

    • Reads a grayscale image (test.jpg) using imread and converts it to NumPy array.
    • Applies the CannyEdgeDetector function to get the edges.
    • Displays the resulting edge image using imshow.

This code effectively identifies edges in the input image and is widely used in image processing for object detection, segmentation, and other tasks.

Source code in the python programming language

#!/bin/python
import numpy as np
from scipy.ndimage.filters import convolve, gaussian_filter
from scipy.misc import imread, imshow
	
def CannyEdgeDetector(im, blur = 1, highThreshold = 91, lowThreshold = 31):
	im = np.array(im, dtype=float) #Convert to float to prevent clipping values
 
	#Gaussian blur to reduce noise
	im2 = gaussian_filter(im, blur)

	#Use sobel filters to get horizontal and vertical gradients
	im3h = convolve(im2,[[-1,0,1],[-2,0,2],[-1,0,1]]) 
	im3v = convolve(im2,[[1,2,1],[0,0,0],[-1,-2,-1]])

	#Get gradient and direction
	grad = np.power(np.power(im3h, 2.0) + np.power(im3v, 2.0), 0.5)
	theta = np.arctan2(im3v, im3h)
	thetaQ = (np.round(theta * (5.0 / np.pi)) + 5) % 5 #Quantize direction

	#Non-maximum suppression
	gradSup = grad.copy()
	for r in range(im.shape[0]):
		for c in range(im.shape[1]):
			#Suppress pixels at the image edge
			if r == 0 or r == im.shape[0]-1 or c == 0 or c == im.shape[1] - 1:
				gradSup[r, c] = 0
				continue
			tq = thetaQ[r, c] % 4

			if tq == 0: #0 is E-W (horizontal)
				if grad[r, c] <= grad[r, c-1] or grad[r, c] <= grad[r, c+1]:
					gradSup[r, c] = 0
			if tq == 1: #1 is NE-SW
				if grad[r, c] <= grad[r-1, c+1] or grad[r, c] <= grad[r+1, c-1]:
					gradSup[r, c] = 0
			if tq == 2: #2 is N-S (vertical)
				if grad[r, c] <= grad[r-1, c] or grad[r, c] <= grad[r+1, c]:
					gradSup[r, c] = 0
			if tq == 3: #3 is NW-SE
				if grad[r, c] <= grad[r-1, c-1] or grad[r, c] <= grad[r+1, c+1]:
					gradSup[r, c] = 0

	#Double threshold
	strongEdges = (gradSup > highThreshold)

	#Strong has value 2, weak has value 1
	thresholdedEdges = np.array(strongEdges, dtype=np.uint8) + (gradSup > lowThreshold)

	#Tracing edges with hysteresis	
	#Find weak edge pixels near strong edge pixels
	finalEdges = strongEdges.copy()
	currentPixels = []
	for r in range(1, im.shape[0]-1):
		for c in range(1, im.shape[1]-1):	
			if thresholdedEdges[r, c] != 1:
				continue #Not a weak pixel
			
			#Get 3x3 patch	
			localPatch = thresholdedEdges[r-1:r+2,c-1:c+2]
			patchMax = localPatch.max()
			if patchMax == 2:
				currentPixels.append((r, c))
				finalEdges[r, c] = 1

	#Extend strong edges based on current pixels
	while len(currentPixels) > 0:
		newPix = []
		for r, c in currentPixels:
			for dr in range(-1, 2):
				for dc in range(-1, 2):
					if dr == 0 and dc == 0: continue
					r2 = r+dr
					c2 = c+dc
					if thresholdedEdges[r2, c2] == 1 and finalEdges[r2, c2] == 0:
						#Copy this weak pixel to final result
						newPix.append((r2, c2))
						finalEdges[r2, c2] = 1
		currentPixels = newPix

	return finalEdges

if __name__=="__main__":
	im = imread("test.jpg", mode="L") #Open image, convert to greyscale
	finalEdges = CannyEdgeDetector(im)
	imshow(finalEdges)


  

You may also check:How to resolve the algorithm Sierpinski arrowhead curve step by step in the AutoHotkey programming language
You may also check:How to resolve the algorithm Higher-order functions step by step in the Déjà Vu programming language
You may also check:How to resolve the algorithm Emirp primes step by step in the ALGOL 68 programming language
You may also check:How to resolve the algorithm First-class functions/Use numbers analogously step by step in the Rust programming language
You may also check:How to resolve the algorithm Apply a digital filter (direct form II transposed) step by step in the Raku programming language