边缘时像素值发生跃迁的位置,是图像的显著特征之一。在图像特征提取,对象检测,模式识别等方面有重要作用。
1 sobel(索贝尔)算子
sobel算子对图像求一阶导数。一阶导数越大,说明像素在该方向的变化越大,边缘信号越强。因为图像的灰度值都是离散的数字,sobel算子采用 离散差分算子 计算图像像素值的近似梯度。
图像是二维的,即沿着宽度/高度两个方向。可以使用两个卷积核(水平,垂直)进行处理 。
这样处理后,可以得到两个新的矩阵,分别反映了每一点像素在水平方向上和垂直方向上的亮度变化情况。综合这俩个方向的变化,可以用G = |G(x)| + |G(y)|来表示图像的边缘。
总的来说,sobel算子,其会分别计算x,y的梯度。(梯度算子)x方向计算边缘:左列像素-右列像素;y方向计算边缘:下行像素-上行像素。
import cv2 import numpy as np img = cv2.imread('./pie.png') #dx = cv2.Sobel(img,-1,dx=1,dy=0,ksize=3) #计算x轴方向梯度,消除水平方向线条,获得的是垂直方向的边缘(参数:img,返回图像结果位深,。。。) #位深为-1表示与原图相同,但是如果输出是负数会被直接截断成0.可以用cv2.CV_64F,保留负数,然后取绝对值,否则梯度为负数的边缘就没有了。 #dy = cv2.Sobel(img,-1,dx=0,dy=1,ksize=3) #计算y轴方向梯度,消除垂直方向线条,获得的是水平方向的边缘 dx = cv2.Sobel(img,cv2.CV_64F,dx=1,dy=0,ksize=3) dx = cv2.convertScaleAbs(dx) #对计算出的梯度取绝对值,把梯度为负数的边缘保留下来 convert 转换 scale 缩放 dy = cv2.Sobel(img,cv2.CV_64F,dx=0,dy=1,ksize=3) dy = cv2.convertScaleAbs(dy) dst = cv2.add(dx,dy) #sobel算子要把x,y方向结果合并在一起 #dst =cv2.cvtColor(dst,cv2.COLOR_BGR2GRAY) cv2.imshow('img',img) cv2.imshow('img_dx',dx) cv2.imshow('img_dy',dy) cv2.imshow('dst',dst) cv2.waitKey(0) cv2.destroyAllWindows()
2 scharr(沙尔)算子
沙尔算子是 sobel算子在3*3卷积核的升级,scharr算子只支持3*3的kernel,所以没有ksize参数;scharr只能求x方向或y方向的边缘;sobel算子的ksize设为-1就是scharr算子,scharr擅长寻找细小边缘。
import cv2 import numpy as np img = cv2.imread('./lena.jpg') # dx =cv2.Scharr(img,-1,dx=1,dy=0) # dy =cv2.Scharr(img,-1,dx=0,dy=1) dx = cv2.Scharr(img,cv2.CV_64F,dx=1,dy=0) dx = cv2.convertScaleAbs(dx) #对计算出的梯度取绝对值,把梯度为负数的边缘保留下来 dy = cv2.Scharr(img,cv2.CV_64F,dx=0,dy=1) dy = cv2.convertScaleAbs(dy) dst = cv2.add(dx,dy) #把x,y方向结果合并在一起 cv2.imshow('img',img) cv2.imshow('img_dx',dx) cv2.imshow('img_dy',dy) cv2.imshow('dst',dst) cv2.waitKey(0) cv2.destroyAllWindows()
3 Laplacian(拉普拉斯)算子
边缘处的二阶导数=0,可以利用这一特性去寻找图像的边缘,但是二阶导的位置也可能是无意义的位置,比如噪声(可以先去噪,再用拉普拉斯提取边缘)。
拉普拉斯算子推导过程:
可以同时对x方向和y方向进行计算,对噪声敏感,需要先降噪。 卷积核:[[0,1,0],[1,-4,1],[0,1,0]]
opencv的拉普拉斯函数:Laplacian(scr,ddepth,dst[,ksize[,scale[,delta[,borderType[),用的时候很简单,如下:
import cv2 img = cv2.imread('./lena.jpg') img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #提取边缘跟图像颜色关系不大,可以先转换为灰度图节约时间 #img = cv2.imread('./pie.png') dst = cv2.Laplacian(img,-1,ksize=3) cv2.imshow('img',img) cv2.imshow('dst',dst) cv2.waitKey(0) cv2.destroyAllWindows()
4 canny边缘检测
边缘检测最优的算法,边缘检测的三个评价标准:1 低错误率(标识出尽可能多的边缘,同时减少噪声的误判);2 高定位性(标识出的边缘要与原图的实际边缘尽可能接近);3 最小响应(图像中的边缘只能标识一次)。
canny检测的步骤:
1 去噪,一般用高斯滤波去噪。
2 计算梯度,对平滑后的图像采用sobel算子计算梯度,梯度方向分为水平,垂直和对角线四个)。
3 非极大值抑制(在获取了梯度和方向后,遍历图像,去除所有不是边界的点。实现方法:逐个遍历像素点,判断当前像素点是否是周围像素点中具有相同方向的梯度最大值)
比较形象的例子:
4 滞后阈值 (梯度值> maxVal 是边界保留;梯度值< minVal 不是边界 去掉;minVal < 梯度值 < maxVal 如果与边界相连(空间上连通),保留,不相连抛弃)
import cv2 img = cv2.imread('./lena.jpg') dst1 = cv2.Canny(img,100,200) #Canny(img,最小阈值,最大阈值) dst2 = cv2.Canny(img,50,120) #小一点的阈值可以得到更精细的边缘,但是也会带入一些不想要的边缘 dst3 = cv2.Canny(img,100,300) cv2.imshow('img',img) cv2.imshow('dst1',dst1) cv2.imshow('dst2',dst2) cv2.imshow('dst3',dst3) cv2.waitKey(0) cv2.destroyAllWindows()
标签:提取,img,边缘,python,算子,cv2,opencv,dx,dy From: https://www.cnblogs.com/libai123456/p/17595247.html