Ultralytics 区域物体计数(RegionCounter)实战:用 YOLO26 对多自定义区域进行实时统计
【免费下载链接】ultralyticsUltralytics YOLO26, YOLO11, YOLOv8 — object detection, instance segmentation, semantic segmentation, image classification, pose estimation, object tracking项目地址: https://gitcode.com/GitHub_Trending/ul/ultralytics
本文基于 Ultralytics 仓库中的RegionCounter解决方案,讲解如何用 YOLO26 对视频画面中一个或多个用户自定义多边形区域内的物体进行实时计数。读完本文,你将掌握如何在 CLI 与 Python 中运行区域计数、如何用字典同时监控多个命名区域(如门店货架区、车道、生产工位)、如何以编程方式读取每个区域的实时计数,并能结合源码理解其"先跟踪、再判断中心点是否落在区域内"的底层原理。
为什么需要区域计数?
Ultralytics 提供了多种基于 YOLO 的解决方案(Solutions),RegionCounter是其中专门用于"区域内实时人数/物体数统计"的模块,对应实现见 ultralytics/solutions/region_counter.py。相比通用目标检测,它有以下几个直接可见的优势:
- 一趟处理多个区域:把一组命名多边形以字典形式传入,每个区域都会得到独立的计数并实时绘制在画面上,一路视频流即可覆盖你关心的所有区域;
- 内置跟踪能力:该方案内部直接运行 YOLO26 检测与物体跟踪,无需你单独搭建或串联一条跟踪管线;
- 可编程读取计数:每一帧处理完都会返回一个结果对象,其中携带区域计数字典,可以直接接入数据看板、告警系统或日志记录。
真实世界中的应用场景
区域计数本质上是"瞬时占用率"统计,即回答"此刻每个区域内有多少目标"这一连续性问题。典型的落地场景包括:
- 零售门店:划分多个货架通道区域,实时统计每个通道内的客流,用于人员调度与热区分析;
- 公共街道/市场:在拥挤街道画面中圈出不同区块,分块统计人群密度,辅助安保与疏导决策;
- 交通与停车:按车道或停车位划分多边形区域,统计各区域内的车辆占用情况;
- 生产与仓储:将流水线工位、暂存区分别框定为多边形,实时掌握在制品数量。
用 YOLO26 进行区域计数:CLI 与 Python
运行区域计数的方式有两种:命令行(CLI)与 Python API。区域既可以是一个点列表(表示单个区域),也可以是一个把区域名映射到点列表的字典(表示多个区域)。
!!! example "区域计数的两种调用方式"
=== "CLI" 使用命令行时通过 `yolo solutions region` 命令即可,`source` 与 `region` 等参数与 Python API 完全对应: ```bash # 运行一个区域计数示例(未指定 source 时会自动下载默认演示视频) yolo solutions region show=True # 传入一个视频源 yolo solutions region source="path/to/video.mp4" # 传入自定义区域(单个四边形的四个角点坐标) yolo solutions region region="[(20, 400), (1080, 400), (1080, 360), (20, 360)]" ``` 当通过 CLI 运行且未提供 `source` 时,[BaseSolution](https://link.gitcode.com/i/14f3819a32549398ba8dcfe89b28960c) 会自动下载官方演示视频作为默认输入源(见 [ultralytics/solutions/solutions.py](https://link.gitcode.com/i/14f3819a32549398ba8dcfe89b28960c#L122-L128))。 === "Python" Python 用法更为灵活,尤其适合需要把计数结果写回自己业务逻辑的场景。下面的例子统计两个命名区域内的物体,并把处理后的帧写入输出视频: ```python import cv2 from ultralytics import solutions cap = cv2.VideoCapture("path/to/video.mp4") assert cap.isOpened(), "Error reading video file" # 传入区域为列表(单个区域,内部会被命名为 Region#01) # region_points = [(20, 400), (1080, 400), (1080, 360), (20, 360)] # 传入区域为字典(多个命名区域,每个区域独立计数) region_points = { "region-01": [(50, 50), (250, 50), (250, 250), (50, 250)], "region-02": [(640, 640), (780, 640), (780, 720), (640, 720)], } # 视频写入器 w, h, fps = (int(cap.get(x)) for x in (cv2.CAP_PROP_FRAME_WIDTH, cv2.CAP_PROP_FRAME_HEIGHT, cv2.CAP_PROP_FPS)) video_writer = cv2.VideoWriter("region_counting.avi", cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h)) # 初始化区域计数器对象 regioncounter = solutions.RegionCounter( show=True, # 是否显示画面 region=region_points, # 传入区域点集合 model="yolo26n.pt", # 用于区域计数的模型,例如 yolo26s.pt ) # 逐帧处理视频 while cap.isOpened(): success, im0 = cap.read() if not success: print("Video frame is empty or processing is complete.") break results = regioncounter(im0) # print(results) # 查看输出(区域计数等字段) video_writer.write(results.plot_im) cap.release() video_writer.release() cv2.destroyAllWindows() # 销毁所有打开的窗口 ``` 从源码实现看,`RegionCounter` 的构造函数会解析你传入的 `region`:若为单个点列表则自动包装为 `{"Region#01": [...]}`,若为字典则保留你自己的区域名;随后把每个区域构造成一个 shapely 多边形并做预处理(见 [region_counter.py](https://link.gitcode.com/i/35f34bdd0ddd5c6a3f44f59339828188#L92-L99))。RegionCounter()参数说明
RegionCounter的参数实际由统一的解决方案配置类 SolutionConfig 管理,它通过 dataclass 定义了全部可选项,构造时传入的**kwargs会覆盖对应默认值;若传入了不存在的键则会直接抛出ValueError。
解决方案级参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
model | str | None | Ultralytics YOLO 模型文件路径。当为None时,BaseSolution 会自动回退为yolo26n.pt |
region | list或dict | None | 感兴趣区域的点集合:可以是(x, y)元组列表,也可以是"区域名 → 点列表"的字典(多区域仅RegionCounter支持)。为None时使用内置默认多边形(四角坐标为(10,200),(540,200),(540,180),(10,180),见 solutions.py) |
line_width | int | 2 | 画面上边界框、关键点以及计数标注的线条粗细 |
verbose | bool | True | 是否启用每帧日志,输出输入尺寸、各类别数量与处理速度;跟踪调用本身始终是静默的 |
跟踪相关参数
RegionCounter内部把参数透传给model.track(),因此支持配置目标跟踪的各项参数。从 solutions.py 可以看到,iou、conf、device、max_det、quantize、tracker、imgsz会被统一收集到track_add_args,并在 extract_tracks 中连同persist=True、classes一起传给跟踪接口。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
tracker | str | 'botsort.yaml' | 指定使用的跟踪算法,内置选项包括botsort.yaml、bytetrack.yaml、ocsort.yaml、deepocsort.yaml、fasttrack.yaml、tracktrack.yaml(对应仓库 ultralytics/cfg/trackers 目录下的配置文件) |
conf | float | 0.25 | 检测置信度阈值;降低该值允许跟踪更多目标,但也可能引入误检 |
iou | float | 0.7 | 交并比(IoU)阈值,用于过滤重叠的检测框 |
classes | list | None | 按类别索引过滤结果,例如classes=[0]只跟踪人(person),classes=[0, 2, 3]只跟踪指定类别 |
device | str | None | 指定推理设备,例如cpu、cuda:0或0,用于在 CPU / 指定 GPU 等设备间选择 |
可视化参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
show | bool | False | 若为True,在窗口中实时显示标注后的画面,便于开发调试期即时查看效果 |
show_conf | bool | True | 是否在每个检测框标签上显示置信度分数 |
show_labels | bool | True | 是否在检测框上显示类别标签 |
区域计数的工作原理
从源码结构与注释看(见 region_counter.py),RegionCounter会把每个传入的区域构造成一个多边形。每个区域至少需要 3 个点,否则 add_region 会抛出ValueError;每个区域还会从 Ultralytics 调色板中分配到独立的绘制颜色。之后每一帧都会经过三个步骤:
- YOLO26 跟踪检测:通过
extract_tracks调用model.track(source=im0, persist=True, ...)对当前帧做检测与跟踪,得到每帧的目标框坐标、类别、跟踪 ID 与置信度; - 中心点归属判断:对每个被跟踪的目标计算其边界框中心点(取
(x1,y1)与(x2,y2)的中点),随后用预处理的 shapely 几何体(prepared_polygon.contains(center))判断该中心点落在哪些区域多边形内,落在哪个区域就给哪个区域计数加一; - 区域计数标注与清零:将每个区域当前的计数绘制在该区域多边形形心位置(带矩形底色的自适应标签),帧处理结束后把所有区域计数归零,等待下一帧重新累计。
需要特别强调的是:每个区域的计数每帧都会重置,因此画面上显示的数字是该区域当前的实时占用数(occupancy)——即此刻有多少目标位于区域内——而不是累计经过的总数。这也解释了为什么RegionCounter需要依赖跟踪:只有把同一目标在帧间关联起来(给出稳定的 track ID),中心点判断才不至于在目标移动时频繁误跳。
若你的目标是"累计统计穿越某条线或某个边界的目标进出次数",应当改用 ObjectCounter;线状(少于 3 个点)的计数区域也只有ObjectCounter支持。
从源码看每帧的处理细节
在 process 方法中,帧处理流程与数据结构如下:
- 区域计数的容器
region_counts在每帧开始时按{region_name: 0}重建,保证帧与帧之间互不残留; - 每个被跟踪目标先绘制出带
track_id、类别名与置信度的标签(具体拼接逻辑见adjust_box_label,受show_labels/show_conf控制),标签颜色依据track_id从调色板取值; - 区域多边形用
cv2.polylines绘制、角点处以小圆点强调,计数文本由adaptive_label以矩形底色的方式绘制在形心位置,并自动处理黑/白文本对比度。
返回结果对象:SolutionResults
每次regioncounter(im0)调用都会返回一个 SolutionResults 对象,本文相关的主要字段包括:
| 字段 | 类型 | 含义 |
|---|---|---|
plot_im | np.ndarray | 已标注好区域、计数与目标框的帧图像,可直接写入视频或保存 |
region_counts | dict[str, int] | 区域名到计数的映射,如{"region-01": 3, "region-02": 0},可直接用于告警与看板 |
total_tracks | int | 当前帧中被跟踪的目标总数(即len(self.track_ids)) |
speed | dict[str, float] | 由__call__填充的性能计时,包含track与solution两个阶段的毫秒耗时(见 solutions.py) |
此外,直接print(results)会列出结果对象中所有非默认值的字段,便于调试查看。
常见问题(FAQ)
在 YOLO26 中区域物体计数是如何工作的?
Ultralytics YOLO26 的区域计数方法是:先对画面中的每个物体进行跟踪,再判断其边界框中心点是否落在每个用户自定义的多边形区域内。区域内显示的数字是该帧的实时占用数,而不是累计总数。可配置参数见上文RegionCounter()参数说明 一节。区域多边形基于 shapely(要求shapely>=2.0.0,见 solutions.py)构建并预处理,以保证逐点包含判断(point-in-polygon)的性能。
如何一次统计多个区域?
把region参数以字典形式传入,字典的键是区域名、值是各自的点列表,例如 region_counter.py 官方案例:
from ultralytics import solutions region_points = { "region-01": [(50, 50), (250, 50), (250, 250), (50, 250)], "region-02": [(640, 640), (780, 640), (780, 720), (640, 720)], } regioncounter = solutions.RegionCounter(region=region_points, model="yolo26n.pt", show=True)每个命名区域会以独立的颜色绘制,并带有独立的计数。若你直接传入一个普通点列表(单个区域),它会自动被命名为Region#01。
如何以编程方式获取区域计数?
每次regioncounter(im0)调用返回的对象带有region_counts字典,把区域名映射到对应计数;同对象上还带有plot_im(标注后的帧)与total_tracks(被跟踪目标总数)。你可以直接打印该结果对象来查看所有可用字段。
是否可以只统计区域内特定类别的物体?
可以。传入classes参数并附上想保留的类别索引即可。例如使用 COCO 预训练模型时classes=[0]表示只统计人(person)。相关跟踪参数完整列表见上文RegionCounter()参数说明 一节。类别过滤会在model.track()调用时生效(见 solutions.py)。
RegionCounter 与 ObjectCounter 有什么区别?
RegionCounter显示的是当前帧有多少物体位于每个多边形区域内,即实时占用率;而 ObjectCounter 统计的是目标累计穿越某条线或某个区域边界的情况,会记录进出总数。需要做实时多区域占用监控请用RegionCounter,需要统计进出流量请用ObjectCounter;线状区域只有ObjectCounter支持。
小结
借助 Ultralytics 的RegionCounter,只需几行代码即可在任意多的命名区域内实时监控物体数量:CLI 一行命令即可跑通演示,Python API 则可与 OpenCV 视频管线无缝集成,并通过results.region_counts把计数接入你自己的业务逻辑。方案实现位于 ultralytics/solutions/region_counter.py,基类与配置体系分别在 ultralytics/solutions/solutions.py 与 ultralytics/solutions/config.py。如果想把计数场景进一步延伸,可以参考仓库中相关的其他指南,例如基于边界穿越累计计数的 ObjectCounter 物体计数、在单个区域内跟踪目标的 TrackZone 跟踪区域,以及更完整的 Ultralytics 解决方案索引。
【免费下载链接】ultralyticsUltralytics YOLO26, YOLO11, YOLOv8 — object detection, instance segmentation, semantic segmentation, image classification, pose estimation, object tracking项目地址: https://gitcode.com/GitHub_Trending/ul/ultralytics
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考