(接上篇博客[Arduino 智能机器人 按指令行走])(http://blog.csdn.net/qazwyc/article/details/56969383)
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install python-opencv
sudo apt-get install python-pip
sudo apt-get install python-dev
sudo pip install picamera
import cv2
import cv2.cv as cv
import cv
import picamera
import picamera.array
import math
import numpy as np
import zmq
import time
import serial, time, sys
from PIL import Image
# For OpenCV2 image display
IMAGE_WINDOW_NAME = 'YelloBarTracker'
CONTROL_WINDOW_NAME = 'Control'
MASK_WINDOW_NAME = 'Mask'
# For socket communication
port = '5556'
context = zmq.Context()
socket = context.socket(zmq.PUB)
# Setting the initial mask threshold
# 根据环境调试数据以便准确的捕捉小球
iLowH = 5
iHighH = 22
iLowS = 219
iHighS = 255
iLowV = 149
iHighV = 255
# 是否抓到球
getball = 0
# connect arduino
# 将arduino接到树莓派上,输入ls /dev查看,我的是ttyUSB0
def connect_arduino():
arduino = serial.Serial('/dev/ttyUSB0',9600,timeout=1)
arduino.close()
arduino.open()
return arduino
# Require by cv2.createTrackbar. we have nothing to do with nothing method
def nothing(var):
pass
def connect():
print('Getting data from camera...')
socket.bind('tcp://*:%s' % port)
# Create trackbars for easier adjustment of the HSV threshold 方便手动调节区间
def make_hsv_adjustment():
cv2.namedWindow(CONTROL_WINDOW_NAME)
cv2.createTrackbar('LowH', CONTROL_WINDOW_NAME, iLowH, 255, nothing); #Hue (0 - 179)
cv2.createTrackbar('HighH', CONTROL_WINDOW_NAME, iHighH, 255, nothing);
cv2.createTrackbar('LowS', CONTROL_WINDOW_NAME, iLowS, 255, nothing); #Saturation (0 - 255)
cv2.createTrackbar('HighS', CONTROL_WINDOW_NAME, iHighS, 255, nothing);
cv2.createTrackbar('LowV', CONTROL_WINDOW_NAME, iLowV, 255, nothing); #Value (0 - 255)
cv2.createTrackbar('HighV', CONTROL_WINDOW_NAME, iHighV, 255, nothing);
def track(image):
'''Accepts BGR image as Numpy array
Returns: (x,y) coordinates of centroid if found
(-1,-1) if no centroid was found
None if user hit ESC
'''
# Blur the image to reduce noise
blur = cv2.GaussianBlur(image, (5,5),0)
# Convert BGR to HSV
hsv = cv2.cvtColor(blur, cv2.COLOR_BGR2HSV)
# Get the treshold from the trackbars
iLowH = cv2.getTrackbarPos('LowH', CONTROL_WINDOW_NAME)
iHighH = cv2.getTrackbarPos('HighH', CONTROL_WINDOW_NAME)
iLowS = cv2.getTrackbarPos('LowS', CONTROL_WINDOW_NAME)
iHighS = cv2.getTrackbarPos('HighS', CONTROL_WINDOW_NAME)
iLowV = cv2.getTrackbarPos('LowV', CONTROL_WINDOW_NAME)
iHighV = cv2.getTrackbarPos('HighV', CONTROL_WINDOW_NAME)
# Threshold the HSV image for only green colors
lower_yellow = np.array([iLowH,iLowS,iLowV])
upper_yellow = np.array([iHighH,iHighS,iHighV])
# Threshold the HSV image to get only yellow colors
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
cv2.imshow(MASK_WINDOW_NAME, mask)
# Blur the mask
bmask = cv2.GaussianBlur(mask, (5,5),0)
# Take the moments to get the centroid
moments = cv2.moments(bmask)
m00 = moments['m00']
centroid_x, centroid_y, radius = None, None, None
if m00 != 0:
centroid_x = int(moments['m10']/m00)
centroid_y = int(moments['m01']/m00)
radius = int(math.sqrt(m00 / 255 / 3.14159265358979323846))
# Assume no centroid
ball = (-1,-1, 0)
# Use centroid if it exists
if centroid_x != None and centroid_y != None and radius != None:
ball = (centroid_x, centroid_y, radius) # 中心坐标及半径
# Put red circle in at centroid in image
cv2.circle(image, (centroid_x, centroid_y), 4, (255,0,0)) # center
cv2.circle(image, (centroid_x, centroid_y), radius, (0,255,0))
# Display full-color image
cv2.imshow(IMAGE_WINDOW_NAME, image)
# Force image display, setting centroid to None on ESC key input
if cv2.waitKey(1) & 0xFF == 27:
ball = None
# Return coordinates of ball
return ball
if __name__ == '__main__':
connect()
make_hsv_adjustment();
arduino = connect_arduino();
with picamera.PiCamera() as camera:
with picamera.array.PiRGBArray(camera) as stream:
camera.resolution = (320, 240)
while True:
camera.capture(stream, 'bgr', use_video_port=True)
# stream.array now contains the image data in BGR order
image = stream.array
ball = track(image)
if not ball:
break
if cv2.waitKey(1) & 0xFF == 27:
break
msg = '%d %d %d' % ball
print(msg)
socket.send(msg)
# try
# 未抓到球时发现距离较近,尝试抓取
if ball[2] > 55 and getball == 0:
# 前进一步
arduino.write('1')
# 夹取
arduino.write('s')
# 假设夹取到
getball = 1
# 已成功夹取到
elif ball[2] > 55 and getball == 1:
# 小车停止
arduino.write('9')
break;
# 未成功抓取 释放夹手
else:
arduino.write('r')
getball = 0
if getball == 0:
# 前方未发现有小球
if ball[2] <= 2:
# 原地右转
arduino.write('8')
arduino.write('9')
else:
# 小球在前方偏右 (摄像头安装时是倒的)
if ball[0] < 130 and ball[2] <= 20:
# 原地右转
arduino.write('8')
arduino.write('9')
# 小球在前方偏左
elif ball[0] > 190 and ball[2] <= 20:
# 原地左转
arduino.write('7')
arduino.write('9')
else:
arduino.write('1')
# reset the stream before the next capture
stream.seek(0)
stream.truncate()
time.sleep(1);
# 完成夹取小球的任务后可以通过在控制台敲入指令控制小车
while True:
cmd = sys.stdin.readline()
arduino.write(cmd)
cv2.destroyAllWindows()
(实训时做的,水平有限,易受环境光照影响,小车找寻与抓取速度也较慢,仅供参考)