# -*- coding: utf-8 -*-
#width = 256, 192
#YSU1100W fast-straight
#YSU1000W fast-left
#YSU0100W fast-right
#YSU1101W slow-s
#YSU1001W s-l
#YSU0101W s-r
#YSU0010W find
import numpy as np
import cv2
import serial
import time
#设定红色阈值,HSV空间
redLower = np.array([0, 0, 230])
redUpper = np.array([10, 255, 237])
#初始化质心
center = 0
#初始化串口
ser = serial.Serial("/dev/ttyUSB0",9600)
# s = 0
#打开摄像头
camera = cv2.VideoCapture(0)
camera.set(3, 320)
camera.set(4, 240)
#遍历每一帧,检测信标灯
while True:
# s = ser.read(8)
# # 如果读到单片机传过来的信号,倒车
# if s:
# ser.write("YSU0000W".encode())
# print("back")
# time.sleep(3)
# s = 0
#读取帧
(ret, frame) = camera.read()
#判断是否成功打开摄像头
if not ret:
# print ('No Camera')
break
#转到HSV空间
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
#根据阈值构建掩膜 黑白 亮的为阈值内区域
mask = cv2.inRange(hsv, redLower, redUpper)
#腐蚀操作 iterations:迭代次数
mask = cv2.erode(mask, None, iterations=1)
#膨胀操作,其实先腐蚀再膨胀的效果是开运算,去除噪点
mask = cv2.dilate(mask, None, iterations=14)
#根据灰度值化为二值图
# GrayImage=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# ret, gray=cv2.threshold(GrayImage, 230, 255, cv2.THRESH_BINARY)
#把红色分的二值图和灰度二值图叠加
# andout = cv2.bitwise_and(mask, gray)
#检测寻找轮廓 cv2.RETR_EXTERNAL 只得到最外面的轮廓
#cv2.findContours() opencv3会返回三个值,分别是img, countours, hierarchy
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
#初始化圆形轮廓质心
center = None
#如果存在轮廓
if len(cnts) > 0:
#找到面积最大的轮廓
c = max(cnts, key = cv2.contourArea)
#确定面积最大的轮廓的最小外接圆
((x, y), radius) = cv2.minEnclosingCircle(c)
#计算轮廓的矩
M = cv2.moments(c)
#计算质心
try:
center = (int(M["m10"]/M["m00"]), int(M["m01"]/M["m00"]))
except:
continue
#只有当半径大于1时,才执行
if radius >= 1:
#画轮廓圆:img,center,radius,color 厚度:负值就是实心
cv2.circle(frame, (int(x), int(y)), int(radius), (0, 255, 255), 1)
#在质心中间画半径为5的点
cv2.circle(frame, center, 5, (0, 0, 255), -1)
#最关键的值pos,相对于画面中心的x方向像素差
pos = center[0]-160
# print("x=%s"%pos)
# print(radius)
try:
#通过x坐标控制串口
# if radius >= 60:
# t = 0
# while True:
# t += 0.05
# if t >= 0.4:
# break
# ser.write("YSU1101W".encode())
# time.sleep(0.05)
#减速 拐角大
if radius >= 100:
#向左转
if pos < -50:
ser.write("YSU1001W".encode())
#直线
elif -50 <= pos <= 50:
ser.write("YSU1101W".encode())
#向右转
else:
ser.write("YSU0101W".encode())
# 正常速度,拐角大
elif 50 <= radius < 100:
if pos < -45:
ser.write("YSU0001W".encode())
elif -45 <= pos <= 45:
ser.write("YSU1100W".encode())
else:
ser.write("YSU0110W".encode())
#正常速度,拐角小
else:
#向左转
if pos < -30:
ser.write("YSU1000W".encode())
#直线
elif - 30<= pos <= 30:
ser.write("YSU1100W".encode())
#向右转
else:
ser.write("YSU0100W".encode())
except:
continue
else:
ser.write("YSU0010W".encode())
else:
ser.write("YSU0010W".encode())
#cv2.imshow('Frame', frame)
#键盘检测,检测到esc键退出
k = cv2.waitKey(1)&0xFF
if k == 27:
break
#摄像头释放
camera.release()
#销毁所有窗口
# cv2.destroyAllWindows()
#关闭串口
ser.close()
|