硬件产品咨询:19113907060(耿女士)
软件技术咨询:18982151213(刘先生)
联系我们
产品咨询

YOLOv8+DeepSORT 人流统计 AI 算法详解

作者:万物纵横
发布时间:2026-03-06 11:18
阅读量:

人流统计是计算机视觉的经典应用场景,核心是精准检测画面中的行人 + 稳定跟踪每个行人的轨迹 + 根据预设规则(如跨线)统计数量。YOLOv8+DeepSORT 是当前工业界主流的轻量化、高精度方案,下面从核心原理、实现流程、代码落地等维度全面解析。


YOLOv8+DeepSORT 人流统计 AI 算法详解(图1)


一、核心组件原理


1. YOLOv8:行人检测基础


YOLOv8 是 2023 年发布的单阶段目标检测模型,相比前代(YOLOv5/7)在速度和精度上均有提升,是人流统计的检测端核心。


核心优势:


轻量化:支持 n/s/m/l/x 不同规模模型,n/s 版本可在普通 GPU/边缘设备实时运行;


精度高:对小目标(如远处行人)、遮挡行人的检测效果更优;


部署友好:支持 ONNX/TensorRT 等格式导出,适配端侧/云端部署。


在人流统计中的作用:


对视频每一帧图像进行推理,输出画面中所有行人的边界框(bbox)、置信度、类别(person),为后续跟踪提供基础检测结果。


2. DeepSORT:行人跟踪核心


SORT(Simple Online and Realtime Tracking)是基础跟踪算法,DeepSORT 是其升级版,核心改进是引入深度特征匹配,解决了 SORT 中目标遮挡、短时消失后重新识别的问题。


核心原理:


  1. 运动匹配:用卡尔曼滤波预测目标下一帧的位置,计算预测框与 YOLOv8 检测框的 IOU(交并比),初步匹配;


  2. 外观匹配:对检测到的行人提取深度特征(常用 ReID 模型),计算特征余弦相似度,解决遮挡/快速移动导致的 IOU 匹配失效问题;


  3. 级联匹配:优先匹配长期未匹配的目标,减少 ID 切换(行人被误识别为新目标);


  4. 轨迹管理:为每个行人分配唯一 ID,维护轨迹的生命周期(新增/更新/删除)。


在人流统计中的作用:


为每个行人分配唯一且稳定的 ID,跟踪其运动轨迹,避免重复统计(如同一行人在画面中移动被多次计数)。


二、人流统计完整流程


整体流程可分为 5 个核心步骤,逻辑如下:


YOLOv8+DeepSORT 人流统计 AI 算法详解(图2)


步骤 1:视频帧输入


支持本地视频文件(mp4/avi)、摄像头实时流、网络视频流(RTSP/HTTP),通过 OpenCV 逐帧读取。


步骤 2:YOLOv8 行人检测


加载预训练的 YOLOv8 模型(推荐 yolov8s.pt,平衡速度和精度);


对单帧图像执行检测,过滤掉非“person”类别、置信度低于阈值(如 0.5)的检测框;


输出格式:[x1, y1, x2, y2, conf, class](左上角/右下角坐标、置信度、类别)。


步骤 3:检测结果预处理


非极大值抑制(NMS):去除重复的行人检测框;


尺寸归一化:将检测框坐标转换为 DeepSORT 要求的格式;


特征提取:对每个行人检测框裁剪图像,输入 ReID 模型提取外观特征(DeepSORT 核心)。


步骤 4:DeepSORT 轨迹跟踪


初始化:为第一帧检测到的每个行人创建新轨迹,分配唯一 ID;


帧间匹配:


  1. 卡尔曼滤波预测当前帧每个轨迹的位置;


  2. 计算预测框与检测框的 IOU,筛选候选匹配;


  3. 计算候选匹配的外观特征相似度,完成精准匹配;


轨迹更新:匹配成功的轨迹更新位置和特征;未匹配的轨迹标记为“丢失”,超过阈值则删除;未匹配的检测框创建新轨迹。


步骤 5:跨线/区域统计(核心规则)


人流统计的核心是定义有效计数规则,主流有 2 种:


规则 1:跨线计数(最常用)


预设 1 条或多条计数线(如画面中一条水平线/垂直线);


跟踪行人轨迹的中心点,判断是否跨越计数线,且满足方向要求(如从左到右、从下到上);


去重:同一 ID 仅在首次跨线时计数,避免重复统计。


规则 2:区域计数


预设一个感兴趣区域(ROI,如画面中的入口/出口区域);


统计当前时刻区域内的行人数量(实时人数),或统计进入/离开区域的总人数。


三、完整代码实现


前置环境准备


# 安装核心依赖

pip install ultralytics opencv-python numpy torch deep-sort-realtime


完整可运行代码


import cv2

import numpy as np

from ultralytics import YOLO

from deep_sort_realtime.deepsort_tracker import DeepSort


# ====================== 配置参数 ======================

VIDEO_PATH = "test_video.mp4"  # 视频路径,替换为0可调用摄像头

COUNT_LINE = [(100, 300), (600, 300)]  # 计数线:(x1,y1)到(x2,y2)

CONF_THRESH = 0.5  # 检测置信度阈值

IOU_THRESH = 0.3   # NMS阈值

COUNT_DIRECTION = "up"  # 计数方向:up/down/left/right


# ====================== 初始化组件 ======================

# 1. 加载YOLOv8行人检测模型

model = YOLO("yolov8s.pt")


# 2. 初始化DeepSORT跟踪器

tracker = DeepSort(

    max_age=30,  # 轨迹最大丢失帧数(避免短时遮挡导致ID丢失)

    n_init=3,    # 新轨迹需要连续匹配的帧数

    nn_budget=100,  # 特征库大小

    override_track_class=None

)


# 3. 视频读取

cap = cv2.VideoCapture(VIDEO_PATH)

if not cap.isOpened():

    raise ValueError("视频文件/摄像头无法打开")


# 计数变量

total_count = 0

counted_ids = set()  # 已计数的ID,避免重复


# ====================== 辅助函数:判断是否跨线 ======================

def is_cross_line(center_prev, center_curr, line, direction):

    """

    判断目标中心点是否跨线

    :param center_prev: 上一帧中心点 (x,y)

    :param center_curr: 当前帧中心点 (x,y)

    :param line: 计数线 [(x1,y1), (x2,y2)]

    :param direction: 计数方向 up/down/left/right

    :return: 是否跨线

    """

    # 提取线的坐标

    x1, y1 = line[0]

    x2, y2 = line[1]

    

    # 简化:以水平线为例(y固定),判断y方向跨越

    if abs(y1 y2) < 10:  # 水平线

        if direction == "up" and center_prev[1] > y1 and center_curr[1] < y1:

            return True

        elif direction == "down" and center_prev[1] < y1 and center_curr[1] > y1:

            return True

    # 垂直线(x固定)

    elif abs(x1 x2) < 10:

        if direction == "left" and center_prev[0] > x1 and center_curr[0] < x1:

            return True

        elif direction == "right" and center_prev[0] < x1 and center_curr[0] > x1:

            return True

    return False


# ====================== 主循环 ======================

# 存储上一帧的轨迹中心点

prev_centers = {}


while cap.isOpened():

    ret, frame = cap.read()

    if not ret:

        break

    

    # 1. YOLOv8检测行人

    results = model(frame, conf=CONF_THRESH, iou=IOU_THRESH, classes=[0])  # classes=[0]只检测person

    detections = []

    

    # 解析检测结果

    for r in results:

        boxes = r.boxes

        for box in boxes:

            # 提取检测框坐标(xyxy)

            x1, y1, x2, y2 = map(int, box.xyxy[0])

            # 提取置信度

            conf = float(box.conf[0])

            # 格式:(x1, y1, x2, y2, conf),符合DeepSORT输入要求

            detections.append(([x1, y1, x2 x1, y2 y1], conf, "person"))  # DeepSORT需要(w,h),所以转换为x1,y1,w,h

    

    # 2. DeepSORT跟踪

    tracks = tracker.update_tracks(detections, frame=frame)

    

    # 3. 遍历轨迹,更新中心点并判断跨线

    curr_centers = {}

    for track in tracks:

        if not track.is_confirmed():

            continue

        

        # 获取轨迹ID和边界框

        track_id = track.track_id

        ltrb = track.to_ltrb()  # (left, top, right, bottom)

        x1, y1, x2, y2 = map(int, ltrb)

        # 计算中心点

        center_x = (x1 + x2) // 2

        center_y = (y1 + y2) // 2

        curr_centers[track_id] = (center_x, center_y)

        

        # 绘制检测框、ID、中心点

        cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)

        cv2.putText(frame, f"ID: {track_id}", (x1, y1 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)

        cv2.circle(frame, (center_x, center_y), 5, (255, 0, 0), -1)

        

        # 4. 判断是否跨线计数

        if track_id in prev_centers:

            if is_cross_line(prev_centers[track_id], curr_centers[track_id], COUNT_LINE, COUNT_DIRECTION):

                if track_id not in counted_ids:

                    total_count += 1

                    counted_ids.add(track_id)

    

    # 更新上一帧中心点

    prev_centers = curr_centers.copy()

    

    # 绘制计数线和统计结果

    cv2.line(frame, COUNT_LINE[0], COUNT_LINE[1], (0, 0, 255), 3)

    cv2.putText(frame, f"Total Count: {total_count}", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 3)

    

    # 显示画面

    cv2.imshow("YOLOv8+DeepSORT Pedestrian Counting", frame)

    

    # 按q退出

    if cv2.waitKey(1) & 0xFF == ord('q'):

        break


# 释放资源

cap.release()

cv2.destroyAllWindows()

print(f"最终统计人数:{total_count}")



代码关键部分解释


1. 参数配置:


COUNT_LINE:自定义计数线,可根据视频画面调整坐标;


COUNT_DIRECTION:控制计数方向(如只统计向上跨线的行人);


max_age=30:轨迹最多丢失30帧(约1秒),避免短时遮挡导致ID丢失。


2. 跨线判断函数:


核心是对比目标上一帧和当前帧的中心点,判断是否跨越预设线且符合方向;


支持水平线/垂直线,可扩展为任意斜线(需补充向量计算逻辑)。


3. 去重逻辑:


用counted_ids集合存储已计数的ID,确保同一行人仅被统计一次。


四、优化方向(工业级落地)


1. 模型轻量化:


将YOLOv8s替换为YOLOv8n,或量化为ONNX/TensorRT格式,提升推理速度(边缘设备如Jetson Nano可实时运行);


裁剪视频ROI区域,只检测感兴趣区域的行人,减少计算量。


2. 跟踪稳定性优化:


调整DeepSORT参数(max_age/n_init),适配不同场景(如拥挤/稀疏人群);


加入轨迹平滑(如卡尔曼滤波后处理),减少ID抖动。


3. 计数规则增强:


支持双向计数(如进/出人数分别统计);


过滤静态行人(如停留超过5秒的行人不计数)。


4. 异常处理:


加入画面防抖、光照补偿,提升复杂环境下的检测精度;


处理视频流中断、模型推理超时等异常。


五、总结


关键点回顾


1. 核心逻辑:YOLOv8 负责精准检测行人,DeepSORT 负责稳定跟踪行人ID,跨线/区域规则负责统计有效人数,三者缺一不可;


2. 核心优势:YOLOv8+DeepSORT 兼顾速度(实时)和精度(低ID切换率),适配端侧/云端部署;


3. 落地关键:重点优化跨线判断逻辑(避免漏计/重计)、跟踪参数(适配场景)、模型轻量化(满足实时性)。


该方案是当前人流统计的主流选择,可直接落地到商场、车站、景区等场景的智能监控系统中。

- END -
分享:
留言 留言 试用申请
产品咨询 产品咨询 硬件产品咨询
19113907060(耿女士)
技术咨询 技术咨询 软件技术咨询
18982151213(刘先生)
微信在线客服 微信在线客服 在线客服
返回官网顶部 返回官网顶部 回到顶部
关闭窗口
产品订购
  • *

  • *

  • *

  • *

  • *