问题
Just looking for some suggestions on how to approach the problem of golf ball tracking with different color balls.
I've explored using absdiff() to get the difference between frames to track the balls but it also picks up the player and club movement. Also, using HSV to pick up specific color balls but I want to be able to pick up most colors (white, yellow, orange, blue). Thanks.
回答1:
-
- Do preprocess each frame
Apply
GaussianBlur
gaussian_blurr = cv2.GaussianBlur(frame, (22, 22), 0)
You can change the parameters, the above parameters are just examples.
Assume below is your original frame:
Gaussian Blur will be:
We apply
GaussianBlur
for reducing noise and outliers.Convert the frame to the HSV scale.
hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)
Converting
hsv
enable us to detect the ball in the current frame.Apply
inRange
method:greenLower = (29, 86, 6) greenUpper = (64, 255, 255) mask = cv2.inRange(hsv, greenLower, greenUpper)
By defining our upper and lower boundaries, we locate the ball in the frame by declaring, 29 < Hue values < 64, 86 < Saturation < 255, 6 < Value < 255.
Apply
erode
anddilate
:mask = cv2.erode(mask, None, iterations=2) mask = cv2.dilate(mask, None, iterations=2)
erode
anddilate
are commonly used for preprocessing images.erode
removes pixels on object boundaries.dilate
connecting areas that are separated by spaces. source -
- Find the center of the ball
Find Contours
cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
Contours are used in shape detection and recognition. The output will be an array of ball location. We need the largest contours in the mask to find the 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"]))
minClosingCircle
will cover the object with minimum area.moments
will return the weighted area. sourceUpdated: If you want to see the centroid of the ball add the following:
cv2.circle(frame, center, 5, (0, 0, 255), -1)
Result:
Now, if we combine all frames, the final will be:
Final with the centroid of the ball:
Now, for different kinds of balls, you need to declare upper and lower bounds, as we declared greenUpper
and greenLower
. Then apply the steps starting from 1.
Full Code:
import cv2
import imutils
import time
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)
vs = cv2.VideoCapture("input.mp4")
time.sleep(2.0)
while True:
_, frame = vs.read()
if frame is None:
break
blurred = cv2.GaussianBlur(frame, (11, 11), 0)
width, height = frame.shape[:2]
hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, greenLower, greenUpper)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
center = None
if len(cnts) > 0:
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"]))
# To see the centroid clearly
if radius > 10:
cv2.circle(frame, (int(x), int(y)), int(radius), (0, 255, 255), 5)
cv2.imwrite("circled_frame.png", cv2.resize(frame, (int(height / 2), int(width / 2))))
cv2.circle(frame, center, 5, (0, 0, 255), -1)
cv2.imshow("Frame", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
vs.release()
cv2.destroyAllWindows()
来源:https://stackoverflow.com/questions/63730808/golf-ball-tracking-in-python-opencv-with-different-color-balls