图像处理:边缘检测原理

很抱歉,前面推导三种边缘检测算子我不是很满意就发出去了,现在以我的知识储备看他们还是有着很大的问题,我潜下心的找资料,看视频,就是为了将我的基础打牢,所以,我在这一篇当中好好的抠细节,毕竟从实际的应用上来说,这是我的学习笔记,再怎么也不能糊弄自己。

目录

原理

Sobel检测算子

Laplacian算子

算子比较


 

原理

边缘检测是图像处理和计算机视觉当中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点,图像的边缘检测可以大幅度的减少数据量,并且剔除了可以认为不相关的信息,保留了图像重要的结构属性,它们绝大多数可以分为两类:基于搜索和基于零穿越。

  • 基于搜索:通过寻找图像一阶导数中max来检测边界,然后利用计算结果估计边缘的局部方向,通常采用梯度的方向,并在此方向找到局部梯度模的最大值,代表的算法是Sobel算子和Scharr算子。

9890063b637244c19caaba40e5784989.jpeg

 

  • 基于零穿越:通过寻找图像二阶导数零穿越来寻找边界,代表算法是Laplacian算子。 

6977d12c3dbb47eabc8de2a2bc918bd6.jpeg

 

Sobel检测算子


Sobel边缘检测算法比较简单,实际应用中效率要比Canny边缘检测算法效率要高,但边缘检测效果不如Canny准确,但很多常会它依旧是首选,它是高斯平滑与微分操作的结合体,所以其抗燥声能力很强,用途较多,尤其是对效率要求较高,而对细纹理不是很在意的情况下。

方法

5515295ff76b44fd90b7c8f8bc86c949.jpeg

 那么我们看到上图最后一个式子,在某一个领域内,某一方向上,前一个像素与后一个像素的差,除以(x+1)-(x-1)=2,就得到当前的一个一阶导数,这就是Sobel算子的一个思想。

这里假设要处理的对象为I,在两个方向求导:

  • 水平变化:将图像I与奇数大小的模板进行卷积,结果为Gx。
  • 垂直变化:将图像I与奇数大小的模板进行卷积,结果为Gy。

如下,模板为3;

2267f4ccb775499d9bfe719ce47509af.jpeg

 最后,统计极大值所在的位置,即为图像的边缘

注:当内核大小为3时,以上Sobel内核可能会产生比较明显的误差,为解决这一个问题,我们使用Scharr函数,但该函数仅作用于大小为3的内核,该函数的运行速度与Sobel算子一样快,但结果更加精准,其计算方法为下图所示:

ee3a773b1f364c9895aaa2662e445dde.png

 应用

 Opencv当中的API为:

sobel_x_or_y=Sobel(src, ddepth, dx, dy, dst=None, ksize=None, scale=None, delta=None, borderType=None)

"""
src:传入图像
ddepth:图像的深度
dx、dy=指求导的阶数,0表示这个方向上没有求导,取值为0、1
ksize=是Sobel算子的大小,即卷积核的大小,为奇数(1,3,5,7等),默认是3
scale:缩放导数的比例常数,默认没有
borderType:函数的边界模式,默认是cv2.BORDER_DEFAULT

"""

Sobel函数求导后会有负数,还有大于255的值,原图像为uint8,8位无符号数,所以Sobel建立的图像位数不够,会有截断。因此,要用16位有符号的数据类型,即cv2.CV_16S(放到深度中)。处理完图像后,再使用cv2.convertScaleAbs()函数将其再转为uint8格式,否则无法显示图像。

Sobel算子是两个方向计算的,最后要用cv2.addWeighted()函数将其组合起来

Scale_abs=cv2.convertScaleAbs(x)
result=cv2.addWeighted(scr1,alpha,scr2,beta)  #混合x,y方向
import cv2
import numpy as np
from matplotlib import pyplot as plt

img=cv2.imread("Images/1-1.jpg",0)
#Sobel:x,y方向
x=cv2.Sobel(img,cv2.CV_16S,1,0)
y=cv2.Sobel(img,cv2.CV_16S,0,1)
#数据转化
Scale_absx=cv2.convertScaleAbs(x)
Scale_absy=cv2.convertScaleAbs(y)
#混合图像
result=cv2.addWeighted(Scale_absx,0.5,Scale_absy,0.5,0)

plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img,cmap=plt.cm.gray),plt.title('yuantu')
plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(result,cmap=plt.cm.gray),plt.title('Sobel')
plt.xticks([]),plt.yticks([])
plt.show()

78735df108034a7898468245d6300fc2.png

 而Scharr,就是将Sobel算子当中的变成ksize=-1。

x=cv2.Sobel(img,cv2.CV_16S,1,0,ksize=-1)
y=cv2.Sobel(img,cv2.CV_16S,0,1,ksize=-1)

8224c7052f794fdea97db1826678eb46.png

可以看到,Scharr检测的细节更加多一些。 

 

Laplacian算子

laplacian是利用二阶导数来检测边缘。因为图像是“二维”,需要在两个方向上求导,如下所示

8e2e066282d746288595f2d808bc5e08.png

 API:

laplacian=cv2.Laplacian(src, ddepth, dst=None, ksize=None, scale=None, delta=None, borderType=None)

"""
src:图像
Ddepth:图像的深度,-1表示采用的是原图像相同的深度,目标图像的深度必须要大于等于原图像的深度;
ksize:卷积核的大小,必须为奇数

"""

 

import cv2
import numpy as np
from matplotlib import pyplot as plt

img=cv2.imread("Images/1-1.jpg",0)

result=cv2.Laplacian(img,cv2.CV_16S)
Scale_abs=cv2.convertScaleAbs(result)

plt.figure(figsize=(10,8),dpi=100)
plt.subplot(121),plt.imshow(img,cmap=plt.cm.gray),plt.title('yuantu')
plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(result,cmap=plt.cm.gray),plt.title('laplacian')
plt.xticks([]),plt.yticks([])
plt.show()

 c11f6c33edaf4c91b1ba268645076728.png

算子比较

6512d8385ca240b69493957f4a790729.png

 

注:此图来源于黑马教程的视频

 

  • 11
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏天是冰红茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值