Skip to content

Instantly share code, notes, and snippets.

@Hermann-SW
Last active March 5, 2023 14:06
Show Gist options
  • Save Hermann-SW/56b3ba66938b9891a0d672f08e1c1849 to your computer and use it in GitHub Desktop.
Save Hermann-SW/56b3ba66938b9891a0d672f08e1c1849 to your computer and use it in GitHub Desktop.
Determine golf club head speed from single raspiraw Raspberry v2 camera high framerate video frame (640x240@383fps, 640x75@1007fps, ...)
#!/usr/bin/python3
#
# Determine club head speed of a golf swing (high framerate video) frame:
# https://forums.raspberrypi.com/viewtopic.php?t=345368#p2070418
import cv2
import numpy as np
from sys import argv, exit
# https://www.geeksforgeeks.org/linear-regression-python-implementation/
def estimate_coef(x, y):
# number of observations/points
n = np.size(x)
# mean of x and y vector
m_x = np.mean(x)
m_y = np.mean(y)
# calculating cross-deviation and deviation about x
SS_xy = np.sum(y*x) - n*m_y*m_x
SS_xx = np.sum(x*x) - n*m_x*m_x
# calculating regression coefficients
b_1 = SS_xy / SS_xx
b_0 = m_y - b_1*m_x
return (b_0, b_1)
# https://stackoverflow.com/a/70385257/5674289
def imread_url(u):
cap = cv2.VideoCapture(u)
return cap, cap.read() # Read the image as a video frame
# image_url = 'out.1817.png'
# image_url = 'https://forums.raspberrypi.com/download/file.php?id=58662'
# image_url = 'https://forums.raspberrypi.com/download/file.php?id=58663'
# image_url = 'https://forums.raspberrypi.com/download/file.php?id=58664'
# image_url = 'out.3360.png'
# image_url = 'https://forums.raspberrypi.com/download/file.php?id=58675'
# image_url = 'https://forums.raspberrypi.com/download/file.php?id=58676'
# image_url = 'https://forums.raspberrypi.com/download/file.php?id=58677'
image_url = 'https://stamm-wilbrandt.de/en/forum/golf_out.1817.png'
dbg = 1
delay = 0
if len(argv) > 1:
if argv[1] in ["-h", "--help"]:
print(argv[0],"[-h|--help|dbg [frameurl [delay (in ms, default 0)]]]")
print("dbg=0 outputs speed only in frame window")
print("dbg=1 in addition to 0, debug pixels in frame window")
print("dbg=2 in addition to 0, debug pixels in analysis window")
print("dbg=3 in addition to 2, show edge detection window")
exit(0)
dbg = int(argv[1])
if len(argv) > 2:
image_url = argv[2]
if len(argv) > 3:
delay = int(argv[3])
cap,(success,img) = imread_url(image_url)
assert success
# https://forums.raspberrypi.com/viewtopic.php?p=2079331#p2079136
b,g,r = cv2.split(img)
ball = cv2.addWeighted(r,8.0,b,-8.0,-128)
blur = cv2.GaussianBlur(ball, (19,19), 0)
edge = cv2.Canny(blur, 50, 100, 7, L2gradient=True)
if dbg >= 3:
cv2.imshow('edge', edge)
# edge detection, golf ball middle slope determination
h,w = edge.shape
X=[]
Y=[]
xmin = w
d = 0
def high():
return h >= 100
thr = 15 if high() else 5
for y in range(h):
l = 0
while l < w and edge[y][l] == 0:
l += 1
if l < w:
r = w - 1
while edge[y][r] == 0:
r -= 1
if l + thr > r: # eliminate row y completely (all pixels black)
while l <= r:
edge[y][l] = 0
l += 1
continue
x = l + 1 # black all pixels between leftmost and rightmost
while x < r:
edge[y][x] = 0
x += 1
if dbg == 1:
img[y][l] = img[y][r] = (255, 255, 0)
mx = (l+r)//2
if mx < xmin:
xmin = mx
if mx <= xmin + thr:
edge[y][mx] = 64
if dbg == 1:
img[y][mx] = (255, 255, 0)
else:
edge[y][mx] = 128
X.append(mx)
Y.append(y)
if r - l > d:
d = r - l
if dbg == 1:
img[y][mx] = (255, 0, 0)
if dbg >= 2:
cv2.imshow('analysis', edge)
b = estimate_coef(np.array(X), np.array(Y)) if len(X) > 2 else (0, 1)
D = 0.04267 # golf ball diameter [m]
line_time_s = 0.000019517 # Raspberry v2 camera, raspiraw mode7
ms = ((D / d) / b[1]) / line_time_s if d > 0 else 0
# D / d: golf ball diameter divided by measured diameter [m/pixel]
# / b[1]: div by middle pixels slope; 1 line time horizontal distance [m]
# / line_time_s: speed [m/s]
txt = f"speed: {ms:.2f}m/s ({ms * 3.6:.1f}km/h)"
# horizontally centered OpenCV text output
font = cv2.FONT_HERSHEY_PLAIN
thck = font_scale = 2 if high() else 1
txtSize = cv2.getTextSize(txt, font, font_scale, thck)
cv2.putText(img, txt, ((w - txtSize[0][0])//2, h//4), font, font_scale,
(255, 0, 0), thck, cv2.LINE_AA)
# frame window is shown always
cv2.imshow('frame', img)
cv2.waitKey(delay)
print(txt)
cap.release()
cv2.destroyAllWindows()
@Hermann-SW
Copy link
Author

Hermann-SW commented Feb 9, 2023

3 windows output with dbg=3 in next comment:
https://forums.raspberrypi.com/viewtopic.php?p=2079384#p2079384

@Hermann-SW
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment