1.3. Edge Detection#

An edge is a place of rapid change in the image intensity function, where gradients are introduced.

Partial derivatives of an image: for 2D function \(f(x, y)\), the partial derivative w.r.t. \(x\) is

\[ \frac{\partial f(x, y)}{\partial x}=\lim _{\varepsilon \rightarrow 0} \frac{f(x+\varepsilon, y)-f(x, y)}{\varepsilon} \]

For discrete data, we can approximate using finite differences:

\[ \frac{\partial f(x, y)}{\partial x}=\frac{f(x+1, y)-f(x, y)}{1} \]

Gradient \(\bigtriangledown f = (\frac{\partial f}{\partial x}, \frac{\partial f}{\partial y})\)#

../../../_images/gradient.jpg
../../../_images/operator.jpg

Gradient operators

Kernel size affects localization and noise sensitive.

Sobel and Laplacian operators#

Modules imported …

Hide code cell source
import cv2
import numpy as np
from matplotlib import pyplot as plt
from skimage import io as io_url
import importlib

import myfunc.mysubplot
importlib.reload(myfunc.mysubplot)

from myfunc.canny import non_max_suppression, double_threshold, hysteresis,sobel_filter,canny_detector
frame = io_url.imread('../images/lena.jpg', as_gray=True)

k = 3 # Kernel size
# Apply Gaussian filter to cancel the noise first
frame = cv2.GaussianBlur(frame,(5,5), sigmaX=1, sigmaY=1)
sobel_x = cv2.Sobel(frame,-1,1,0,ksize=k)
sobel_y = cv2.Sobel(frame,-1,0,1,ksize=k)
magnitude, angle = sobel_filter(frame)

laplacian = cv2.Laplacian(frame,-1,ksize=k)
data = 255*magnitude/magnitude.max()
data = data.astype(np.uint8)
ret,th = cv2.threshold(data.astype(np.uint8),0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

Here is a fancy way to subplot grayscale images

fig = plt.subplots(nrows=2, ncols=3, figsize=(16, 16))
titles = ['Original','Sobel X','Sobel Y','Gradient Magnitude','Gradient Magnitude after otsu thresholding','Laplacian']
images = [frame, np.abs(sobel_x)/np.abs(sobel_x).max(), np.abs(sobel_y)/np.abs(sobel_y).max(), magnitude, th, laplacian]
myfunc.mysubplot.subplots(images, titles, 2, 3)
../../../_images/2cbb1281272fdaf81394a5d0acf06ae6170cf634b42b722b0d2cfb08d393a2b9.png
Ha, nice plots!

The otsu thresholoding and other thresholding approaches could see this page

Canny Edge Detector#

A step-by-step link and my implementation

  • Noise reduction using Gaussian filter

  • Gradient calculation

  • Non-maximum suppression: thin the edges

  • Double threshold: weak, strong and uncertain positions

  • Edge Tracking by Hysteresis: are uncertain connnected with strong positions?

mag_thin = non_max_suppression(magnitude, angle)
t = 0.08

mag_th = double_threshold(mag_thin, t, 2*t)
res = canny_detector(frame, t, 2*t)

frame = 255*frame/frame.max()
edges = cv2.Canny(frame.astype('uint8'),60,120)

fig = plt.subplots(nrows=2, ncols=2, figsize=(8, 8))
titles = ['non maximum suppression','double thresholding', 'hysteresis', 'opecv canny']
images = [mag_thin, mag_th, res, edges]
mysubplot(images, titles, 2, 2)
../../../_images/0331c86259fcea903cef3ef14489fc508f373ccdba8c74fc3d6f207c5b2326ca.png