Opencv-Python学习笔记十——图像梯度、边缘检测 Gradient, Edge Detection

图像梯度 边缘检测

图像梯度,图像边界
使用到的函数有: cv2.Sobel(), cv2.Schar(), cv2.Laplacian()

梯度简单来说就是求导,OpenCV 提供了三种不同的梯度滤波器,或者说高通滤波器: Sobel,Scharr 和 Laplacian。

  • Sobel, Scharr 其实就是求一阶或二阶导数。
  • Scharr 是对 Sobel(使用小的卷积核求解求解梯度角度时)的优化。
  • Laplacian 是求二阶导数。

Sobel算子 cv2.Sobel()

dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])

前四个是必须的参数:

  • src参数是需要处理的图像;
  • ddepth参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度;
  • dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为0、1、2。

其后是可选的参数:

  • ksize是Sobel算子的大小,必须为1、3、5、7。
  • scale是缩放导数的比例常数,默认情况下没有伸缩系数;
  • delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
  • borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。

Sobel算子是高斯平滑与微分操作的结合体,所以它的抗噪声能力很好,可以设定求导的方向(xorder 或 yorder),还可以设定使用的卷积核的大小(ksize),如果 ksize=-1,会使用 3x3 的 Scharr 滤波器,它的的效果要比 3x3 的 Sobel 滤波器好(而且速度相同,所以在使用 3x3 滤波器时应该尽量使用 Scharr 滤波器)。

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

img = cv2.imread('edage.jpg', 0)
 
"""
在Sobel函数的第二个参数这里使用了cv2.CV_16S。
因为OpenCV文档中对Sobel算子的介绍中有这么一句:
“in the case of 8-bit input images it will result in truncated derivatives”。
即Sobel函数求完导数后会有负值,还有会大于255的值。而原图像是uint8,即8位无符号数,
所以Sobel建立的图像位数不够,会有截断。因此要使用16位有符号的数据类型,即cv2.CV_16S
"""
x = cv2.Sobel(img,cv2.CV_16S,1,0)
y = cv2.Sobel(img,cv2.CV_16S,0,1)

"""
在经过处理后,别忘了用convertScaleAbs()函数将其转回原来的uint8形式。否则将无法显示图像,而只是一副灰色的窗口。

dst = cv2.convertScaleAbs(src[, dst[, alpha[, beta]]])
可选参数alpha是伸缩系数,beta是加到结果上的一个值。结果返回uint8类型的图片
"""
absX = cv2.convertScaleAbs(x)   # 转回uint8
absY = cv2.convertScaleAbs(y)

"""
由于Sobel算子是在两个方向计算的,最后还需要用cv2.addWeighted(...)函数将其组合起来
dst = cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])
其中alpha是第一幅图片中元素的权重,beta是第二个的权重,gamma是加到最后结果上的一个值。
"""
dst = cv2.addWeighted(absX,0.5,absY,0.5,0)

img_h1 = np.hstack([img, absX])
img_h2 = np.hstack([absY, dst])
img_all = np.vstack([img_h1, img_h2])

plt.figure(figsize=(20,10))
plt.imshow(img_all, cmap=plt.cm.gray)
plt.show()
sobel()

Laplacian 算子

拉普拉斯算子可以使用二阶导数的形式定义,可假设其离散实现类似于二阶Sobel导数,事实上,OpenCV在计算拉普拉斯算子时直接调用Sobel 算子。
Laplacian算子:图像中的边缘区域,像素值会发生“跳跃”,对这些像素求导,在其一阶导数在边缘位置为极值,这就是Sobel算子使用的原理——极值处就是边缘。

dst = cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])

前两个是必须的参数:

  • src参数是需要处理的图像;
  • ddepth参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度;

其后是可选的参数:

  • ksize是算子的大小,必须为1、3、5、7。默认为1。
  • scale是缩放导数的比例常数,默认情况下没有伸缩系数;
  • delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
  • borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。

拉普拉斯对噪声敏感,会产生双边效果。不能检测出边的方向。通常不直接用于边的检测,只起辅助的角色,检测一个像素是在边的亮的一边还是暗的一边利用零跨越,确定边的位置。

%matplotlib inline
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("edage.jpg", 0)
 
gray_lap = cv2.Laplacian(img, cv2.CV_16S, ksize=3)
dst = cv2.convertScaleAbs(gray_lap)
 
plt.imshow(dst, cmap=plt.cm.gray)
plt.show()
Laplacian.png

边缘检测

边缘检测的一般步骤:

  1. 滤波——消除噪声
  2. 增强——使边界轮廓更加明显
  3. 检测——选出边缘点

Canny边缘检测

图像的边缘检测的原理是检测出图像中所有灰度值变化较大的点,而且这些点连接起来就构成了若干线条,这些线条就可以称为图像的边缘。
Canny边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。

Canny算子检测原理是通过图像信号函数的极大值来判定图像的边缘像素点。边缘检测的算法主演是基于图像强度的一阶和二阶微分操作,但导数通常对噪声很敏感,边缘检测算法常常需要根据图像源的数据进行预处理操作,因此必须采用滤波器来改善与噪声有关的边缘检测的性能。在进行Canny算子边缘检测前,应当先对原始数据与高斯模板进行卷积操作,得到的图像与原图像相比有些模糊。通常使用高斯平滑滤波器卷积降噪。

edge = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]])

必要参数:

  • 第一个参数是需要处理的原图像,该图像必须为单通道的灰度图;
  • 第二个参数是阈值1;
  • 第三个参数是阈值2。 其中较大的阈值2用于检测图像中明显的边缘,但一般情况下检测的效果不会那么完美,边缘检测出来是断断续续的。所以这时候用较小的第一个阈值用于将这些间断的边缘连接起来.

可选参数中apertureSize就是Sobel算子的大小。

而L2gradient参数是一个布尔值,如果为真,则使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开放),否则使用L1范数(直接将两个方向导数的绝对值相加)

Canny边缘检测基本原理:

  1. 图象边缘检测必须满足两个条件:一能有效地抑制噪声;二必须尽量精确确定边缘的位置。
  2. 根据对信噪比与定位乘积进行测度,得到最优化逼近算子。这就是Canny边缘检测算子。
  3. 类似与Marr(LoG)边缘检测方法,也属于先平滑后求导数的方法。

Canny 的目标是找到一个最优的边缘检测算法,最优边缘检测的含义是:

  • 好的检测 - 算法能够尽可能多地标识出图像中的实际边缘。
  • 好的定位 - 标识出的边缘要尽可能与实际图像中的实际边缘尽可能接近。
  • 最小响应 - 图像中的边缘只能标识一次,并且可能存在的图像雜訊不应标识为边缘。

canny 算法五步骤

  1. 高斯模糊
  2. 灰度转换
  3. 计算梯度
  4. 非最大信号抑制
  5. 高低阈值输出二值图像

可参考,opencv入门12:梯度和边缘检测……

%matplotlib inline
import cv2
import numpy as np
import matplotlib.pyplot as plt
 
 
def edge_detect(img):
    #高斯模糊,降低噪声
    blurred = cv2.GaussianBlur(img,(3,3),0)
    #灰度图像
    gray = cv2.cvtColor(blurred,cv2.COLOR_RGB2GRAY)
    #图像梯度
    xgrad = cv2.Sobel(gray,cv2.CV_16SC1,1,0)
    ygrad = cv2.Sobel(gray,cv2.CV_16SC1,0,1)
    #计算边缘
    #50和150参数必须符合1:3或者1:2
    edge_output = cv2.Canny(xgrad,ygrad,50,150)
 
    dst = cv2.bitwise_and(img,img,mask=edge_output)
    
    return edge_output, dst
    
    
img = cv2.imread('edage.jpg')

edge_output, canny_edge = edge_detect(img.copy())

plt.figure(figsize=(20, 8))

plt.subplot(131)
plt.imshow(img[:,:,::-1])

plt.subplot(132)
plt.imshow(canny_edge[:,:,::-1])

plt.subplot(133)
plt.imshow(edge_output, cmap=plt.cm.gray)

plt.tight_layout()
plt.show()
canny.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容