通过Opencv进行边缘检测可以说是十分常见了,接下来让我们聊一聊如何通过python opencv一步一步实现边缘检测
pic = cv2.imread(file_path, flag=None)
参数:
返回值:
注意:结果可能与 cvtColor() 的输出不同。编解码器附带 OpenCV 图像(libjpeg、默认使用 libpng、libtiff 和 libjasper)。因此,OpenCV 始终可以读取 JPEG、PNG、TIFF。而Linux需要安装随操作系统映像提供的编解码器libjpeg-dev
cap = cv2.VideoCapture(CAMERA_ID)
参数
返回值
ret, frame = cap.read()
返回值
gs_frame=cv2.GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)
说明:将源图像与指定的高斯核进行卷积
参数
OpenCV中的inRange()函数可实现二值化功能(这点类似threshold()函数
inRange_hsv=cv2.inRange((InputArray src, InputArray lowerb,InputArray upperb, OutputArray dst)
参数
返回值
img_erosion=cv2.erode(src, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
说明:通过使用特定的结构元素侵蚀图像。该函数使用确定的指定结构元素侵蚀源图像,取最小值的像素邻域的形状.侵蚀可以应用几次(迭代),对于多通道图像,每个通道都是独立处理的。
参数
返回值
说明:通过使用特定的结构元素来扩大图像。该函数使用指定的结构元素来扩展源图像,该结构元素确定取最大值的像素邻域的形状。
dilate_img=cv2.dilate(src, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
参数
返回值
morphologyEx_frame=cv2.morphologyEx(src, op, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)
说明:使用腐蚀和膨胀来执行高级形态变换,开操作就是先腐蚀后膨胀
参数
返回值
sobel算子简介:sobel算子认为,邻域的像素对当前像素产生的影响不是等价的,所以距离不同的像素具有不同的权值,对算子结果产生的影响也不同。一般来说,距离越远,产生的影响越小。
sobel算子原理: 对传进来的图像像素做卷积,卷积的实质是在求梯度值,或者说给了一个加权平均,其中权值就是所谓的卷积核;然后对生成的新像素灰度值做阈值运算,以此来确定边缘信息。x方向的梯度会加强图像水平方向的特征,而y方向的梯度会加强图像竖直方向的特征
sobel=cv2.Sobel(src, ddepth, dx, dy, dst=None, ksize=None, scale=None, delta=None, borderType=None)
说明:Sobel 算子结合了高斯平滑和微分,所以结果或多或少耐噪音。大多数情况下,函数被调用( xorder = 1, yorder = 0, ksize = 3)或 ( xorder = 0, yorder = 1, ksize = 3) 计算第一个 x 或 y 图像导数。
参数
dst=cv2.convertScaleAbs(src, dst=None, alpha=None, beta=None)
说明:由于sobel算子算出的值会产生负值,否则负数会一律当做0处理,所以要使用取绝对值函数。在输入数组的每个元素上,函数 convertScaleAbs依次执行三个操作:缩放、取绝对值,转换为无符号 8 位类型。在多通道数组的情况下,该函数处理每个通道独立。当输出不是 8 位时,操作可以是通过调用 Mat::convertTo 方法(或使用矩阵表达式),然后计算结果的绝对值。
参数
add_weight_img=cv2.addWeighted(src1, alpha, src2, beta, gamma, dst=None, dtype=None)
说明:计算两个数组的加权和: dst = src1alpha + src2beta + gamma
参数
scharr_img=cv2.Scharr(src, ddepth, dx, dy, dst=None, scale=None, delta=None, borderType=None)
说明:虽然Sobel算子可以有效的提取图像边缘,但是对图像中较弱的边缘提取效果较差。因此为了能够有效的提取出较弱的边缘,需要将像素值间的差距增大。Scharr算子是对Sobel算子差异性的增强,因此两者之间的在检测图像边缘的原理和使用方式上相同。Scharr算子的边缘检测滤波的尺寸为3×3,因此也有称其为Scharr滤波器。可以通过将滤波器中的权重系数放大来增大像素值间的差异.
参数
canny_img=cv2.Canny(image, threshold1, threshold2, edges=None, apertureSize=None, L2gradient=None)
说明:在输入图像中找到边缘,并使用精明算法。阈值 1 和阈值 2 之间的最小值用于边缘链接。这最大值用于查找强边缘的初始段。
参数
contours, hierarchy=cv2.findContours(image, mode, method, contours=None, hierarchy=None, offset=None):
说明:从二进制图像中检索轮廓。
参数
image:一般为sobel算子或者scharr算子得到的二值化图像。8 位单通道图像。非零像素被视为 1。零像素保持为 0,因此图像被视为 binary
mode:
method
contours:检测的轮廓数组,每一个轮廓用一个point类型的vector表示
hierarchy:和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][0 ] ~hierarchy[ i ][ 3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。
offset:每个轮廓点移动的可选偏移量
返回值
cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)
说明:绘制轮廓轮廓或填充轮廓
参数
源代码:
import cv2
import numpy as np
# 选择图片检测或者选择视频检测
is_picture = True
file_path = '../Picture/Badminton.jpeg'
# 识别OpencCV书的阈值:'red': {'Lower': np.array([0, 53, 66]), 'Upper': np.array([74, 76, 187])
# 这个是颜色的HSV的范围值(分别代表的是H,S,V),可以根据需求进行删改
color_dist = {'red': {'Lower': np.array([0, 53, 66]), 'Upper': np.array([74, 76, 187])},
'blue': {'Lower': np.array([100, 80, 46]), 'Upper': np.array([124, 255, 255])},
'green': {'Lower': np.array([77, 54, 47]), 'Upper': np.array([166, 255, 255])},
'yellow': {'Lower': np.array([26, 43, 46]), 'Upper': np.array([34, 255, 255])},
}
class DetectProcess(object):
def __init__(self):
super(DetectProcess, self).__init__()
# 形态学腐蚀操作:cv2.erode
def erode(self, img):
# 创建腐蚀使用的内核:3x3和5x5
kernel = np.ones((3, 3), np.uint8)
# 执行腐蚀操作 iterations表示执行腐蚀的次数
img_erosion = cv2.erode(img, kernel, iterations=1)
return img_erosion
# 形态学膨胀:cv2.dilate
def dilate(self, img):
kernel = np.ones((5, 5), np.uint8)
dilation = cv2.dilate(img, kernel, iterations=1)
return dilation
# 开运算:cv2.morphologyEx() :先腐蚀再膨胀,有助于消除噪音.
def morphologyExOpening(self, img):
kernel = np.ones((5, 5), np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
return opening
# 闭运算:用于消除前景对象内的小孔或对象上的小黑点
def morphologyExClosing(self, img):
kernel = np.ones((5, 5), np.uint8)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
return closing
# sobel算子:返回的图像通道和原图相同,即彩色图像处理后仍为3通道
# sobel得到的图像是有许多小点的的
def sobel(self, img):
# 核函数的取值范围:1,3,5,7,9,核函数过大效果不好
Ksize = 3
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=Ksize)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=Ksize)
# sobel-x方向
sobel_X = cv2.convertScaleAbs(sobelx)
# sobel-y方向
sobel_Y = cv2.convertScaleAbs(sobely)
# sobel-xy方向
sobel_XY = cv2.addWeighted(sobel_X, 0.5, sobel_Y, 0.5, 0)
return sobel_XY
# Scharr算子:返回的图像通道和原图相同,即彩色图像处理后仍为3通道
def scharr(self, img):
scharr_x = cv2.Scharr(img, cv2.CV_8U, 1, 0)
scharr_y = cv2.Scharr(img, cv2.CV_8U, 0, 1)
scharrX = cv2.convertScaleAbs(scharr_x)
scharrY = cv2.convertScaleAbs(scharr_y)
scharr_XY = cv2.addWeighted(scharrX, 0.5, scharrY, 0.5, 0)
return scharr_XY
# Canny:返回的为单通道图像
# 得到的是一条淡颜色的线
def canny(self, img):
# 核函数的取值为3,5,7
# 高低阈值maxVal和minVal的取值范围1-255
# L2g为“精准”标识符,参数为True和False
Ksize = 3
minVal = 20
maxVal = 40
L2g = True
Canny = cv2.Canny(img, minVal, maxVal, apertureSize=Ksize, L2gradient=False)
return Canny
# 对轮廓的面积进行筛选
def areaFilter(contours):
"""
对面积进行筛选,若大于900的面积我们才认为是有效的边缘,这个可以根据自己的需求进行调整
:param contours: 轮廓的集合
:return: 识别到的有效的轮廓集合
"""
areas = []
for i in range(len(contours)):
if cv2.contourArea(contours[i]) <= 900:
continue
else:
areas.append(contours[i])
return areas
# areas.sort()
# print("area is:", areas)
if __name__ == '__main__':
detect = DetectProcess()
# 调用摄像头
cap = cv2.VideoCapture(0)
while True:
if is_picture:
frame = cv2.imread(file_path)
else:
# 读取视频帧,ret标志读取的结果,frame为读取到的视频帧图像
ret, frame = cap.read()
# 高斯滤波
gs_frame = cv2.GaussianBlur(frame, (5, 5), 0)
# 转化成HSV图像
hsv = cv2.cvtColor(gs_frame, cv2.COLOR_BGR2HSV)
# 规定红色区域的HSV.
# OpenCV中的inRange()函数可实现二值化功能(这点类似threshold()函数
# cv2.inRange((InputArray src, InputArray lowerb,InputArray upperb, OutputArray dst);
# 参数1:输入要处理的图像,可以为单通道或多通道。
# 参数2:包含下边界的数组或标量。
# 参数3:包含上边界数组或标量。
# 参数4:输出图像,与输入图像src 尺寸相同且为CV_8U 类型。也可以作为返回值处理
inRange_hsv = cv2.inRange(hsv, color_dist['green']['Lower'], color_dist['green']['Upper'])
cv2.imshow('inRange_hsv', inRange_hsv)
# 形态学腐蚀操作
erode_frame = detect.erode(inRange_hsv)
cv2.imshow('erode', erode_frame)
# 形态学膨胀操作
dilate_frame = detect.dilate(erode_frame)
cv2.imshow('dilate', dilate_frame)
# 开运算
morphologyExOpening_frame = detect.morphologyExOpening(inRange_hsv)
cv2.imshow('morphologyExOpening', morphologyExOpening_frame)
# 闭运算
morphologyExClosing_frame = detect.morphologyExClosing(morphologyExOpening_frame)
cv2.imshow('morphologyExClosing', morphologyExClosing_frame)
# Sobel_frame
Sobel_frame = detect.sobel(morphologyExClosing_frame)
cv2.imshow('Sobel_frame', Sobel_frame)
# 寻找外部的点:建立RETR_EXTERNAL来统计最大外围的点。
contours, hierarchy = cv2.findContours(Sobel_frame.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# cnt = contours[1:50] 这个表示的是提取的图像的范围
cv2.drawContours(frame, areaFilter(contours), -1, (0, 0, 255), 2)
cv2.imshow('result', frame)
if cv2.waitKey(1) & 0xFF == 27:
break
cv2.destroyAllWindows()