Python - opencv (一) 边缘检测
本文开始Python - opencv的学习,因为有一些图像基础,图形学的基础部分(包括图像基本知识、环境部署、灰度直方图和二值化、图像缩放、腐蚀膨胀、开闭运算)跳过,直接从常用处理和机器学习开始。
本文记录opencv的边缘检测应用。
一. Sobel算子
sobel算子的思想,Sobel算子认为,邻域的像素对当前像素产生的影响不是等价的,所以距离不同的像素具有不同的权值,对算子结果产生的影响也不同。一般来说,距离越远,产生的影响越小。
sobel算子的原理,对传进来的图像像素做卷积,卷积的实质是在求梯度值,或者说给了一个加权平均,其中权值就是所谓的卷积核;然后对生成的新像素灰度值做阈值运算,以此来确定边缘信息。
原图中的作用点像素值通过卷积之后为:
可以简化成:
比如,一下矩阵为原图中的像素点矩阵,带入上式中的A,最终得到的G或者|G|是下面(x,y)处的像素值,可以自己去搜索下卷积的含义来理解。
另外,卷积核也可以旋转,用与查找不与x,y轴平行或垂直的方向上的边缘。
一般来说,对图像分别进行x和y两个方向的sobel运算再求和,比先进行一个方向,再进行另一个方向效果要好很多。
例子:
原图:
代码:
1 import cv2 2 3 if __name__ == '__main__': 4 img = cv2.imread('../pics/1.jpg', cv2.IMREAD_GRAYSCALE) 5 cv2.imshow('img', img) 6 sobel_x = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=3) 7 sobel_x = cv2.convertScaleAbs(sobel_x) 8 sobel_y = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=3) 9 sobel_y = cv2.convertScaleAbs(sobel_y) 10 sobel_xy = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0) 11 cv2.imshow('img', sobel_xy) 12 cv2.waitKey() 13 cv2.destroyAllWindows()
这里convertScaleAbs函数是一个位深转化函数,可将任意类型的数据转化为CV_8UC1。具体数据处理方式如下:
(1). 对于src*alpha+beta的结果如果是负值且大于-255,则直接取绝对值;
(2). 对于src*alpha+beta的结果如果大于255,则取255;
(3). 对于src*alpha+beta的结果是负值,且小于-255,则取255;
(4). 对于src*alpha+beta的结果如果在0-255之间,则保持不变;
对于单方向sobel以后,卷积乘到的赋值进行一个变换,可以实现两个方向分别求卷积
效果:
人的轮廓基本上能分割出来
二. Scharr算子和Laplacian算子
特点:对边界识别度更高,缺点是对噪声很敏感
两者算法和Sobel很像,都是求卷积
代码:
1 import cv2 2 import numpy as np 3 4 if __name__ == '__main__': 5 img = cv2.imread('../pics/1.jpg', cv2.IMREAD_GRAYSCALE) 6 7 scharr_x = cv2.Scharr(img, cv2.CV_64F, 1, 0) 8 scharr_x = cv2.convertScaleAbs(scharr_x) 9 scharr_y = cv2.Scharr(img, cv2.CV_64F, 0, 1) 10 scharr_y = cv2.convertScaleAbs(scharr_y) 11 scharr_xy = cv2.addWeighted(scharr_x, 0.5, scharr_y, 0.5, 0) 12 13 laplacian = cv2.Laplacian(img, cv2.CV_64F) 14 laplacian = cv2.convertScaleAbs(laplacian) 15 16 res = np.hstack((scharr_xy, laplacian)) 17 cv2.imshow('img', res) 18 cv2.waitKey()
效果:
三. Canny算法
Canny算法包括下列步骤:
- 滤波消除噪声(Gauss)
- 计算每个像素点的梯度强度和方向
- 非极大值抑制,消除杂散效应
- 双阈值确定边缘
- 抑制过滤的弱边缘,完成检测
非极大值抑制的两种方法:
1.
2.
双阈值检测
梯度值 > max : 处理为边界
min < 梯度值 < max:有边界则保留,否则删除
梯度值 < min: 删除
代码:
canny = cv2.Canny(img, 60, 120) # param2 and param3 are threshold
效果:阈值越大,选取边界范围越小