Advertisement
Guest User

Messenger Basketball Player

a guest
Mar 26th, 2016
536
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.08 KB | None | 0 0
  1. import cv2 as cv
  2. import numpy as np
  3. import sys
  4. from math import acos, asin, cos, pi
  5. from time import sleep
  6. import serial
  7.  
  8.  
  9. # define thresholds
  10. BALL = {
  11.     'thresh': [np.array([0, 45, 15]), np.array([21, 255, 255])],
  12.     'area': [20000, 25000],
  13.     'loc_x': [600, 900],
  14.     }
  15. BASKET = {
  16.     'thresh': [np.array([0, 30, 83]), np.array([216, 255, 255])],
  17.     'area': [2015, 3914],
  18.     'loc_x': [150, 450],
  19.     }
  20.  
  21. BLOB_DATA = [BALL, BASKET]
  22.  
  23. # crop bounds
  24. CROP = [[543, 257], [1413, 808]]
  25.  
  26. # blur kernel
  27. GAUS_KERNEL = np.ones((3, 3), np.float32)/15
  28.  
  29. # robot home position
  30. HOME = [0, 55]
  31.  
  32. # aim time for the shoot
  33. SHOOT_DELAY = 0.2
  34. INFER_DELAY = 1.50
  35.  
  36. # tick frequency (used for timing between frames to get velocities in px/sec)
  37. FREQUENCY = cv.getTickFrequency()
  38.  
  39. # kernel for morphological operations performed on the binary images
  40. MORPH_KERNEL = np.ones((4, 4),np.uint8)
  41.  
  42. COM_PORT = "COM3"
  43. BAUD = 115200
  44. TIMEOUT = 0.1
  45.  
  46. SERVO_CALIB = [
  47.     [93, 0.8556],
  48.     [80, 0.8556],
  49.     [80, 20],
  50. ]
  51.  
  52. VIDEO_ENCODER = cv.VideoWriter_fourcc(*'MRLE')
  53.  
  54. LOG_VIDEO = True
  55.  
  56. def end():
  57.     """ End the program """
  58.     cam.release()
  59.     video_out.release()
  60.     cv.destroyAllWindows()
  61.     ser.close()
  62.     sys.exit()
  63.  
  64. def write_servo(ser_obj, pin, val):
  65.     ser_obj.write(chr(pin))
  66.     ser_obj.write(chr(val))
  67.  
  68. def send_move(pixel_coord, absolute=False):
  69.     if not absolute:
  70.         coord = [0, 0]
  71.         coord[0] = 23.91 - 0.001115 * pixel_coord[0] - 0.1089 * pixel_coord[1]
  72.         coord[1] = 165 - 0.1177 * pixel_coord[0] - 0.006929 * pixel_coord[1]
  73.     else:
  74.         coord = pixel_coord
  75.  
  76.     theta = [0, 0]
  77.  
  78.     theta[1] = asin(coord[0] / float(42))
  79.     a = coord[1] - 42 * cos(theta[1])
  80.     theta[0] = asin((50 - a) / 38)
  81.     theta[1] *= -1
  82.  
  83.     theta = [x * 180 / pi for x in theta]
  84.  
  85.     for i, angle in enumerate(theta):
  86.         calib = SERVO_CALIB[i]
  87.         write_servo(ser, i, int(calib[0] + calib[1] * angle))
  88.         sleep(0.001)
  89.  
  90. def pen(activate):
  91.     if activate:
  92.         write_servo(ser, 2, 22)
  93.         pass
  94.     else:
  95.         write_servo(ser, 2, 80)
  96.         pass
  97.     sleep(0.001)
  98.  
  99. cam = cv.VideoCapture(0)
  100.  
  101. video_out = cv.VideoWriter('test.avi', -1, 20.0, (CROP[1][0] - CROP[0][0], CROP[1][1] - CROP[0][1]))
  102.  
  103. cam.set(3, 1920)
  104. cam.set(4, 1080)
  105.  
  106. prev_pos = [0, 0]
  107. prev_tick = cv.getTickCount()
  108.  
  109. # vector of previous velocities for running average
  110. vel_ave = [np.zeros(40, np.float32), np.zeros(40, np.float32)]
  111. # bounds of the basket movement
  112. bounds_ave = [
  113.     [np.zeros(3, np.float32), np.zeros(3, np.float32)],
  114.     [np.zeros(3, np.float32), np.zeros(3, np.float32)]
  115.     ]
  116. bounds = [[0, 0], [0, 0]]
  117.  
  118. # open serial port to the Arduino
  119. ser = serial.Serial(COM_PORT, BAUD, timeout=TIMEOUT)
  120. # wait for port to settle
  121. sleep(2)
  122.  
  123. # move to home position and deactivate pen
  124. send_move(HOME, absolute=True)
  125. pen(0)
  126.  
  127. # number of frames since the last shot. Allows for some settling since last shot
  128. shot = 0
  129.  
  130. # current (and previous frame) sign of the velocity vector
  131. sign = [0, 0]
  132. prev_sign = [0, 0]
  133.  
  134. # predicted location of basket after shooting
  135. pred_loc = [0, 0]
  136.  
  137. # occasionally used for camera positioning. Keeps a cropped stream visible
  138. while(True):
  139.     # quit if q is pressed
  140.     ret, frame = cam.read()
  141.     frame = frame[CROP[0][1]:CROP[1][1], CROP[0][0]:CROP[1][0]]
  142.     if ret:
  143.         video_out.write(frame)
  144.         cv.imshow('Video Stream', frame)
  145.     else:
  146.         break
  147.  
  148.     if cv.waitKey(1) & 0xFF == ord(' '):
  149.         break
  150.  
  151. while(True):
  152.     # quit if q is pressed
  153.     if cv.waitKey(1) & 0xFF == ord('q'):
  154.         end()
  155.  
  156.     # get frame and crop
  157.     ret, frame = cam.read()
  158.     frame = frame[CROP[0][1]:CROP[1][1], CROP[0][0]:CROP[1][0]]
  159.  
  160.     # make copy for imshowing at the end
  161.     original = frame.copy()
  162.  
  163.     # apply blur
  164.     frame = cv.filter2D(frame, -1, GAUS_KERNEL)
  165.  
  166.     # convert to hsv
  167.     hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
  168.  
  169.     # make binary image of ball and basket
  170.     ball_bin = cv.inRange(hsv, BALL['thresh'][0], BALL['thresh'][1])
  171.     basket_bin = cv.inRange(hsv, BASKET['thresh'][0], BASKET['thresh'][1])
  172.  
  173.     # copy images to keep originals for imshowing at the end
  174.     # ball_bin_original = ball_bin.copy()
  175.     # basket_bin_original = basket_bin.copy()
  176.  
  177.     # process binary images to retrieve contours of points of interest
  178.     binaries = [ball_bin, basket_bin]
  179.     poi_coords = []
  180.     # contours = []
  181.     for i in range(len(binaries)):
  182.         # filter noise
  183.         binaries[i] = cv.erode(binaries[i], MORPH_KERNEL, iterations=1)
  184.         binaries[i] = cv.dilate(binaries[i], MORPH_KERNEL, iterations=3)
  185.  
  186.         # find contours
  187.         _, new_contours, heirarchy = cv.findContours(binaries[i].copy(),
  188.             cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
  189.  
  190.         coords = []
  191.         # filter contours
  192.         # filtered_contours = []
  193.         for contour in new_contours:
  194.             area = cv.contourArea(contour)
  195.             if BLOB_DATA[i]['area'][0] < area < BLOB_DATA[i]['area'][1]:
  196.                 # filtered_contours.append(contour)
  197.                 moments = cv.moments(contour)
  198.                 centroid_x = int(moments['m10']/moments['m00'])
  199.                 centroid_y = int(moments['m01']/moments['m00'])
  200.                 if BLOB_DATA[i]['loc_x'][0] < centroid_x < BLOB_DATA[i]['loc_x'][1]:
  201.                     coords = [centroid_x, centroid_y]
  202.         # contours.append(filtered_contours)
  203.         if coords == []:
  204.             continue
  205.         poi_coords.append(coords)
  206.  
  207.     # make contours frame to display contours
  208.     # contours_frame = original.copy()
  209.     # _ = cv.drawContours(contours_frame, contours[0], -1, (255,0,0), 3)
  210.     # _ = cv.drawContours(contours_frame, contours[1], -1, (0,255,0), 3)
  211.  
  212.     if len(poi_coords) != 2:
  213.         print("lost")
  214.         # cv.imshow('contour', contours_frame)
  215.         continue
  216.  
  217.     # extract ball and basket coords
  218.     ball_coord = poi_coords[0]
  219.     basket_coord = poi_coords[1]
  220.  
  221.     # get time
  222.     time = (cv.getTickCount() - prev_tick) / FREQUENCY
  223.     # calc instantaneous basket velocity vector
  224.     vel = [(x - y) / float(time) for x, y in zip(prev_pos, basket_coord)]
  225.  
  226.     # add the calculated velocities to the average list
  227.     for i in range(len(vel_ave)):
  228.         vel_ave[i] = np.concatenate(([abs(vel[i])], vel_ave[i][:-1]))
  229.  
  230.     # predict location of basket after throwing
  231.     for i in range(len(pred_loc)):
  232.         pred_loc[i] = basket_coord[i] - int(INFER_DELAY * sign[i] * np.average(vel_ave[i]))
  233.  
  234.     # detect and store movement bounds
  235.     for i in range(len(vel)):
  236.         if vel[i] != 0:
  237.             prev_sign[i] = sign[i]
  238.             sign[i] = cmp(vel[i], 0)
  239.  
  240.             if prev_sign[i] != sign[i] and shot > 20:
  241.                 j = 0
  242.                 if prev_sign[i] > 0:
  243.                     j = 1
  244.                 bounds_ave[i][j] = np.concatenate(([basket_coord[i]], bounds_ave[i][j][:-1]))
  245.                 bounds[i][j] = np.average(bounds_ave[i][j])
  246.                 # print(bounds_ave)
  247.  
  248.     # detect if bounds have been reached
  249.     for i in range(len(bounds)):
  250.         if pred_loc[i] > bounds[i][0] and np.average(vel_ave[i]) > 5:
  251.             pred_loc[i] = int(2 * bounds[i][0] - pred_loc[i])
  252.         elif pred_loc[i] < bounds[i][1] and np.average(vel_ave[i]) > 5:
  253.             pred_loc[i] = int(2 * bounds[i][1] - pred_loc[i])
  254.  
  255.     prev_tick = cv.getTickCount()
  256.     prev_pos = basket_coord[:]
  257.  
  258.     points_frame = original.copy()
  259.     points_frame = cv.circle(points_frame, tuple(poi_coords[0]), 20, (0,0,255), -1)
  260.     points_frame = cv.circle(points_frame, tuple(poi_coords[1]), 20, (0,255,0), -1)
  261.     points_frame = cv.circle(points_frame, tuple(pred_loc), 20, (255,0,0), -1)
  262.  
  263.     points_frame = cv.circle(points_frame, tuple(ball_coord), 20, (0,255,255), -1)
  264.  
  265.     shot += 1
  266.  
  267.     # print(str(np.std(vel_ave)) + " " + str(ball_coord[1]) + " " + str(pred_loc[1]))
  268.  
  269.     if pred_loc[0] < 310 and (np.average(vel_ave[1]) < 5 or (np.std(vel_ave[0]) < 30 and np.std(vel_ave[1]) < 45 and ball_coord[1]-15 < pred_loc[1] < ball_coord[1]+15 and np.std(bounds_ave[0][0]) < 20 and np.std(bounds_ave[0][1]) < 20 and np.std(bounds_ave[1][0]) < 20 and np.std(bounds_ave[1][1]) < 20)) and shot > 20:
  270.         print("shoot {0}, {1}".format(ball_coord, pred_loc))
  271.  
  272.         m = (pred_loc[1] - ball_coord[1]) / float(pred_loc[0] - ball_coord[0])
  273.         c = ball_coord[1] - m * ball_coord[0]
  274.  
  275.         MAX_PIX = 340
  276.  
  277.         increments = 20
  278.         time_step = SHOOT_DELAY / float(increments)
  279.         x_step = (MAX_PIX - ball_coord[0]) / float(increments)
  280.         x = ball_coord[0]
  281.  
  282.         send_move(ball_coord)
  283.         pen(1)
  284.         sleep(0.6)
  285.         for i in range(increments):
  286.             if i == int(increments * 0.60):
  287.                 pen(0)
  288.             send_move([x, m * x + c])
  289.             x += x_step
  290.             sleep(time_step)
  291.         pen(0)
  292.         send_move(HOME, absolute=True)
  293.         sleep(1)
  294.         shot = 0
  295.  
  296.     # show images
  297.     # cv.imshow('ball', ball_bin)
  298.     # cv.imshow('basket', basket_bin)
  299.     # cv.imshow('frame', frame)
  300.     cv.imshow('points', points_frame)
  301.     # cv.imshow('contour', contours_frame)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement