1 c++ python opencv numpy computer-vision
我使用本指南制作了一个球跟踪程序:https : //www.pyimagesearch.com/2015/09/14/ball-tracking-with-opencv/
我想问一下,是否有一种方法可以告诉我某个球在特定时间内反弹了多少次。甚至任何我可以用来计算球在地面上的反弹的方法,因为我打算使用该程序来跟踪进行篮球运球训练的人。先感谢您 :)
我想做类似这样的事情:https ://youtu.be/OMXYvkryF1I at 2:26
如果有帮助,这是我的代码:
# import the necessary packages
from collections import deque
#list like data structure will keep prev positions of ball
#can make a trail of the ball from it
import numpy as np
import argparse
import imutils
#this is that guys list of Opencv stuff he uses - got resizing and all - can use pip to get it
#$ pip install --upgrade imutils
import cv2
import time
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video",
help="C:/Object_detection/models-master/research/object_detection/test_images/multi_angle.mp4")
#can put path to video here. That is if it is there
#if not there the program will just use the webcam
ap.add_argument("-b", "--buffer", type=int, default=64,
help="max buffer size")
# this tells max size of deque which is the list with points
args = vars(ap.parse_args())
##Put lower & upper boundaries of colour
#colourLow = (0, 135, 30)
#colourHigh = (19, 255, 255)
#Put lower & upper boundaries of colour
colourLow = (0, 135, 30)
colourHigh = (19, 255, 255)
pts = deque(maxlen=args["buffer"]) #initialises our deque points
# if a video path was not supplied, grab the reference
# to the webcam
# item that tells if we using a video or webcam
if not args.get("video", False):
cap = cv2.VideoCapture(0) #imutils.Video stream item works good with webcam
# otherwise, grab a reference to the video file
else:
cap = cv2.VideoCapture(args["video"]) #this is if the video is supplied
#Loop for video frame capturing
while True:
#calls the read method in our capture module
ret, frame = cap.read()
#if we were running a video from external source and no other frame was taken again for processing
#it means we reached end of video so we break out of loop
if frame is None:
break
frame = imutils.resize(frame, width=800) #smaller frames means faster processing so we resize
blurred = cv2.GaussianBlur(frame, (11, 11), 0) #blur reduces picture noise to allow us to see stuff more clearly
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # converting frame to HSV
# we now masking to get the desired colour only
# we do erosion, dilation and removal of blobs
mask = cv2.inRange(hsv, colourLow, colourHigh) #locates our object in the frame
mask = cv2.erode(mask, None, iterations=2) #erosion
mask = cv2.dilate(mask, None, iterations=2) #removal of blobs
# Will draw outline of ball and find (x, y) center of ball
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)[-2] #this makes sure contour will work on all opencv items
center = None #make the coords of the ball 0 at first
if len(cnts) > 0: # only proceed if at least one contour was found
# finds largest contour mask, then uses this to get minimum enclosing circle and center
c = max(cnts, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
M = cv2.moments(c)
center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"])) #this & above line get centre coords
# only proceed if the radius meets a minimum size
if (radius > 30):
# draw the circle and centroid on the frame,
# then update the list of tracked points
cv2.circle(frame, (int(x), int(y)), int(radius),
(0, 255, 255), 2)
cv2.circle(frame, center, 5, (0, 0, 255), -1)
# update list of points
pts.appendleft(center)
# loop over set of points
for i in range(1, len(pts)):
#if we don't have tracked points we should ignore them
if pts[i - 1] is None or pts[i] is None:
continue
ickk = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5)
def drawline(img,pt1,pt2,color,thickness=ickk,style='dotted',gap=20):
dist =((pt1[0]-pt2[0])**2+(pt1[1]-pt2[1])**2)**.5
pts= []
for i in np.arange(0,dist,gap):
r=i/dist
x=int((pt1[0]*(1-r)+pt2[0]*r)+.5)
y=int((pt1[1]*(1-r)+pt2[1]*r)+.5)
p = (x,y)
pts.append(p)
if style=='dotted':
for p in pts:
cv2.circle(img,p,thickness,color,-1)
else:
s=pts[0]
e=pts[0]
i=0
for p in pts:
s=e
e=p
if i%2==1:
cv2.line(img,s,e,color,thickness)
i+=1
#if we do we will draw point connecting line
#gotta define the thickness first
thickness = int(np.sqrt(args["buffer"] / float(i + 1)) * 2.5)
#cv2.line(frame, pts[i - 1], pts[i], (0, 0, 255), thickness)
drawline(frame,pts[i - 1], pts[i],(0, 0, 255),thickness)
# show the frame to our screen
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
# if the 'q' key is pressed, stop the loop
if key == ord("q"):
break
# cleanup the camera and close any open windows
cap.release()
cv2.destroyAllWindows()
Run Code Online (Sandbox Code Playgroud)
我设置了一个模拟来展示我在评论中所说的内容。基本上,每次相机拍照时(无论您的相机以何种 fps 运行),您都可以获得球的位置。使用该位置,您可以估计速度(位置变化除以时间)。如果该速度的方向突然发生变化,那么您可以将其视为反弹。
此代码的绝大部分用于设置模拟,出于您的目的可以安全地忽略。这是相关的代码块
# check if it's time for a snapshot
camera_timer += dt; # time since last snapshot
if camera_timer > (1.0 / camera_fps):
# estimate velocity
est_vel[0] = (ball_pos[0] - prev_pos[0]) / camera_timer;
est_vel[1] = (ball_pos[1] - prev_pos[1]) / camera_timer;
# check if the sign of the velocity has changed
if sign(est_vel[0]) != sign(prev_est_vel[0]) or sign(est_vel[1]) != sign(prev_est_vel[1]):
# check for bounces from large change in velocity
dvx = abs(est_vel[0] - prev_est_vel[0]);
dvy = abs(est_vel[1] - prev_est_vel[1]);
change_vel = math.sqrt(dvx*dvx + dvy*dvy);
if change_vel > bounce_thresh:
bounce_count += 1;
# update previous state trackers
prev_est_vel = est_vel[:];
prev_pos = ball_pos[:];
# reset camera timer
camera_timer = 0;
snap = True;
Run Code Online (Sandbox Code Playgroud)
如果您想自己玩模拟游戏,这就是全部内容
import cv2
import numpy as np
import time
import math
# get mouse click
click_pos = None;
click = False;
def mouseClick(event, x, y, flags, param):
# hook to globals
global click_pos;
global click;
# check for left mouseclick
if event == cv2.EVENT_LBUTTONDOWN:
click = True;
click_pos = (x,y);
# return sign of number
def sign(val):
if val > 0:
return 1;
if val < 0:
return -1;
return 0;
# create blank image
res = (600,600,3);
bg = np.zeros(res, np.uint8);
display = np.zeros(res, np.uint8);
# set up click callback
cv2.namedWindow("Display");
cv2.setMouseCallback("Display", mouseClick);
click_force = 1000;
# font stuff
font = cv2.FONT_HERSHEY_SIMPLEX;
fontScale = 1;
fontColor = (255, 100, 0);
thickness = 2;
# make a ball
ball_radius = 20;
ball_pos = [300,300];
ball_vel = [0,0];
# set physics
drag = 0.98;
bounce_mult = 0.95;
grav = -9.8; # acceleration in pixels per second
time_scale = 5.0;
# register click animations
click_anims = [];
anim_dur = 0.25; # seconds
anim_radius = 20; # pixels
# track bounces
prev_pos = ball_pos[:];
est_vel = [0,0];
prev_est_vel = [0,0];
bounce_count = 0;
bounce_thresh = 10; # velocity must have a sudden change greater than this magnitude to count
camera_fps = 24; # we'll only take snapshots at this speed
camera_timer = 0; # time since last snapshot
snap = False;
pic_count = 0;
# loop
done = False;
prev_time = time.time();
while not done:
# refresh display
display = np.copy(bg);
# update timestep
now_time = time.time();
dt = now_time - prev_time;
dt *= time_scale;
prev_time = now_time;
# update physics
# position
ball_pos[0] += ball_vel[0] * dt;
ball_pos[1] += ball_vel[1] * dt;
# velocity
ball_vel[1] -= grav * dt;
drag_mult = (1 - ((1 - drag) * dt));
ball_vel[0] *= drag_mult;
ball_vel[1] *= drag_mult;
# check for mouse click
if click:
# register animation
click = False;
click_anims.append([time.time(), click_pos[:]]);
# get dist
dx = ball_pos[0] - click_pos[0];
dy = ball_pos[1] - click_pos[1];
dist = math.sqrt(dx*dx + dy*dy);
# clamp dist
if dist < 1:
dist = 1;
# get force attenuation
# force = click_force / (dist*dist); # too much
force = click_force / dist;
# get angle and get axial force
angle = math.atan2(dy, dx);
xforce = math.cos(angle) * force;
yforce = math.sin(angle) * force;
# apply force
ball_vel[0] += xforce;
ball_vel[1] += yforce;
# check for bounce
# left
if ball_pos[0] - ball_radius < 0:
ball_pos[0] = 0 + ball_radius;
ball_vel[0] *= -bounce_mult;
# right
if ball_pos[0] + ball_radius > res[0]:
ball_pos[0] = res[0] - ball_radius;
ball_vel[0] *= -bounce_mult;
# up # +y-axis is down in OpenCV
if ball_pos[1] - ball_radius < 0:
ball_pos[1] = 0 + ball_radius;
ball_vel[1] *= -bounce_mult;
# down
if ball_pos[1] + ball_radius > res[1]:
ball_pos[1] = res[1] - ball_radius;
ball_vel[1] *= -bounce_mult;
# check if it's time for a snapshot
camera_timer += dt; # time since last snapshot
if camera_timer > (1.0 / camera_fps):
# estimate velocity
est_vel[0] = (ball_pos[0] - prev_pos[0]) / camera_timer;
est_vel[1] = (ball_pos[1] - prev_pos[1]) / camera_timer;
# check if the sign of the velocity has changed
if sign(est_vel[0]) != sign(prev_est_vel[0]) or sign(est_vel[1]) != sign(prev_est_vel[1]):
# check for bounces from large change in velocity
dvx = abs(est_vel[0] - prev_est_vel[0]);
dvy = abs(est_vel[1] - prev_est_vel[1]);
change_vel = math.sqrt(dvx*dvx + dvy*dvy);
if change_vel > bounce_thresh:
bounce_count += 1;
# update previous state trackers
prev_est_vel = est_vel[:];
prev_pos = ball_pos[:];
# reset camera timer
camera_timer = 0;
snap = True;
# draw bounce text
cv2.putText(display, "Bounces: " + str(bounce_count), (15,40), font,
fontScale, fontColor, thickness, cv2.LINE_AA);
# draw ball
x, y = ball_pos;
cv2.circle(display, (int(x), int(y)), ball_radius, (220,150,0), -1);
# draw click animations
for a in range(len(click_anims)-1, -1, -1):
# get lifetime
life = now_time - click_anims[a][0];
if life > anim_dur:
del click_anims[a];
else:
# draw
mult = life / anim_dur;
radius = int(anim_radius * mult);
if radius > 0:
val = 255 - int(255 * mult);
color = [val, val, val];
cv2.circle(display, click_anims[a][1], radius, color, 2);
# show
cv2.imshow("Display", display);
key = cv2.waitKey(1);
# # if snapshot, save a picture
# if snap:
# snap = False;
# cv2.imwrite("bouncy/" + str(pic_count).zfill(5) + ".png", display);
# pic_count += 1;
# check keypresses
done = key == ord('q');
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
152 次 |
| 最近记录: |