Opencv计算机视觉--图像边缘检测

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()
  1. 读取并预处理图像(转为灰度图并缩小尺寸)

  2. 分别计算x方向和y方向的图像梯度

  3. 将两个方向的梯度幅值合并得到完整的边缘检测结果

  4. 显示原始图像和边缘检测结果

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)原理
  1. 高斯滤波去噪 - 先用高斯模糊平滑图像,减少噪声干扰

  2. 计算梯度 - 用Sobel算子计算每个像素的梯度幅值和方向

  3. 非极大值抑制 - 只保留梯度方向上的局部最大值,细化边缘

  4. 双阈值检测 - 用高低两个阈值筛选边缘:强边缘保留,弱边缘判断是否连接强边缘,其余剔除

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()

​​​​​​​

相关推荐
空山新雨后、2 小时前
从 CIFAR 到 ImageNet:计算机视觉基准背后的方法论
人工智能·深度学习·算法·计算机视觉
Light602 小时前
智链护航,数档永存:基于领码SPARK平台构建下一代AI+区块链档案系统解决方案
人工智能·spark·区块链
雨大王5122 小时前
汽车生产拉动LES系统:构建精益物流新模式
人工智能·汽车·制造
万行2 小时前
机器人系统ros2&期末速通4
人工智能·决策树·机器人
芝麻别开门2 小时前
opengl图像处理
图像处理·人工智能
Java后端的Ai之路2 小时前
【AI应用开发工程师】-Gemini写前端的一个坑
前端·人工智能·gemini·ai应用开发工程师
深蓝电商API2 小时前
Scrapy爬取Ajax动态加载页面三种实用方法
爬虫·python·scrapy·ajax
国服第二切图仔2 小时前
实战:在华为云上快速搭建 openJiuwen Agent 平台,并开发一个“诗词雅集”知识库智能体
人工智能·华为云·智能体·openjiuwen