opencv图像处理-图像梯度

本文详细介绍了图像梯度的概念,以及Sobel、Scharr和Laplacian算子在图像边缘检测中的应用。通过实例代码展示了这些算子如何计算图像的梯度,并解释了处理结果中可能出现的问题及解决方案,如边缘信息丢失。同时,通过对比不同算子的处理效果,突显了它们在实际应用中的特点和选择考虑因素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图像梯度是指图像某像素在x和y两个方向上的变化率(与相邻像素比较),本质上即导数。

Sobel算子

Sobel算子是高斯平滑加微分运算的联合运算,因此它更抗噪声

Sobel算子常用模板


代码:

dst=cv.Sobel(src,ddepth,dx,dy,ksize)

  • ddepth: 输出图像的深度,若使用-1,则与原图像深度保持一致numpy.uint8,输出图像的深度必须大于等于原图像的深度
  • dx和dy分别表示导数方向为水平和竖直方向,0表示此方向不求导
  • kszie: Sobel算子的大小,如果ksize = -1,则使用3x3 Scharr滤波器,比3x3 Sobel滤波器具有更好的结果,必须为1,3,5,7
import cv2 as cv
img=cv.imread('test.png',cv.IMREAD_GRAYSCALE)
# 在x方向求导
sobelx=cv.Sobel(img,cv.CV_8U,1,0,ksize=3)
# 取绝对值,转回原来的uint8形式
sobelx=cv.convertScaleAbs(sobelx)
cv.imshow('original',img)
cv.imshow('sobelx',sobelx)
cv.waitKey(0)
cv.destroyAllWindows()

处理结果:

从上面的处理结果我们会发现一个问题 :右边的边缘信息被忽略了.

造成此种情况的原因在于黑色到白色的过渡被视为正斜率(具有正值),而白色到黑色的过渡被视为负斜率(具有负值),此时若设置输出图像的深度为cv.CV_8Unumpy.uint8,则所有的负值都会被截断为0(所建立的图像位数不够,会被截断为0),边界将会丢失。

解决方案: 如果要检测两个边缘,更好的选择是将输出数据类型保留为更高的形式,例如cv.CV_16Scv.CV_64F等,取其绝对值,然后转换回cv.CV_8U

注意:取绝对值的步骤也同样需要,否则边缘也同样会丢失。

import cv2 as cv
img=cv.imread('test.png',cv.IMREAD_GRAYSCALE)
# CV_64F 表示输出图像的深度
# 在x方向求导
sobelx=cv.Sobel(img,cv.CV_64F,1,0,ksize=3) 
sobelx=cv.convertScaleAbs(sobelx)
# 在y方向求导
sobely=cv.Sobel(img,cv.CV_64F,0,1,ksize=3)
sobely=cv.convertScaleAbs(sobely)
# x和y方向按权求和
sobelxy=cv.addWeighted(sobelx,0.5,sobely,0.5,0)
cv.imshow('original',img)
cv.imshow('sobelx',sobelx)
cv.imshow('sobely',sobely)
cv.imshow('sobelxy',sobelxy)
cv.waitKey(0)
cv.destroyAllWindows()

处理结果:


Scharr算子

Scharr是对Sobel算子(使用小的卷积核求解梯度角度时)的优化。

卷积核


代码:

import cv2 as cv
img=cv.imread('test.png',cv.IMREAD_GRAYSCALE)
# x方向求导
scharrx=cv.Scharr(img,cv.CV_64F,1,0,scale=3)
scharrx=cv.convertScaleAbs(scharrx)
# y方向求导
scharry=cv.Scharr(img,cv.CV_64F,0,1,scale=3)
scharry=cv.convertScaleAbs(scharry)
# x和y方向按权求和
scharrxy=cv.addWeighted(scharrx,0.5,scharry,0.5,0)
cv.imshow('x',scharrx)
cv.imshow('Y',scharry)
cv.imshow('xy',scharrxy)
cv.imshow('original',img)
cv.waitKey(0)
cv.destroyAllWindows()

处理结果:


laplacian算子

拉普拉斯算子是一种各向同性的二阶微分算子,在(x,y)处的值定义为:

ksize=1时,拉普拉斯滤波器使用的卷积核:

其他常用的拉普拉斯模板:


代码:

import cv2 as cv
img=cv.imread('test.png')
laplacian=cv.Laplacian(img,cv.CV_64F)
laplacian=cv.convertScaleAbs(laplacian)
cv.imshow('laplacian',laplacian)
cv.imshow('original',img)
cv.waitKey(0)
cv.destroyAllWindows()

处理结果:


不同算子之间比较

代码:

import cv2 as cv
import numpy as np
img=cv.imread('lena.jpg',cv.IMREAD_GRAYSCALE)
# Sobel算子
sobelx=cv.Sobel(img,cv.CV_64F,1,0,ksize=3)
sobelx=cv.convertScaleAbs(sobelx)
sobely=cv.Sobel(img,cv.CV_64F,0,1,ksize=3)
sobely=cv.convertScaleAbs(sobely)
sobelxy=cv.addWeighted(sobelx,0.5,sobely,0.5,0)
# Scharr算子
scharrx=cv.Scharr(img,cv.CV_64F,1,0,scale=3)
scharrx=cv.convertScaleAbs(scharrx)
scharry=cv.Scharr(img,cv.CV_64F,0,1,scale=3)
scharry=cv.convertScaleAbs(scharry)
scharrxy=cv.addWeighted(scharrx,0.5,scharry,0.5,0)
# Laplacian算子
laplacian=cv.Laplacian(img,cv.CV_64F)
laplacian=cv.convertScaleAbs(laplacian)

res=np.hstack((img,sobelxy,scharrxy,laplacian))
cv.imshow('all',res)
cv.waitKey(0)
cv.destroyAllWindows()

对比:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S5R2E4aj-1635000400560)(https://cdn.jsdelivr.net/gh/code-jie123/code-jie123cdn/202110021507528.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值