【Python】使用YOLO8识别视频中的车与人物

文章目录

与我之前写的这篇文章呼应:【Web】使用Vue3开发3D游戏(九)纹理视觉效果

一、效果

1.1、原视频

路况

1.2、效果视频

路况识别效果

1.3、静图效果

二、简介

在行车记录仪路况分析、道路障碍物检测、智能驾驶仿真场景中,行人、车辆识别是最基础也是最核心的能力。本文基于 YOLOv8 实现本地 MP4 视频实时检测,精准区分行人、轿车、摩托车、货车、巴士等交通参与者,同时适配 Vue3 + PlayCanvas 3D 前端 数据协议,输出标准化障碍物类型,可直接对接 3D 场景做障碍物映射,非常适合做仿真项目、机器狗路况感知、Web3D 可视化开发。

三、环境准备

3.1、安装依赖

运行

bash 复制代码
pip install ultralytics opencv-python websockets
  • ultralytics:YOLOv8 官方库,一行加载模型、推理
  • opencv-python:视频读取、画面绘制、编码推流
  • websockets:向前端实时推送视频流 + 障碍物数据

3.2、YOLOv8 类别说明

YOLOv8 预训练模型自带 80 个类别,路况常用关键类别:

类别 ID 对应物体
0 行人 person
1 自行车
2 轿车car
3 摩托车
5 巴士公交车
7 卡车货车

业务规则:所有车辆统一归类为 car 类型 = 1,行人固定 type=0,完美适配你 Vue3 前端 mapTypeToModel 映射规则:

js 复制代码
const typeMap = {
  0: 'person',
  1: 'car'
};

四、核心解析

  • 只检测行人 + 全部车辆,过滤无关物体
  • 绘制矩形框标记目标
  • 适配前端协议:人type=0,所有车type=1
  • WebSocket 同时推送 视频画面 + 3D 障碍物坐标
  • 优化帧率、控制 CPU 占用,不卡顿服务器
  • 固定端口 9090,兼容你现有 Vue 前端连接

4.1、检测目标过滤

只保留路况有效目标:

py 复制代码
if cls_id not in [0, 1, 2, 3, 5, 7]:
    continue

排除猫、狗、椅子等无关物体,减少无效计算、降低 CPU。

4.2、类型映射(适配你 Vue 前端)

py 复制代码
if cls_id == 0:
    obj_type = 0   # 行人 → person
else:
    obj_type = 1   # 所有车辆 → car

完美对应前端:

js 复制代码
const typeMap = {0:'person', 1:'car'}

4.3、3D 坐标映射

根据画面中目标左右位置归一化,映射为 3D 场景左右偏移,前后固定,实现:

视频里人 / 车往左 → 3D 障碍物往左

视频里人 / 车往右 → 3D 障碍物往右

4.4、性能优化

  • 压缩视频分辨率推理,大幅降 CPU
  • 控制检测间隔,不无限死循环占用资源
  • 异常连接捕获,不抛崩溃错误
  • 视频播放完毕自动循环,无需手动重启

五、使用方法

把行车记录仪路况视频命名为 test.mp4,放在同目录

安装依赖后直接运行:

bash 复制代码
python3 mp4_websocket_stream.py

Vue3 前端直接连接 ws://ip:9090,自动接收:

实时摄像头画面

行人 / 车辆 3D 障碍物数据,自动渲染对应模型

适配场景

  • Web3D 智能驾驶仿真
  • 机器狗 / 无人车路况感知可视化
  • 行车记录仪视频 AI 分析
  • PlayCanvas + Vue3 前后端联合开发
  • 路口行人车辆检测统计

六、完整源码

py 复制代码
import asyncio
import websockets
import json
import base64
import cv2
import threading
import time
from ultralytics import YOLO

# ==================== 配置 ====================
VIDEO_PATH      = "./test.mp4"
WEBSOCKET_HOST  = "0.0.0.0"
WEBSOCKET_PORT  = 9090
JPEG_QUALITY    = 60
MOVE_SCALE      = 2.5
DETECT_INTERVAL = 0.05
# ==============================================

latest_frame_bytes = None
obstacle_list = []

# 加载YOLO模型
model = YOLO("yolov8n.pt")

def video_loop():
    global latest_frame_bytes, obstacle_list
    cap = cv2.VideoCapture(VIDEO_PATH)
    fps = cap.get(cv2.CAP_PROP_FPS) or 25

    while True:
        ret, frame = cap.read()
        if not ret:
            cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
            continue

        # 降低分辨率,省CPU
        small_frame = cv2.resize(frame, (640, 360))
        h, w = small_frame.shape[:2]
        obs = []

        # YOLO推理
        results = model(small_frame, conf=0.5, verbose=False, imgsz=320)
        
        for result in results:
            for box in result.boxes:
                cls_id = int(box.cls[0])

                # 只检测 人 + 车
                if cls_id not in [0,1,2,3,5,7]:
                    continue

                # 画框
                x1, y1, x2, y2 = map(int, box.xyxy[0])
                cv2.rectangle(small_frame, (x1, y1), (x2, y2), (0, 255, 0), 2)

                # 计算3D坐标
                cx = (x1 + x2) / 2
                norm_x = (cx - w/2) / (w/2)

                # ==========================
                # 前端要求:人=0,车=1
                # ==========================
                if cls_id == 0:
                    obj_type = 0  # 人
                else:
                    obj_type = 1  # 所有车辆统一为 car

                # 你的正确坐标,完全不动!
                obs.append({
                    "track_id": int(box.id[0]) if box.id is not None else 100,
                    "type": obj_type,
                    "x": 10,
                    "y": -norm_x * MOVE_SCALE,
                    "z": 5.0,
                    "width": 0.6,
                    "height": 1.7,
                    "length": 0.6,
                    "heading": 0.0
                })

        obstacle_list = obs

        # 修复这里!cv2.imencode
        ok, jpeg = cv2.imencode('.jpg', small_frame, [cv2.IMWRITE_JPEG_QUALITY, JPEG_QUALITY])
        if ok:
            latest_frame_bytes = jpeg.tobytes()

        time.sleep(DETECT_INTERVAL)

async def send_client(websocket):
    global latest_frame_bytes, obstacle_list
    try:
        while True:
            if latest_frame_bytes:
                b64 = base64.b64encode(latest_frame_bytes).decode()
                await websocket.send(json.dumps({"msg": {"data": b64}}))
                await websocket.send(json.dumps({"msg": {"objs": obstacle_list}}))
            await asyncio.sleep(0.05)
    except:
        pass

async def handle_conn(websocket):
    try:
        await send_client(websocket)
    except:
        pass

async def main():
    threading.Thread(target=video_loop, daemon=True).start()
    async with websockets.serve(handle_conn, WEBSOCKET_HOST, WEBSOCKET_PORT):
        print("✅ 启动成功:人=0,车=1,端口9090正常!")
        await asyncio.Future()

if __name__ == "__main__":
    asyncio.run(main())
相关推荐
临沂GEO2 小时前
GEO搜索优化科普|正规地理位置流量运营入门指南
大数据·人工智能·python·流量运营
大模型码小白2 小时前
Spring AI Tool 实现自然语言操作 MySQL 数据库详解
服务器·开发语言·数据库·人工智能·python·mysql·spring
美狐美颜SDK开放平台2 小时前
视频美颜SDK是什么?直播APP开发中美颜功能实现方式介绍
深度学习·架构·实时互动·音视频·视频美颜sdk
荷蒲4 小时前
【小白量化Qbuddy】利用AI学习中文Python
人工智能·python·学习
美狐美颜sdk5 小时前
直播APP开发如何实现美颜功能?视频美颜SDK接入流程与技术方案解析
大数据·人工智能·音视频·美颜sdk·美颜api
数据狐(Datafox)5 小时前
京东商品列表API技术解析与落地应用(含标准 JSON 示例)
java·大数据·前端·人工智能·python·数据分析·json
量化吞吐机5 小时前
2026年下半年手工交易规则走向量化表达,产品该先接住哪一步
人工智能·python
Metaphor6926 小时前
使用 Python 读取和删除 Excel 文件属性
python·excel
迷迭香yy7 小时前
Python构建转融券多空识别系统从接口到因子的全流程 IG50免费开源股票数据API接口
开发语言·python·开源
月光船幽幽7 小时前
真实即粗糙,光滑是伪造
人工智能·python