# -*- 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()
|