You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用OpenCV/Python绘制高尔夫球杆挥杆的插值轨迹曲线?

解决方案:绘制平滑带渐隐效果的高尔夫挥杆轨迹

1. 先解决轨迹抖动/折线问题:平滑检测点

YOLOv5的检测结果可能存在帧间小偏移,直接连点会产生生硬折线,可用以下两种方法平滑坐标:

滑动平均法(简单易实现)

维护一个最近N帧的检测点队列,取队列平均坐标作为当前轨迹点,抵消小幅抖动:

from collections import deque
import numpy as np

# 保存最近10帧的杆头坐标,可根据帧率调整长度
point_queue = deque(maxlen=10)

def smooth_point(current_point):
    if current_point is not None:
        point_queue.append(current_point)
    if len(point_queue) > 1:
        avg_x = int(np.mean([p[0] for p in point_queue]))
        avg_y = int(np.mean([p[1] for p in point_queue]))
        return (avg_x, avg_y)
    return current_point

卡尔曼滤波(精准轨迹预测)

如果需要更稳定的追踪,用OpenCV卡尔曼滤波器预测杆头位置,修正检测误差:

import cv2
import numpy as np

# 初始化卡尔曼滤波器(状态量:x,y,dx,dy;观测值:x,y)
kalman = cv2.KalmanFilter(4, 2)
kalman.measurementMatrix = np.array([[1, 0, 0, 0], [0, 1, 0, 0]], np.float32)
kalman.transitionMatrix = np.array([[1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]], np.float32)
kalman.processNoiseCov = np.eye(4, dtype=np.float32) * 0.03

def kalman_update(current_point):
    if current_point is not None:
        measurement = np.array([[np.float32(current_point[0])], [np.float32(current_point[1])]])
        kalman.correct(measurement)
    prediction = kalman.predict()
    return (int(prediction[0]), int(prediction[1]))

2. 绘制类似目标图的渐隐轨迹

目标轨迹是带拖尾渐变的效果,而非生硬直线,推荐以下两种实现方式:

方式一:透明轨迹画布叠加(效果自然)

创建带alpha通道的画布,每次绘制轨迹后降低画布透明度,再叠加到原帧:

import cv2

trail_canvas = None
prev_point = None
cap = cv2.VideoCapture("你的高尔夫视频路径.mp4")

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    
    # 替换为你的YOLOv5检测逻辑,返回杆头坐标(x,y)
    current_point = detect_club_head(frame)
    # 用滑动平均或卡尔曼滤波平滑点
    smoothed_point = smooth_point(current_point)
    
    if trail_canvas is None:
        # 初始化和帧同尺寸的透明画布
        trail_canvas = np.zeros_like(frame, dtype=np.float32)
    
    if smoothed_point and prev_point:
        # 在画布上绘制轨迹线,颜色、厚度可调整
        cv2.line(trail_canvas, prev_point, smoothed_point, (0, 255, 0), 3)
    
    # 降低画布透明度,实现轨迹渐隐(数值越小,轨迹消失越快)
    trail_canvas *= 0.95
    # 叠加轨迹到原帧
    frame = cv2.addWeighted(frame, 1.0, trail_canvas.astype(np.uint8), 0.8, 0)
    
    prev_point = smoothed_point
    
    cv2.imshow("挥杆轨迹", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

方式二:按时间梯度绘制线条

保存最近M个轨迹点,从最新到最旧绘制透明度逐渐降低的线条:

from collections import deque
import cv2

# 保存最近50个轨迹点,数量根据轨迹长度需求调整
trail_points = deque(maxlen=50)
cap = cv2.VideoCapture("你的高尔夫视频路径.mp4")

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    
    current_point = detect_club_head(frame)
    smoothed_point = smooth_point(current_point)
    
    if smoothed_point:
        trail_points.append(smoothed_point)
    
    # 绘制渐变轨迹
    for i in range(1, len(trail_points)):
        if not trail_points[i-1] or not trail_points[i]:
            continue
        # 计算透明度权重,越旧的点越淡
        alpha = i / len(trail_points)
        # 颜色渐变(也可以固定颜色,通过addWeighted控制透明度)
        color = (0, int(255 * alpha), 0)
        thickness = max(1, int(3 * alpha))
        cv2.line(frame, trail_points[i-1], trail_points[i], color, thickness)
    
    cv2.imshow("挥杆轨迹", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

关键调优提示

  • 检测稳定性:给YOLOv5设置较高置信度阈值(如conf=0.7),或用高尔夫球杆专用数据集微调模型,减少误检测导致的轨迹跳变。
  • 参数适配:滑动窗口长度、轨迹衰减系数、轨迹点数量需根据视频帧率和挥杆速度调整,找到最优效果。
  • 性能优化:高帧率视频下,避免设置过大的轨迹队列长度,防止内存占用过高。

内容的提问来源于stack exchange,提问作者Yogendra Yatnalkar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 07:46:00