【进阶】基于一阶导数的~
基于一阶导数的边缘检测算子(算法),是利用图像在边缘处的阶跃性,即图像梯度在边缘取得极大值的特性进行边缘检测。梯度是一个矢量,它具有方向θ和模|ΔI|:

梯度方向始终是垂直于边缘方向,梯度的模值大小提供了边缘的强度信息。
在实际使用中,通常利用有限差分进行梯度近似。对于上面的公式,我们有如下的近似:

了解上述原理之后就可以介绍如下几种常见的一阶边缘检测算子了。
1. Roberts 算法
1963年,Roberts提出了这种寻找边缘的算子。Roberts边缘算子是一个2x2的模板,采用的是对角方向相邻的两个像素之差,所以也被称为交叉微分算法。从图像处理的实际效果来看,边缘定位较准,对噪声敏感。在Roberts检测算子中:

可以的出Roberts算子的水平与竖直边缘检测卷积核为:

算法构造
import cv2
import numpy as np
def Roberts(img):
h, w = img.shape[0:2] # 切片操作 获取图像高和宽 切片操作:[start:stop:step]
_Roberts = np.zeros((h, w), dtype=img.dtype)
# 求微分,获得新的图像矩阵
for i in range(h - 1):
for j in range(w - 1):
dx = int(img[i, j]) - int(img[i + 1, j + 1])
dy = int(img[i, j + 1]) - int(img[i + 1, j])
_Roberts[i, j] = np.sqrt(dx ** 2 + dy ** 2)
return _Roberts # 返回一个二维的图像矩阵
image = cv2.imread("tyut_logo.png")
image = cv2.resize(image, (512, 512))
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转化为灰度图
blur = cv2.GaussianBlur(gray, (7, 7), 0) # 高斯滤波 图像去噪
ret, thresh1 = cv2.threshold(blur, 127, 255, cv2.THRESH_BINARY) # 二进制阈值化
result = Roberts(thresh1) # 调用Roberts算法函数进行图像轮廓提取
cv2.imshow('gray', gray)
cv2.imshow('roberts', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行效果如下图:

45°很清晰很明显, 从卷积核你能得出什么结论?
2. Prewitt算法
Prewitt算子利用周围邻域8个点的灰度值来估计中心的梯度,它的梯度计算公式如下:

算法构造
import cv2
import numpy as np
def Prewitt(img):
h, w = img.shape[0:2]
_Prewitt = np.zeros((h, w), dtype=img.dtype)
for i in range(h - 1):
for j in range(w - 1):
dx = (int(img[i - 1, j + 1]) + int(img[i, j + 1]) + int(img[i + 1, j + 1])) - (int(img[i - 1, j - 1]) + int(img[i, j - 1]) + int(img[i + 1, j - 1]))
dy = (int(img[i + 1, j - 1]) + int(img[i + 1, j]) + int(img[i + 1, j + 1])) - (int(img[i - 1, j - 1]) + int(img[i - 1, j]) + int(img[i + 1, j + 1]))
_Prewitt[i, j] = np.sqrt(dx ** 2 + dy ** 2)
return _Prewitt
image = cv2.imread("tyut_logo.png")
image = cv2.resize(image, (512, 512))
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7, 7), 0)
ret, thresh1 = cv2.threshold(blur, 127, 255, cv2.THRESH_BINARY)
result = Prewitt(thresh1)
cv2.imshow('gray', gray)
cv2.imshow('prewitt', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行效果如下图:

0°,45°,90°很清晰很明显,从卷积核形式你能得出什么结论?
3. Sobel算法
比起Prewitt算子,Sobel [ˈsoʊbəl] 算子也是用周围8个像素来估计中心像素的梯度,但是Sobel算子认为靠近中心像素的点应该给予更高的权重,所以Sobel算子把与中心像素4邻接的像素的权重设置为2或-2。

算法构造
import cv2
import numpy as np
def Sobel(img):
h, w = img.shape[0:2]
_Sobel = np.zeros((h, w), dtype=img.dtype)
for i in range(h - 1):
for j in range(w - 1):
dx = (int(img[i - 1, j + 1]) + 2 * int(img[i, j + 1]) + int(img[i + 1, j + 1])) - (int(img[i - 1, j - 1]) + 2 * int(img[i, j - 1]) + int(img[i + 1, j - 1]))
dy = (int(img[i + 1, j - 1]) + 2 * int(img[i + 1, j]) + int(img[i + 1, j + 1])) - (int(img[i - 1, j - 1]) + 2 * int(img[i - 1, j]) + int(img[i - 1, j + 1]))
_Sobel[i, j] = np.sqrt(dx ** 2 + dy ** 2)
return _Sobel
image = cv2.imread("tyut_logo.png")
image = cv2.resize(image, (512, 512))
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (7, 7), 0)
ret, thresh1 = cv2.threshold(blur, 127, 255, cv2.THRESH_BINARY)
result = Sobel(thresh1)
cv2.imshow('gray', gray)
cv2.imshow('sobel', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行效果如下图:

由于Sobel算子强调 靠近中心像素的点应该给予更高的权重,所以在上下左右四个方向上的边缘非常明显。