You need to enable JavaScript to run this app. 基于Python与OpenCV的运动目标速度检测:实现快速动作筛选
优惠活动
大模型
产品
解决方案
定价
更多

基于Python与OpenCV的运动目标速度检测:实现快速动作筛选

基于现有代码实现运动目标速度度量与快速场景筛选方案

完全可以实现你需要的效果——不需要换算成m/s、km/h这类真实物理速度,用跨帧像素位移作为通用量化运动快慢的指标,就足够支撑阈值筛选,完全适配你这个测试场景里识别打斗等突发剧烈运动的需求。

核心实现逻辑

你现有的代码已经能通过相邻帧差检测出运动目标的矩形框,要计算运动快慢,只需要补一层简单的目标跨帧匹配逻辑:

  • 给每个上一帧检测到的目标,存储它的矩形框中心坐标、唯一ID、位置历史记录
  • 当前帧检测到新的目标框后,通过中心位置的欧氏距离,匹配和上一帧位置最接近的目标,判定为同一个运动目标
  • 计算同一个目标相邻两帧的中心位置欧氏距离,这个值就是你要的量化速度指标:数值越大,代表单位时间内目标移动的距离越远,运动越快
  • 给这个位移值设置对应阈值,就能筛选出快速运动的场景:比如普通站立小幅晃动的位移值通常在5-10像素,慢走的位移值在10-30像素,打斗时肢体快速挥动的位移值通常能超过50像素,超过阈值的目标可以用特殊颜色加粗标注,直接区分普通运动和剧烈运动

针对现有代码的关键修改点

你现在的代码存在两个影响速度计算的问题:

  1. 没有目标跨帧匹配逻辑,每帧检测到的矩形框都是独立的,没法关联同一个目标的前后位置
  2. 现有退出按键判断逻辑有误:cv2.waitKey(60) == 60 是按6号键退出,通常应该改成检测ESC键(ASCII码27)退出

修改后的核心代码片段示例:

# 初始化跟踪目标列表,存储上一帧的目标信息:格式为 {id: [中心x, 中心y, 历史位置]}
tracked_objects = {}
next_object_id = 0
speed_threshold = 45  # 可根据实际测试调整的速度阈值,单位:像素/帧

while cap.isOpened():
    ret, frame1 = cap.read()
    if not ret:
        break
    diff = cv2.absdiff(frame1, frame2)
    gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
    _, thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)
    dilated = cv2.dilate(thresh, None, iterations=5)
    contours, _ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    # 当前帧检测到的目标列表
    current_detections = []
    for contour in contours:
        cnt_area = cv2.contourArea(contour)
        if cnt_area < 1000 or cnt_area > 4000:
            continue
        (x, y, w, h) = cv2.boundingRect(contour)
        center_x = x + w//2
        center_y = y + h//2
        current_detections.append((center_x, center_y, x, y, w, h))

    # 匹配当前检测和上一帧的跟踪目标
    updated_tracks = {}
    for det in current_detections:
        det_cx, det_cy, x, y, w, h = det
        min_dist = float('inf')
        matched_id = -1
        # 找距离最近的上一帧目标
        for obj_id, (prev_cx, prev_cy, _) in tracked_objects.items():
            dist = np.sqrt((det_cx - prev_cx)**2 + (det_cy - prev_cy)**2)
            if dist < min_dist and dist < 60: # 匹配阈值:中心距离小于60像素才算同一个目标
                min_dist = dist
                matched_id = obj_id
        # 匹配上的目标,计算速度
        if matched_id != -1:
            prev_cx, prev_cy, history = tracked_objects[matched_id]
            speed = min_dist
            history.append((det_cx, det_cy))
            updated_tracks[matched_id] = [det_cx, det_cy, history]
            # 超过速度阈值就用红色加粗框标注,普通目标用灰色框
            if speed > speed_threshold:
                cv2.rectangle(frame1, (x,y), (x+w, y+h), (0, 0, 255), thickness=2)
                cv2.putText(frame1, f"快速运动 速度:{int(speed)}", (x, y-10), 
                           cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,0,255), 2)
            else:
                cv2.rectangle(frame1, (x,y), (x+w, y+h), (128,128,128), thickness=1)
        # 没匹配上的新目标,分配新ID
        else:
            updated_tracks[next_object_id] = [det_cx, det_cy, [(det_cx, det_cy)]]
            next_object_id +=1
    # 更新跟踪列表
    tracked_objects = updated_tracks

    cv2.imshow('frame', frame1)
    frame2 = frame1.copy()
    ret, frame2 = cap.read()

    if cv2.waitKey(60) == 27: # 按ESC退出
        break

cv2.destroyAllWindows()
cap.release()

调优建议

  • 速度阈值speed_threshold不需要固定,你可以跑一遍测试视频,打印每个目标的实时速度值,找打斗场景和普通站立、走路场景的速度分界值就行,一般在30-60像素/帧区间最适合这个测试视频
  • 可以加个短暂的速度平滑:比如取最近3帧的平均位移值当最终速度,避免视频噪声导致的单帧速度虚高误判
  • 匹配阈值不要设太大,避免把相邻的两个人错匹配成同一个目标,通常设置成比单个人体的宽度小一点的值就够

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 08:54:00