1.sobel算子
cv2.Sobel(src, ddepth, dx, dy[, ksize[, scale[, delta[, borderType]]]])
1)原理
-
通过卷积核对图像进行卷积运算,检测图像中的边缘
-
x方向检测垂直边缘,y方向检测水平边缘
-
最终结果合并了两个方向的边缘信息
2)参数:
src: 输入图像
ddepth: 输出图像的深度(可以理解为数据类型),-1表示与原图像相同的深度
dx,dy: 当组合为dx=1,dy=0时求x方向的一阶导数,当组合为dx=0,dy=1时求y方向的一阶导数(如果同时为1,通常效果不佳)
ksize: (可选参数) Sobel算子的大小,必须是1,3,5或者7,默认为3。
3)具体实例
python
import cv2
import numpy as np
yuan1 = cv2.imread('baiqiu.png')
yuan=cv2.resize(yuan1,dsize=None,fx=0.7,fy=0.7)
cv2.imshow('yuan', yuan)
cv2.waitKey(0)
# x方向上的边缘
yuan_x = cv2.Sobel(yuan, -1, dx=1, dy=0)#这里的-1指的是uint8
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(0)
# 使用图像加权运算组合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)
#
cv2.destroyAllWindows()

4)小例子
python
import cv2
import numpy as np
# 读取图像观看效果
'''sobel算子'''
# 读取灰度图像
zl1 = cv2.imread('xiaomao.jpg', 0) # 参数0表示以灰度模式读取图像
# 将图像尺寸缩小为原来的一半
zl = cv2.resize(zl1, dsize=None, fx=0.5, fy=0.5) # fx和fy分别表示宽度和高度的缩放比例
# 显示原始图像
cv2.imshow('zl', zl) # 创建一个名为'zl'的窗口显示图像
cv2.waitKey(0) # 等待任意按键按下,0表示无限等待
# 计算x方向的Sobel导数(使用64位浮点数存储结果)
zl_x_64 = cv2.Sobel(zl, cv2.CV_64F, dx=1, dy=0)
# cv2.CV_64F: 输出图像深度为64位浮点数(可保存负值)
# dx=1, dy=0: 计算x方向的一阶导数
# 将64位浮点数转换为8位无符号整数(取绝对值)
zl_x_full = cv2.convertScaleAbs(zl_x_64)
# convertScaleAbs: 先计算绝对值,然后转换为8位无符号整数
# 计算y方向的Sobel导数
zl_y_64 = cv2.Sobel(zl, cv2.CV_64F, dx=0, dy=1) # dx=0, dy=1: 计算y方向的一阶导数
# 将y方向的梯度结果转换为8位无符号整数
zl_y_full = cv2.convertScaleAbs(zl_y_64)
# 将x和y方向的梯度结果加权合并
zl_xy_sobel_full = cv2.addWeighted(zl_x_full, 1, zl_y_full, 1, 0)
# 参数说明:图像1, 权重1, 图像2, 权重2, 亮度调整值
# 这里使用等权重(1:1)合并x和y方向的梯度幅值
# 显示Sobel边缘检测结果
cv2.imshow('sobel', zl_xy_sobel_full) # 创建一个名为'sobel'的窗口显示边缘检测结果
cv2.waitKey(0) # 等待任意按键按下
# 关闭所有OpenCV窗口(原代码中缺少,建议添加)
cv2.destroyAllWindows()
-
读取并预处理图像(转为灰度图并缩小尺寸)
-
分别计算x方向和y方向的图像梯度
-
将两个方向的梯度幅值合并得到完整的边缘检测结果
-
显示原始图像和边缘检测结果

2.Scharr算子
cv.Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]])
1)核心思想
Sobel算子的核心思想是:图像中边缘处的像素值会发生剧烈变化,这种变化可以通过计算像素点的梯度(导数)来检测。
2)特点
是Sobel算子的改进版本,使用不同的卷积核系数
对于3x3卷积核,Scharr比Sobel具有更好的旋转对称性
只支持3x3大小的卷积核
对边缘的响应更强,但可能对噪声更敏感
3)参数
src:输入图像
ddepth:输出图片的数据深度,由输入图像的深度进行选择
dx:x轴方向导数的阶数
dy:y轴方向导数的阶数
4)例子
python
import cv2
# 使用cv2.IMREAD_GRAYSCALE参数以灰度模式读取图像,等同于参数0
zl1 = cv2.imread('xiaomao.jpg', cv2.IMREAD_GRAYSCALE) # cv2.IMREAD_GRAYSCALE = 0,表示读取为灰度图像
# 调整图像大小,dsize=None表示不直接指定输出尺寸,fx=0.5, fy=0.5表示宽度和高度都缩小到原来的一半
zl = cv2.resize(zl1, dsize=None, fx=0.5, fy=0.5)
# 将原图尺寸缩小一半,可以加快处理速度并减少内存使用
# 显示缩小后的原始灰度图像
cv2.imshow('zl', zl) # 在名为'zl'的窗口中显示图像
cv2.waitKey(0) # 等待键盘按键,参数0表示无限期等待,按任意键继续执行
# 使用Scharr算子计算x方向(水平方向)的梯度
# cv2.CV_64F表示输出图像深度为64位浮点数,可以保存负梯度值
# dx=1, dy=0表示计算x方向的一阶导数
zl_x_64 = cv2.Scharr(zl, cv2.CV_64F, dx=1, dy=0)
# Scharr算子是Sobel算子的优化版本,对边缘的响应更好,但只支持3x3核大小
# 将64位浮点数梯度图像转换为8位无符号整数图像
# convertScaleAbs函数会:1)计算绝对值 2)缩放(这里默认缩放因子为1)3)转换为uint8类型
zl_x_full = cv2.convertScaleAbs(zl_x_64)
# 这个转换是必要的,因为原始的64F图像包含负值,而显示需要0-255的正整数
# 使用Scharr算子计算y方向(垂直方向)的梯度
# dx=0, dy=1表示计算y方向的一阶导数
zl_y_64 = cv2.Scharr(zl, cv2.CV_64F, dx=0, dy=1)
# 将y方向梯度图像转换为8位无符号整数图像
zl_y_full = cv2.convertScaleAbs(zl_y_64)
# 将x方向和y方向的梯度图像合并,得到完整的边缘检测结果
# addWeighted函数执行加权融合:dst = src1*alpha + src2*beta + gamma
# 这里alpha=1, beta=1, gamma=0,表示直接相加
zl_xy_scharr_full = cv2.addWeighted(zl_x_full, 1, zl_y_full, 1, 0)
# 这种组合方式近似计算了梯度幅值:|G| ≈ |Gx| + |Gy|
# 显示Scharr边缘检测结果
cv2.imshow('scharr', zl_xy_scharr_full) # 在名为'scharr'的窗口中显示边缘检测结果
cv2.waitKey(0) # 等待键盘按键,按任意键继续
# 关闭所有OpenCV创建的窗口
cv2.destroyAllWindows()
# 释放窗口资源,这是良好的编程习惯,避免内存泄漏
1. 读取并预处理图像(转为灰度图并缩小尺寸)
2. 使用Scharr算子分别计算x和y方向的图像梯度
3. 将梯度值转换为可显示的8位图像
4. 合并两个方向的梯度得到完整的边缘检测结果
5. 显示原始图像和边缘检测结果

3.Laplacian
cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
1)基本概念
Laplacian算子是一种二阶微分算子 ,用于检测图像中的边缘和角点 。与Sobel和Scharr(一阶导数)不同,它直接计算图像的二阶导数。
2)特点
二阶微分算子,直接检测像素值的二阶变化
各向同性:对各个方向的边缘响应一致
边缘处会产生正负对,零交叉点对应边缘位置
对噪声非常敏感(本代码中没有先进行滤波处理)
ksize参数影响检测的灵敏度,越大检测到的边缘越平滑
3)参数
src:输入图像,可以是灰度图像,也可以是多通道的彩色图像
ddepth:输出图片的数据深度:
ksize:计算二阶导数滤波器的孔径大小,必须为正奇数,可选项
scale:缩放比例因子,可选项,默认值为1
delta:输出图像的偏移量,可选项,默认值为0
4)例子
python
import cv2
# 以灰度模式读取图像,参数0等同于cv2.IMREAD_GRAYSCALE
# 灰度图像只有一个通道,处理速度更快,适合边缘检测任务
xiaomao1 = cv2.imread('xiaomao.jpg', 0)
# 调整图像大小,将图像缩小为原来的一半
# dsize=None:不直接指定输出尺寸
# fx=0.5:宽度缩放因子为0.5(缩小一半)
# fy=0.5:高度缩放因子为0.5(缩小一半)
# 缩小图像可以加快处理速度并减少内存占用
xiaomao = cv2.resize(xiaomao1, dsize=None, fx=0.5, fy=0.5)
# 显示缩小后的原始灰度图像
# 'xiaomao'是窗口名称,xiaomao是要显示的图像
cv2.imshow('xiaomao', xiaomao)
# 等待按键,参数0表示无限期等待,直到用户按下任意键
# 按任意键后程序继续执行
cv2.waitKey(0)
# 使用Laplacian算子进行边缘检测
# 参数说明:
# 1. xiaomao: 输入图像(灰度图)
# 2. cv2.CV_64F: 输出图像深度为64位浮点数
# - 为什么要用64F:Laplacian计算结果可能包含负值(二阶导数有正负)
# - 使用64位浮点数可以保留这些负值信息
# 3. ksize=3: 指定Laplacian核的大小
# - ksize必须是正奇数(1,3,5,7等)
# - ksize=1:使用最简单的4邻域Laplacian核 [[0,1,0],[1,-4,1],[0,1,0]]
# - ksize=3:使用扩展的Laplacian核,可能包含对角线方向
# - ksize=3时,OpenCV使用类似 [[1,1,1],[1,-8,1],[1,1,1]] 的8邻域核
xiaomao_lap = cv2.Laplacian(xiaomao, cv2.CV_64F, ksize=3)
# 将64位浮点数的Laplacian结果转换为8位无符号整数图像
# convertScaleAbs函数执行以下操作:
# 1. 计算绝对值(因为Laplacian结果有正负,取绝对值后负值变为正值)
# 2. 线性缩放(默认缩放因子为1,偏移为0)
# 3. 转换为8位无符号整数类型(uint8,范围0-255)
# 这是为了将结果图像转换为适合显示和保存的格式
xiaomao_lap_full = cv2.convertScaleAbs(xiaomao_lap)
# 显示Laplacian边缘检测结果
# 'lap'是窗口名称,xiaomao_lap_full是要显示的边缘检测图像
cv2.imshow('lap', xiaomao_lap_full)
# 等待按键,用户查看边缘检测结果后按任意键继续
cv2.waitKey(0)
# 注意:原代码缺少销毁窗口的语句,建议添加以下代码
cv2.destroyAllWindows()
1. 读取并预处理图像:转为灰度图并缩小尺寸,提高处理效率
2. 应用Laplacian算子:计算图像的二阶导数,检测边缘
3. 结果转换:将包含正负值的浮点结果转换为0-255的整数图像
4. 显示结果:显示原始图像和边缘检测结果

4.canny边缘检测
cv.Canny( image, threshold1, threshold2[, apertureSize[, L2gradient]])
1)原理
-
高斯滤波去噪 - 先用高斯模糊平滑图像,减少噪声干扰
-
计算梯度 - 用Sobel算子计算每个像素的梯度幅值和方向
-
非极大值抑制 - 只保留梯度方向上的局部最大值,细化边缘
-
双阈值检测 - 用高低两个阈值筛选边缘:强边缘保留,弱边缘判断是否连接强边缘,其余剔除
2)参数
image为输入图像。
threshold1表示处理过程中的第一个阈值。fL
threshold2表示处理过程中的第二个阈值。fH
3)例子
python
import cv2
# 以灰度模式读取图像,参数0表示转为灰度图像(单通道)
xioamao1 = cv2.imread('xiaomao.jpg', 0)
# 将图像尺寸缩小为原来的一半
# dsize=None: 不直接指定输出尺寸
# fx=0.5: 宽度缩放因子为0.5(缩小一半)
# fy=0.5: 高度缩放因子为0.5(缩小一半)
xioamao = cv2.resize(xioamao1, dsize=None, fx=0.5, fy=0.5)
# 显示原始图像,窗口名为'zl'
cv2.imshow('zl', xioamao)
# 等待按键,0表示无限等待,按任意键继续
cv2.waitKey(0)
# 使用Canny算法进行边缘检测
# 参数说明:
# 1. xioamao: 输入图像
# 2. 100: 低阈值,用于弱边缘判断
# 3. 150: 高阈值,用于强边缘判断
# Canny会自动完成:高斯滤波、计算梯度、非极大值抑制、双阈值检测四步
xioamao_canny = cv2.Canny(xioamao, 100, 150)
# 显示Canny边缘检测结果,窗口名为'canny'
cv2.imshow('canny', xioamao_canny)
# 等待按键,按任意键继续
cv2.waitKey(0)
# 关闭所有OpenCV创建的窗口
cv2.destroyAllWindows()