目录
[二、Sobel 算子:基础梯度检测的扛把子](#二、Sobel 算子:基础梯度检测的扛把子)
[1. 原理速览](#1. 原理速览)
[2. 实战代码(直接复用)](#2. 实战代码(直接复用))
[3. 效果图表分析(图 1:Sobel 算子边缘检测效果对比)](#3. 效果图表分析(图 1:Sobel 算子边缘检测效果对比))
[三、Scharr 算子:Sobel 的 "增强版",边缘更锐利](#三、Scharr 算子:Sobel 的 “增强版”,边缘更锐利)
[1. 原理速览](#1. 原理速览)
[2. 实战代码(直接复用)](#2. 实战代码(直接复用))
[3. 效果图表分析(图 2:Sobel vs Scharr 边缘检测对比)](#3. 效果图表分析(图 2:Sobel vs Scharr 边缘检测对比))
[四、Laplacian 算子:二阶导数,检测 "所有方向边缘"](#四、Laplacian 算子:二阶导数,检测 “所有方向边缘”)
[1. 原理速览](#1. 原理速览)
[2. 实战代码(直接复用)](#2. 实战代码(直接复用))
[3. 效果图表分析(图 3:Laplacian 算子边缘检测效果)](#3. 效果图表分析(图 3:Laplacian 算子边缘检测效果))
[五、Canny 边缘检测:边缘检测的 "天花板"](#五、Canny 边缘检测:边缘检测的 “天花板”)
[1. 原理速览](#1. 原理速览)
[2. 实战代码(直接复用)](#2. 实战代码(直接复用))
[3. 效果图表分析(图 4:Canny 边缘检测效果 + 参数影响)](#3. 效果图表分析(图 4:Canny 边缘检测效果 + 参数影响))
前言
在上一篇 机器视觉实战教程中,我们搞定了图像基础操作、形态学变换等核心技能,而边缘检测作为计算机视觉中 "提取图像核心特征" 的关键一步,是实现目标识别、图像分割的必经之路!今天这篇,我们就把 Sobel、Scharr、Laplacian、Canny 这四大边缘检测算子扒得明明白白,代码直接复用,效果直观对比,看完就能上手!
一、边缘检测的核心逻辑
边缘是图像中像素值突变的区域,本质是灰度值的不连续性。OpenCV 提供的各类算子,核心都是通过 "卷积运算" 计算像素梯度(梯度越大,边缘越明显),不同算子的卷积核设计不同,检测效果也各有优劣。
二、Sobel 算子:基础梯度检测的扛把子
1. 原理速览
Sobel 算子分 X/Y 方向一阶导数计算:
- X 方向:检测垂直边缘(列像素变化);
- Y 方向:检测水平边缘(行像素变化)。由于像素梯度可能为负(超出 0-255 范围),需转换为 64 位浮点型保存,再取绝对值还原边缘信息。
2. 实战代码(直接复用)
python
'''# sobel算子'''
# cv2.Sobel(src, ddepth, dx, dy[, ksize[, scale[, delta[, borderType]]]])
# 参数:
# src:输入图像
# ddepth: 输出图像的深度(可以理解为数据类型),-1表示与原图像相同的深度
# dx,dy:当组合为dx=1,dy=0时求x方向的一阶导数,当组合为dx=0,dy=1时求y方向的一阶导数(如果同时为1,通常效果不佳)
# ksize:(可选参数)Sobel算子的大小,必须是1,3,5或者7,默认为3。
yuan = cv2.imread('yuan.png')
cv2.imshow('yuan',yuan)
cv2.waitKey(0)
# # x方向上的边缘
yuan_x = cv2.Sobel(yuan,-1,dx=1,dy=0)
cv2.imshow('yuan_x',yuan_x)
cv2.waitKey(0)
# x方向上的边缘,包括负数信息(右端),但显示不出来,因为范围是(0~255)
yuan_x_64 = cv2.Sobel(yuan,cv2.CV_64F,dx=1,dy=0)#默认uint8改为float64,可保存负数
cv2.imshow('yuan_x_64',yuan_x_64)
cv2.waitKey(0)
# #x方向上的边缘,包括负数信息,进行取绝对值的操作,右端的负值信息就可以显示出来了
yuan_x_full = cv2.convertScaleAbs(yuan_x_64)#转换为绝对值,负数转换为正数
cv2.imshow('yuan_x_full',yuan_x_full)
cv2.waitKey(0)
# # y方向上的边缘
yuan_y = cv2.Sobel(yuan,-1,dx=0,dy=1)
cv2.imshow('yuan_y',yuan_y)
cv2.waitKey(0)
# y方向上的边缘,包括负数信息(下端),但显示不出来,因为范围是(0~255)
yuan_y_64 = cv2.Sobel(yuan,cv2.CV_64F,dx=0,dy=1)#默认int8改为float64,可保存负数
yuan_y_full = cv2.convertScaleAbs(yuan_y_64)#转换为绝对值,负数转换为正数
cv2.imshow('yuan_y_full',yuan_y_full)
cv2.waitKey(0)
# #如果同时使用x,y方向的结果如何呢?(不建议使用)
yuan_xy = cv2.Sobel(yuan,-1,dx=1,dy=1)
cv2.imshow('yuan_xy',yuan_xy)
cv2.waitKey(100000)
# #使用图像加权运算组合x和y方向的2个边缘。
yuan_xy_full = cv2.addWeighted(yuan_x_full,1,yuan_y_full,1,0)
cv2.imshow('yuan_xy_full',yuan_xy_full)
cv2.waitKey(0)
# # #读取图像观看效果 sobel算子
zl = cv2.imread('zl.png',cv2.IMREAD_GRAYSCALE)#不用灰度试试效果
zl_x_64 = cv2.Sobel(zl,cv2.CV_64F,dx=1,dy=0)#默认int8改为float64,可保存负数
zl_x_full = cv2.convertScaleAbs(zl_x_64)#转换为绝对值,负数转换为正数
zl_y_64 = cv2.Sobel(zl,cv2.CV_64F,dx=0,dy=1)#默认int8改为float64,可保存负数
zl_y_full = cv2.convertScaleAbs(zl_y_64)#转换为绝对值,负数转换为正数
zl_xy_sobel_full = cv2.addWeighted(zl_x_full,1,zl_y_full,1,0)
cv2.imshow('zl_xy_sobel_full',zl_xy_sobel_full)
cv2.waitKey(0)
3. 效果图表分析(图 1:Sobel 算子边缘检测效果对比)

| 图像类型 | 效果描述 |
|---|---|
| 原始图像(yuan.png) | 彩色原图,包含丰富的纹理和边缘信息 |
| X 方向边缘(yuan_x) | 仅显示垂直方向边缘,右端负梯度区域初始为黑(未转 64 位),转后还原完整边缘 |
| Y 方向边缘(yuan_y) | 仅显示水平方向边缘,下端负梯度区域转 64 位 + 绝对值后清晰可见 |
| X+Y 加权边缘(yuan_xy_full) | 融合垂直 + 水平边缘,完整还原图像所有方向边缘,细节保留适中 |
| 灰度图 Sobel(zl_xy_sobel_full) | 灰度图边缘检测无色彩干扰,边缘轮廓更清晰,适合后续特征提取 |
三、Scharr 算子:Sobel 的 "增强版",边缘更锐利
1. 原理速览
Scharr 算子是 Sobel 的优化版,卷积核权重更大,对微小边缘的检测更敏感,适合边缘模糊、细节丰富的图像。
2. 实战代码(直接复用)
python
'''Scharr 算子 '''
# # # # cv.Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]])
# # # # src:输入图像
# # # # ddepth:输出图片的数据深度,由输入图像的深度进行选择
# # # # dx:x 轴方向导数的阶数
# # # # dy:y 轴方向导数的阶数
zl = cv2.imread('zl.png',cv2.IMREAD_GRAYSCALE)
zl_x_64 = cv2.Scharr(zl,cv2.CV_64F,dx=1,dy=0)#默认int8改为float64,可保存负数
zl_x_full = cv2.convertScaleAbs(zl_x_64)#转换为绝对值,负数转换为正数
zl_y_64 = cv2.Scharr(zl,cv2.CV_64F,dx=0,dy=1)#默认int8改为float64,可保存负数
zl_y_full = cv2.convertScaleAbs(zl_y_64)#转换为绝对值,负数转换为正数
zl_xy_Scharr_full = cv2.addWeighted(zl_x_full,1,zl_y_full,1,0)
cv2.imshow('zl_xy_Scharr_full',zl_xy_Scharr_full)
cv2.waitKey(0)

3. 效果图表分析(图 2:Sobel vs Scharr 边缘检测对比)
| 算子 | 效果特征 |
|---|---|
| Sobel | 边缘平滑,噪声少,但微小边缘易被忽略 |
| Scharr | 边缘更锐利,微小纹理(如图像中的细线条)清晰可见,但会放大少量噪声 |
| 适用场景 | Sobel:通用场景、噪声多的图像;Scharr:细节丰富、边缘模糊的图像 |
四、Laplacian 算子:二阶导数,检测 "所有方向边缘"
1. 原理速览
Laplacian 算子计算二阶导数,无需分 X/Y 方向,直接检测所有方向边缘,但对噪声极敏感,通常需先做平滑处理。
2. 实战代码(直接复用)
python
'''Laplacian算子'''
# # #cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
# # # 参数说明:
# # # src:输入图像,可以是灰度图像,也可以是多通道的彩色图像
# # # ddepth:输出图片的数据深度:
# # # ksize:计算二阶导数滤波器的孔径大小,必须为正奇数,可选项
# # # scale:缩放比例因子,可选项,默认值为 1
# # # delta:输出图像的偏移量,可选项,默认值为 0
zl = cv2.imread('zl.png',cv2.IMREAD_GRAYSCALE)
cv2.imshow('zl',zl)
zl_lap = cv2.Laplacian(zl,cv2.CV_64F)
zl_lap_full = cv2.convertScaleAbs(zl_lap)#转换为绝对值,负数转换为正数
cv2.imshow('zl_lap_full',zl_lap_full)
cv2.waitKey(0)

3. 效果图表分析(图 3:Laplacian 算子边缘检测效果)
| 图像状态 | 效果描述 |
|---|---|
| 原始灰度图 | 纹理均匀,边缘过渡自然 |
| Laplacian 处理后 | 所有方向边缘被高亮,尤其是图像中的 "突变区域"(如明暗交界),但噪声也被放大 |
| 优化建议 | 先通过高斯滤波去噪,再用 Laplacian 检测边缘 |
五、Canny 边缘检测:边缘检测的 "天花板"
1. 原理速览
Canny 是多步骤的最优边缘检测算法:① 高斯滤波去噪 → ② 计算梯度幅值和方向 → ③ 非极大值抑制 → ④ 双阈值筛选 → ⑤ 边缘连接,是工业界最常用的边缘检测方案。
2. 实战代码(直接复用)
python
'''canny边缘检测'''
# # cv.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]])
# # image 为输入图像。
# # threshold1 表示处理过程中的第一个阈值。fL
# # threshold2 表示处理过程中的第二个阈值。fH
zl = cv2.imread('zl.png',cv2.IMREAD_GRAYSCALE)
cv2.imshow('zl',zl)
cv2.waitKey(0)
zl_canny = cv2.Canny(zl,100,150)#低,高
cv2.imshow('zl_canny',zl_canny)
cv2.waitKey(0)
3. 效果图表分析(图 4:Canny 边缘检测效果 + 参数影响)

| 阈值组合(低 / 高) | 效果描述 |
|---|---|
| 100/150 | 边缘完整且纯净,无多余噪声,目标轮廓清晰可辨 |
| 50/100 | 边缘过多,噪声被误检为边缘,轮廓杂乱 |
| 150/200 | 边缘过少,部分弱边缘被过滤,轮廓不完整 |
| 核心结论 | 低阈值控制弱边缘保留,高阈值控制强边缘筛选,需根据图像噪声调整 |
六、总结
边缘检测是从 "像素级" 到 "特征级" 的关键一步:
入门用 Sobel,通用且稳定;
追细节用 Scharr,边缘更锐利;
全方向检测用 Laplacian(需先去噪);
工业级应用用 Canny,效果最优!
下一篇我们将进阶到 "轮廓检测 + 模板匹配",从提取边缘特征到精准匹配目标,手把手教你实现 "图像中找目标" 的核心技能!