一.目的
写这篇文章记录自己在打工训赛的时候遇到的问题以及解决方案,为以后自己的复习留下文章
二.智能救援项目
1.项目介绍
智能救援项目是在一块方向区域内,两辆全自动小车实现自动寻找目标,到达位置,抓取目标,将目标放置在规定区域。
2.大体思路
通过摄像头找到小球的位置,识别颜色,获取坐标,这里的坐标是小球在屏幕上的位置以及小球的半径,还需要进行计算获取小球关于小车的位置,当获取小球关于小车位置之后,将信号发送给小车,小车到达目标位置,抓取小球,再进行识别兑换区域,当到达后将小球放置其中即可。
难点:
1.如何精确识别小球,并获取其位置
2.如何识别兑换区域
三.技术实现
1.识别不同颜色的小球
思路:
HSV处理
1.通过将图片转化为HSV格式
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
2.将HSV三通道分离
h, s, v = cv2.split(hsv)
3.通过调整HSV三通道,各个通道阈值,使得想要出现的颜色最明显
h_binary = cv2.inRange(np.array(h), np.array(hmin), np.array(hmax))
s_binary = cv2.inRange(np.array(s), np.array(smin), np.array(smax))
v_binary = cv2.inRange(np.array(v), np.array(vmin), np.array(vmax))
4.将三通道合并
binary = cv2.bitwise_and(h_binary, cv2.bitwise_and(s_binary, v_binary))
到这里完成了基本的处理,将不同颜色的球分开
这里需要对于每个颜色调整,重新运行程序十分费劲,滑动条实时调整比较方便一些
1.初始化窗口
cv2.namedWindow('h_binary')
cv2.namedWindow('s_binary')
cv2.namedWindow('v_binary')
2.创建轨迹条
cv2.createTrackbar('hmin', 'h_binary', 6, 179, nothing)
cv2.createTrackbar('hmax', 'h_binary', 26, 179, nothing)
cv2.createTrackbar('smin', 's_binary', 110, 255, nothing)
cv2.createTrackbar('smax', 's_binary', 255, 255, nothing)
cv2.createTrackbar('vmin', 'v_binary', 140, 255, nothing)
cv2.createTrackbar('vmax', 'v_binary', 255, 255, nothing)
参数
parameter1:滑动条名称
parameter2:添加到哪个窗口
parameter3:滑动条初始值
parameter4:滑动条最大值(最小值为0)
3.获取轨迹条的值
hmin = cv2.getTrackbarPos('hmin', 'h_binary')
hmax = cv2.getTrackbarPos('hmax', 'h_binary')
smin = cv2.getTrackbarPos('smin', 's_binary')
smax = cv2.getTrackbarPos('smax', 's_binary')
vmin = cv2.getTrackbarPos('vmin', 'v_binary')
vmax = cv2.getTrackbarPos('vmax', 'v_binary')
cv2.getTrackbarPos() 是回调函数,获取的是之前创建的轨迹条的值
当我把轨迹条的值一直在循环中赋值给合并前的通道最大值以及最小值,即可实时返回更改后的图像,及时观察图片变化
图片预处理
1.高斯滤波
blur = cv2.GaussianBlur(binary, (13, 13), 0)
2.创建卷积核
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 9))
3.开运算(开运算能够除去孤立的小点,毛刺和小桥,而总的位置和形状不变)
Open = cv2.morphologyEx(blur, cv2.MORPH_OPEN, kernel)
4.闭运算(闭运算能够填平小孔,弥合小裂缝,而总的位置和形状不变)
Close = cv2.morphologyEx(Open, cv2.MORPH_CLOSE, kernel)
圆形检测
圆形检测这里有很多方法,上次去工训只是实验了霍夫圆检测,但霍夫圆检测也存在很多缺陷,用起来很抖
霍夫圆检测
circles = cv2.HoughCircles(Close, cv2.HOUGH_GRADIENT, 2, 20, param1=200, param2=50, minRadius=1, maxRadius=300)
这里会返回数组circles,一个或多个圆形的x,y,r,还有可能没有检测到
画图
1.先判断是否检测到了圆
2.先将circles四舍五入,再转化为uint16型(因为像素没有小数)
3.对circles进行遍历
4.给出圆心以及半径画圆,以及圆心
if type(circles) != type(None): #防止没有找到圆形轮廓
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(img, (i[0],i[1]),i[2],(b,g,r),2) #draw the circle
cv2.circle(img, (i[0],i[1]),2,(b,g,r),3) #draw the center
调用摄像头
1.打开摄像头
capture = cv2.VideoCapture(1) #0默认为笔记本摄像头
2.读取摄像头图片
retval, image = capture.read(1) # 从摄像头中实时读取视频
调用摄像头整体流程
capture = cv2.VideoCapture(0) # 打开笔记本内置摄像头
while (capture.isOpened()): # 笔记本内置摄像头被打开后
retval, image = capture.read(0) # 从摄像头中实时读取视频
cv2.imshow("Video", img) # 在窗口中显示读取到的视频
key = cv2.waitKey(1) # 窗口的图像刷新时间为1毫秒
if key == 27: # 如果按下esc
break
capture.release() # 关闭笔记本内置摄像头
cv2.destroyAllWindows() # 销毁显示摄像头视频的窗口
代码整体流程
1.调试每个颜色,获取各个颜色的hsv参数代码
import cv2
import numpy as np
def nothing(*arg):
pass
#初始化窗口以及进度条
def Trackbar_Init():
# 1 create windows
cv2.namedWindow('h_binary')
cv2.namedWindow('s_binary')
cv2.namedWindow('v_binary')
# 2 Create Trackbar
cv2.createTrackbar('hmin', 'h_binary', 6, 179, nothing)
cv2.createTrackbar('hmax', 'h_binary', 26, 179, nothing)
cv2.createTrackbar('smin', 's_binary', 110, 255, nothing)
cv2.createTrackbar('smax', 's_binary', 255, 255, nothing)
cv2.createTrackbar('vmin', 'v_binary', 140, 255, nothing)
cv2.createTrackbar('vmax', 'v_binary', 255, 255, nothing)
# 创建滑动条 滑动条值名称 窗口名称 滑动条值 滑动条阈值 回调函数
# 在HSV色彩空间下得到二值图
def Get_HSV(image):
# 1 get trackbar's value
hmin = cv2.getTrackbarPos('hmin', 'h_binary')
hmax = cv2.getTrackbarPos('hmax', 'h_binary')
smin = cv2.getTrackbarPos('smin', 's_binary')
smax = cv2.getTrackbarPos('smax', 's_binary')
vmin = cv2.getTrackbarPos('vmin', 'v_binary')
vmax = cv2.getTrackbarPos('vmax', 'v_binary')
# 2 to HSV
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# cv2.imshow('hsv', hsv)
h, s, v = cv2.split(hsv)
# 3 set threshold (binary image)
# if value in (min, max):white; otherwise:black
h_binary = cv2.inRange(np.array(h), np.array(hmin), np.array(hmax))
s_binary = cv2.inRange(np.array(s), np.array(smin), np.array(smax))
v_binary = cv2.inRange(np.array(v), np.array(vmin), np.array(vmax))
# 4 get binary(对H、S、V三个通道分别与操作)
binary = cv2.bitwise_and(h_binary, cv2.bitwise_and(s_binary, v_binary))
# 5 Show
cv2.imshow('h_binary', h_binary)
cv2.imshow('s_binary', s_binary)
cv2.imshow('v_binary', v_binary)
cv2.imshow('binary', binary)
return binary
Trackbar_Init()
capture = cv2.VideoCapture(1) # 打开笔记本内置摄像头
while (capture.isOpened()): # 笔记本内置摄像头被打开后
retval, image = capture.read(1) # 从摄像头中实时读取视频
img = image.copy()
binary = Get_HSV(image)
blur = cv2.GaussianBlur(binary,(9,9),0)
cv2.imshow("blur", blur)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
Open = cv2.morphologyEx(blur, cv2.MORPH_OPEN, kernel)
cv2.imshow("Open", Open)
Close = cv2.morphologyEx(Open, cv2.MORPH_CLOSE, kernel)
cv2.imshow("close", Close)
# 6 Hough Circle detect
circles = cv2.HoughCircles(Close, cv2.HOUGH_GRADIENT, 2, 120, param1=120, param2=100, minRadius=10, maxRadius=300)
# param2:决定圆能否被检测到(越少越容易检测到圆,但相应的也更容易出错)
if type(circles) != type(None): #防止没有找到圆形轮廓
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
cv2.circle(img, (i[0],i[1]),i[2],(0,255,255),2) #draw the circle
cv2.circle(img, (i[0],i[1]),2,(0,0,255),3) #画圆心
cv2.imshow("Video", img) # 在窗口中显示读取到的视频
key = cv2.waitKey(1) # 窗口的图像刷新时间为1毫秒
if key == 27: # 如果按下esc
break
capture.release() # 关闭笔记本内置摄像头
cv2.destroyAllWindows() # 销毁显示摄像头视频的窗口
注:这里主要看调整hsv各个参数的最大值和最小值对于最后整体图像的影响,也就是hsv合成后图像的影响,以及各种滤波操作后的影响,在一个通道中效果很好但是放在整体中可能就不一定喽
2.获取每个颜色的参数之后进行整体识别
import cv2
import numpy as np
def nothing(*arg):
pass
#初始化窗口以及进度条
def Trackbar_Init():
# 1 create windows
cv2.namedWindow('h_binary')
cv2.namedWindow('s_binary')
cv2.namedWindow('v_binary')
# 2 Create Trackbar
cv2.createTrackbar('hmin', 'h_binary', 6, 179, nothing)
cv2.createTrackbar('hmax', 'h_binary', 26, 179, nothing)
cv2.createTrackbar('smin', 's_binary', 110, 255, nothing)
cv2.createTrackbar('smax', 's_binary', 255, 255, nothing)
cv2.createTrackbar('vmin', 'v_binary', 140, 255, nothing)
cv2.createTrackbar('vmax', 'v_binary', 255, 255, nothing)
# 创建滑动条 滑动条值名称 窗口名称 滑动条值 滑动条阈值 回调函数
# 在HSV色彩空间下得到二值图
def Get_HSV(image,hmin,hmax,smin,smax,vmin,vmax):
# 1 get trackbar's value
# 2 to HSV
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
# cv2.imshow('hsv', hsv)
h, s, v = cv2.split(hsv)
# 3 set threshold (binary image)
# if value in (min, max):white; otherwise:black
h_binary = cv2.inRange(np.array(h), np.array(hmin), np.array(hmax))
s_binary = cv2.inRange(np.array(s), np.array(smin), np.array(smax))
v_binary = cv2.inRange(np.array(v), np.array(vmin), np.array(vmax))
# 4 get binary(对H、S、V三个通道分别与操作)
binary = cv2.bitwise_and(h_binary, cv2.bitwise_and(s_binary, v_binary))
# 5 Show
# cv2.imshow('h_binary', h_binary)
# cv2.imshow('s_binary', s_binary)
# cv2.imshow('v_binary', v_binary)
# cv2.imshow('binary', binary)
return binary
def Image_Processing(binary,color):
# 3 Gausi blur
blur = cv2.GaussianBlur(binary, (13, 13), 0)
# 4 Open
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 9))
Open = cv2.morphologyEx(blur, cv2.MORPH_OPEN, kernel)
# 5 Close
Close = cv2.morphologyEx(Open, cv2.MORPH_CLOSE, kernel)
cv2.imshow(color, Close)
# 6 Hough Circle detect
circles = cv2.HoughCircles(Close, cv2.HOUGH_GRADIENT, 1, 20, param1=200, param2=50, minRadius=1, maxRadius=300)
# param2:决定圆能否被检测到(越少越容易检测到圆,但相应的也更容易出错)
# judge if circles is exist
return circles
def draw_circle(img,circles,b,g,r):
if type(circles) != type(None): #防止没有找到圆形轮廓
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
x, y, r = i[0], i[1], i[2]
print(x,y,r)
cv2.circle(img, (i[0],i[1]),i[2],(b,g,r),2) #draw the circle
cv2.circle(img, (i[0],i[1]),2,(b,g,r),3)
capture = cv2.VideoCapture(1) # 打开笔记本内置摄像头
while (capture.isOpened()): # 笔记本内置摄像头被打开后
retval, image = capture.read(1) # 从摄像头中实时读取视频
#img用做绘图,image用作处理
img = image.copy()
#找红球轮廓
binary_red = Get_HSV(image,0,10,43,255,16,255)
circle_red = Image_Processing(binary_red,"red")
draw_circle(img,circle_red,0,0,255)
#找蓝球轮廓
binary_blue = Get_HSV(image,90,133,136,255,20,255)
circle_blue = Image_Processing(binary_blue,"blue")
draw_circle(img,circle_blue,255,0,0)
#找黄球轮廓
binary_yellow = Get_HSV(image,20,27,83,255,155,255)
circle_yellow = Image_Processing(binary_yellow,"yellow")
draw_circle(img,circle_yellow,0,255,255)
#找黑球轮廓
binary_black = Get_HSV(image,0,73,0,255,0,63)
circle_black = Image_Processing(binary_black,"black")
draw_circle(img,circle_black,255,255,255)
cv2.imshow("Video", img) # 在窗口中显示读取到的视频
key = cv2.waitKey(1) # 窗口的图像刷新时间为1毫秒
if key == 27: # 如果按下esc
break
capture.release() # 关闭笔记本内置摄像头
cv2.destroyAllWindows() # 销毁显示摄像头视频的窗口
这里的霍夫圆检测需要多实验,实践出真知
附一张图片,当天弄得时间比较紧张,所以效果不好,多调调参
后期规划:
1.先用这一版opencv结果和stm32单片机进行联调,当可以达到基础的要求之后,再用其他方法提升检测的精准度
2.尝试检测兑换区域
3.在通过yolo增加精确度