做数据标注的同行应该都有这种体会:接到一批人车检测的数据包,打开文件夹发现几万张图,每张图上都是密密麻麻的行人和车辆,纯人工框选加分类,一天下来眼睛都快瞎了。后来我干脆写了一套“人车预标注”的 Python 算法流程:先用训练好的检测模型把所有图片自动跑一遍,输出 COCO 格式的标注 JSON,人工只需要在标注平台上做增删和修正。这套流程在几个智慧路口、停车管理相关的项目里实测下来,效率比纯手工提升了大概 3 到 5 倍,而且框的位置一致性比人工还好。这篇文章就把这套预标注算法的设计思路、模型细节、完整代码流程,以及我在实际运行中踩过的坑一次说清楚,需要的可以直接照着搭。
我做这套东西主要解决的问题很直接:人工标注速度太慢、质量不稳定、成本太高。自动预标注不是要替代人工,而是把人的精力从几百个框里解放出来,只去审核模型认为“有问题”的那部分。所以算法设计上要优先保证“宁多勿漏”,把该框出来的全框出来,同时留出低置信度样本给人工复核。真正跑起来之后你会发现,很多原来需要专门雇一个团队干的活,现在几个人就能轻松处理完。
1. 人车预标注的核心思路与方案选型
1.1 为什么需要预标注,到底省在哪里
先算一笔账。一张城市道路图片里如果平均出现 20 到 30 个行人和车辆,纯手工画框加选类别,熟练标注员一张图也得 40 秒到 1 分钟。一万张图就是将近 150 个小时的人工成本,这还没有算返工和质检。用预标注之后,模型先自动画好框并标好类别,人工审核一张图平均只要 10 到 15 秒,重点看漏检和错检的地方就行。效率提升不是一星半点,尤其是在做大规模数据集清洗和迭代的时候,省下来的时间非常可观。
除了省时间,还有两个隐性好处。第一个是一致性:同一个类别、同一个大小目标,人工画框会有个人习惯差异,有人喜欢紧贴边界,有人喜欢留点余量,而模型输出的框是统一的几何逻辑,后续训练模型时数据分布更干净。第二个是可迭代:预标注结果经过人工修正后回流到训练集,模型越训越强,下一次预标注的准确率还会提升,这是一个滚雪球式的正反馈。
有人可能会问,预标注的精度不够怎么办?这就是选型时要考虑的核心问题——预标注的定位不是“一次到位”,而是“尽量接近最终目标”。只要准确率在 90% 以上,人工修正的成本已经远低于从零画框。
1.2 算法选型:为什么用单阶段检测模型
做目标检测的模型大体分两派:两阶段检测器和单阶段检测器。两阶段的代表性架构是 Faster R-CNN 这一系,先用区域提议网络选出候选框,再对每个候选框做二次分类和回归,精度高但速度普遍偏慢。单阶段模型如 YOLO 系列则把目标定位和分类在一个前向推理里完成,没有独立提议阶段,速度自然快很多。
预标注场景对延迟极其敏感,因为数据量动辄几万张甚至几十万张,每张图慢 100 毫秒,整体耗时都会拉长很多。所以我的方案选的是单阶段检测模型,具体是 YOLOv8s——它在单阶段里属于兼顾速度与精度的折中选择,中等显存的 GPU 就能跑得很舒服。相比更早的 YOLOv5,YOLOv8 默认使用 anchor-free 的检测头,对不同尺寸目标的回归更直接,配套库的训练和推理接口也更规范,适合快速搭出预标注流程。
选型时还有一个实际因素:生态成熟度。YOLO 系列的权重、部署资料、周边工具非常多,遇到问题很容易找到解决方案。如果项目用的训练数据比较特殊,也可以基于 YOLO 框架从头训练或微调一个专用模型。从工程角度看,稳定性和可维护性比单纯的算法指标更值钱。
1.3 类别体系怎么定:人、车以及合并策略
预标注的第一步要先定类别列表,这直接影响标注文件的格式和后续训练的评估。在智慧交通、安防监控场景里,目标通常包括行人、轿车、货车、公交车、摩托车、自行车等等。如果全部按细类标注,模型要区分的类别太多,分类错误率会上升,人工审核时的负担也更大。
我在这个项目里采用了精简的类别体系:只分person和vehicle两类,其中vehicle涵盖轿车、货车、公交车、卡车等所有机动车。这么做有三个理由:一是道路数据里人车是主要参与方,大部分业务的最终决策只需要区分“人”和“车”;二是类别少,模型的学习负担小,准确率更容易做高;三是标注人员审核时不用纠结“这算 SUV 还是 MPV”,认知负担大幅降低。
如果业务确实需要细分,也不需要改太多代码,只要在配置里扩展 categories 列表并在后处理时保留模型的原始类别输出即可。这里有一个很重要的提醒:类别 ID 的定义顺序必须全局唯一且稳定,不然不同批次的标注文件合并后会出现类别号错乱的严重问题。
2. 环境搭建与模型细节解析
2.1 依赖安装:一条命令装完与版本雷区
这套预标注流程的依赖集中在 Python 生态里,核心组件包括 PyTorch、ultralytics 库、OpenCV、pycocotools、tqdm。我的建议是直接用 conda 建一个干净环境,Python 版本选 3.8 到 3.10。3.11 也能跑,但某些第三方库的预编译包可能不全,装起来容易碰到源码编译问题,没必要冒险。
安装命令大致是这样的,具体版本号建议锁定:
conda create -n prelabel python=3.9 conda activate prelabel pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python numpy pycocotools tqdm这里最容易踩的坑是 PyTorch 和 CUDA 的版本匹配。第一次跑的时候报Torch not compiled with CUDA enabled,十有八九是装了 CPU 版 PyTorch,只要按上面命令指定 CUDA 版本的安装源就能解决。还有一种情况是显卡驱动和 CUDA 版本不兼容,可以先在终端执行 Python 检查一下torch.cuda.is_available(),如果是 False 就说明 PyTorch 根本没有拿到显卡资源,需要重装匹配的版本。
ultralytics 库的接口变化也比较频繁,不同小版本之间model.predict()的返回值结构可能会调整。固定版本号是个好习惯,比如pip install ultralytics==8.0.0这种写法,可以避免第二天同事跑代码时因为库升级而报错。
2.2 模型结构速览:权重输入输出到底是什么
YOLOv8s 的网络结构大致可以分成三块:主干网络提取不同尺度的特征,颈部网络做多层特征的融合,最后检测头输出每个位置的预测信息。对于预标注工具来说,我们不需要深入理解每一层卷积是怎么设计的,但必须清楚模型的输入输出约定。
输入是 RGB 图像,默认会经过 letterbox 预处理变成正方形,常见尺寸是 640x640。模型的原始输出是一个张量,形状大致是[1, 候选框数量, 4+1+类别数],其中 4 表示预测框的中心点坐标和宽高,1 表示该位置有目标的置信度,后面的维度是每个类别的概率值。后面所有工作其实就是在处理这张表:过滤低置信度的框、做非极大值抑制、把坐标换算回原图、写进标注文件。
权重文件方面,可以直接使用公开的预训练权重,也可以使用自己业务数据微调过的权重。输出时建议至少准备两个格式:PyTorch 的原生.pt格式用于日常调试,ONNX 格式用于无 GPU 或跨平台部署。ONNX 的好处是只要环境里有 onnxruntime,任何机器都能跑,不依赖 PyTorch 的 GPU 版,对团队协作非常友好。
2.3 预处理逻辑:letterbox 与坐标还原的来龙去脉
模型要求输入固定尺寸,但原始图片的宽高比各不相同。最粗暴的做法是直接缩放到 640x640,但这样会把原本的矩形目标拉伸变形,小目标和细长目标的检测效果会明显下降。业界通用的做法是 letterbox:先把图片等比缩放到目标尺寸以内,再用灰色边把短边补齐到正方形。这样图片内容没有变形,模型看到的几何关系更接近真实世界。
letterbox 的计算过程用代码表达非常简洁:
import cv2 import numpy as np def letterbox(img, new_shape=(640, 640), color=(114, 114, 114)): shape = img.shape[:2] r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) new_unpad = (int(round(shape[1] * r)), int(round(shape[0] * r))) dw = (new_shape[1] - new_unpad[0]) / 2 dh = (new_shape[0] - new_unpad[1]) / 2 img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) return img, r, (dw, dh)调用ultralytics的predict时,letterbox 会在内部自动完成,返回的检测框坐标也已经换算回原图尺寸,大部分情况下我们不需要自己写还原逻辑。但如果你直接拿到原始张量自己写解码流程,就必须记住一个公式:原图坐标 = 模型输出坐标减去 padding 再除以缩放比例。很多人在这一步翻车,框全部往右下角偏移,就是忘了减去 letterbox 的左侧和上侧填充。
2.4 后处理逻辑:置信度阈值、NMS 与类别过滤
模型输出的一堆候选框里,绝大多数是低置信度的噪声框。预标注流程的后处理要做两件事:先按置信度把明显不对的框扔掉,再用非极大值抑制去掉重叠的重复框。
置信度阈值我一般设为 0.3 到 0.4 之间。如果跑出来漏检比较多,就把阈值调低一点;如果错误框太多导致审核工作量爆炸,就调高一点。需要特别强调的是,预标注场景的阈值应该比部署场景偏低,因为漏检意味着人工要额外画框,而多检一个错框只需要人工删掉,显然后者的成本更低。
NMS 的 IoU 阈值通常设 0.45 到 0.5。同一个行人被相邻锚点预测出两个重叠框时,NMS 会保留置信度更高的那个。如果发现密集人群场景中很多框被误删,说明 IoU 阈值太小,可以调大一点。另外,在多类别同时存在时还可以开启 agnostic NMS,也就是跨类别统一做抑制,防止“人”和“车”两个框重叠时被保留成两个不同类别的重复框。
3. 核心代码实现与流程拆解
3.1 预标注主流程:从图片列表到标注 JSON
整套预标注主流程可以拆成 6 个阶段:
- 扫描输入目录,拿到所有待处理图片路径。
- 加载模型权重,确定推理设备。
- 按批次读取图片,执行检测推理。
- 对每张图的检测结果做后处理和坐标换算。
- 组装 COCO 格式的 images、annotations、categories 三个字段。
- 输出 JSON 文件,并在本地生成一份可视化预览图。
这个流程看起来简单,但实际写代码时要注意异常处理,尤其是单张图片损坏或格式异常时,不能让整个任务中断。我的做法是单独写一个load_image函数,遇到读取失败的图片就记录日志并跳过,不影响整个批次运行。
3.2 推理与坐标换算的实现要点
下面是推理阶段的核心代码,可以在项目里直接复制修改:
from ultralytics import YOLO model = YOLO("weights/best.pt") results = model.predict( source=img_path, conf=0.35, iou=0.45, imgsz=640, device="0", verbose=False, ) boxes = results[0].boxes.xyxy.cpu().numpy() clses = results[0].boxes.cls.cpu().numpy() confs = results[0].boxes.conf.cpu().numpy()这里有三个要点需要注意。第一,boxes.xyxy返回的是原图坐标,左上角和右下角的 x、y 值,不需要再乘缩放比。第二,类别置信度和分类置信度是两回事,conf表示这个框是否包含目标的整体置信度,在做“宁多勿漏”策略时要看这个值,而不是单纯看某个类别的概率。第三,如果一次传一个图片目录给predict,ultralytics 内部会并行处理,但输出顺序有时候和文件排序不一致,建议还是按批次自主控制,用source=单张图的方式逐张推理,或者传入 list 并保持索引映射。
坐标换算成 COCO 的 xywh 格式时,我习惯用下面的小函数:
def xyxy2xywh(box): x1, y1, x2, y2 = box w = x2 - x1 h = y2 - y1 return [round(x1, 2), round(y1, 2), round(w, 2), round(h, 2)]保留两位小数是为了避免浮点数直接写入 JSON 产生很长的小数尾数,同时精度也足够人工审核定位。框的四个坐标还要做一次边界裁剪,防止模型输出超出图像宽高的负值,这种脏数据会直接让标注平台崩溃。
3.3 COCO 格式标注文件的组装与导出
COCO 格式是标注平台通用的标准之一,组装时要把三块信息分开维护。images列表里每个元素记录图片 ID、文件名、宽度、高度;annotations列表里每个元素记录标注框数据,包含 annotation 自增 ID、对应的 image_id、类别 ID、bbox、area 和 iscrowd 字段;categories列表固定类别顺序。
核心组装逻辑可以参考:
import json def build_coco_annotation(image_id, boxes, clses, confs, cat_map): anns = [] for bbox, cls_id, conf in zip(boxes, clses, confs): if conf < 0.35: continue x, y, w, h = xyxy2xywh(bbox) anns.append({ "id": len(anns) + 1, "image_id": image_id, "category_id": int(cls_id), "bbox": [x, y, w, h], "area": w * h, "iscrowd": 0, }) return anns写入 JSON 时要注意两个 Python 细节:一是json.dump要设置ensure_ascii=False,避免中文文件名变成 Unicode 转义;二是indent=4会让文件更易读,但如果你有几万张图的标注,生成的文件会非常巨大,建议先以数组形式在内存中累计,最后一次性 dump,而不是每一张图都打开文件追加写入。真的需要增量写入时,可以用手动拼接 JSON 数组的方式,或者直接拆分输出多个分片 JSON 文件,后续再合并。
3.4 视频输入场景:抽帧预处理与时间戳命名
很多项目的数据源不是图片文件夹,而是监控视频或者行车记录视频。视频直接输入检测模型虽然可行,但相邻帧内容高度重复,全部标注会造成数据冗余。我的做法是先按固定间隔抽帧,比如每 2 秒抽取一帧,再对抽出的帧做预标注。
抽帧用 OpenCV 的VideoCapture实现,每一帧保存为独立的 jpg 文件,文件名包含视频名和毫秒时间戳,方便后续回溯原始片段。比如video_name_000123456.jpg,这里的数字代表从视频起点到该帧的毫秒数。如果业务上还要用到目标的运动轨迹和速度信息,时间戳命名就变得非常重要,否则后续做跟踪和测速时无法对齐时域信息。
抽帧默认每 2 秒一帧对高速移动的场景可能太稀疏,对静止监控场景又可能太拥挤。更聪明的方案是按场景变换抽帧:计算相邻帧的像素差异,变化超过阈值才保存,这样静止画面不会产生重复样本,运动剧烈的段落又不会丢帧。这一段逻辑可以放到预标注流程的最前面独立运行,不影响检测部分。
4. 实操运行与性能调优指南
4.1 命令行参数设计:让同事拿到就能用
为了让这套预标注工具不只停留在自己的脚本里,我把入口封装成了标准的命令行程序,参数设计如下:
python prelabel.py \ --source /data/images \ --weights /model/best.pt \ --conf 0.35 \ --iou 0.45 \ --imgsz 640 \ --output /data/annotations.json \ --batch-size 8 \ --device 0几个核心参数的作用在项目文档里必须写清楚。source支持图片目录、单个图片、视频文件,程序先自动判断输入类型再走不同分支。conf和iou是后处理的核心参数,直接影响标注的“松紧度”。batch-size控制每次推理的图片张数,如果显存不足就把这个数字调小。output指定输出 JSON 的路径。
还有一个--review-dir参数我强烈建议加上,它会把置信度低于某阈值的检测结果拼接成一张大的可视化预览图,方便在正式标注前快速评估这批数据的质量。人工不需要打开标注平台,只要扫一眼预览图就能知道模型成色如何。
4.2 性能优化:从每秒几十张到上百张
预标注速度决定了整套流程的吞吐上限。在中等规模的 GPU 上,默认 FP32 精度、batch 8、640 输入尺寸,实测单张推理大约在 10 到 15 毫秒左右。但如果数据量有几十万张,这个速度还是不够看,需要考虑三个层面的优化。
第一层是推理精度降半。YOLOv8 可以开启半精度推理,显存占用几乎减半,速度提升通常在 30% 到 50%。如果部署环境支持 TensorRT,还能进一步压缩推理时间,但 TensorRT 的模型转换过程相对麻烦,建议等流程跑通后再做。
第二层是输入尺寸策略。本身全是高清大图的道路数据,直接把imgsz从 640 调到 960 或 1280,小目标检测效果会立竿见影地提升,但推理时间也会相应增加不少。这里的取舍要看项目需求:如果你的核心目标是“一次性生成可用的标注”,那大尺寸更划算;如果只是快速粗标,640 就够用了。
第三层是数据读取优化。批量推理时,CPU 读图速度经常成为瓶颈。使用多进程预取图片并做 letterbox,能让 GPU 始终保持满负荷。Ultralytics 自带的 dataloader 已经做了不少优化,但如果完全自己写循环,可以用concurrent.futures.ThreadPoolExecutor做图片加载,实测能把整体吞吐再提高 20% 左右。
下表是我在不同配置下的经验参考值,具体数字会因显卡型号和图片复杂度而波动:
| 配置 | 推理速度参考 | 适用场景 |
|---|---|---|
| FP32 + batch 4 + imgsz 640 | 中 | 小批量试跑、验证效果 |
| FP16 + batch 8 + imgsz 640 | 快 | 大批量预标注生产 |
| FP16 + batch 8 + imgsz 1280 | 中慢 | 小目标密集、高清数据 |
| ONNX + CPU | 慢 | 无 GPU 的临时环境 |
4.3 难例过滤:低置信度样本单独留给人工
预标注流程里最好的一个机制是把“模型搞不定”的样本单独拎出来。设置一个review_threshold,比如 0.3,那么凡是最高置信度低于这个阈值的检测结果,都认为模型不太确定,这些样本直接进入人工重点审核列表。
还有一个更实用的小技巧:按“图片中包含的低置信度框数量”排序,把那些低置信度框最多的图片排在审核队列最前面。原因很直接,一个图片里如果有 5 个框置信度都很低,说明这张图大概率是逆光、遮挡或极端天气,模型表现普遍不好,人工需要重点处理。那些全部框都在 0.8 以上的图片大概率没有大问题,可以快速略过或者抽检。
运行完预标注之后,强烈建议生成一个confidence_report.csv,里面记录每张图的图片路径、目标数量、平均置信度、最低置信度。这样不仅可以用来自查,还能间接评估模型在当前数据分布上的表现,为后续采集训练数据提供依据。
5. 常见问题与排查技巧实录
5.1 环境与运行时报错速查表
我把自己和同事在实际运行中碰到的高频问题整理成了下面的表,基本覆盖了从安装到跑批的绝大多数坑。
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| ImportError: No module named torch | 未安装 PyTorch 或环境激活错误 | 激活 conda 环境后重新安装 |
| Torch not compiled with CUDA enabled | PyTorch 装了 CPU 版 | 用指定 CUDA 版本的 index-url 重装 |
| pycocotools 编译失败 | Windows 缺少 C++ 构建工具 | pip 安装预编译包或先装视觉 C++ 工具 |
| RuntimeError: CUDA out of memory | batch 或 imgsz 太大 | 调小 batch,开启 FP16,升级显存 |
| AttributeError: NoneType has no attribute xyxy | 图片读取失败或推理结果为空 | 检查图片路径,增加跳过异常图像逻辑 |
| JSONDecodeError:标注文件无法解析 | 文件写入被中断或编码问题 | 用 ensure_ascii=False,避免增量追加损坏 |
还有一个容易被忽略的问题:图片文件名带有中文或非标准字符时,OpenCV 的imread在 Windows 下可能读取失败但不会报错,返回一个空数组。最稳妥的办法是统一用Path.glob扫描文件后读取,并在读取函数里判断img is not None,否则跳过。
5.2 检测质量问题的定位与解决思路
漏检和错检是预标注质量最大的敌人。遇到“白天效果好、夜间图一片稀烂”的情况,先不要急着骂模型。理想状态应该是把数据按光照、时段、天气分组统计检测表现,找出模型失效的具体分布。如果夜间图普遍漏检,高效的解决方案不是重新训练模型,而是先对输入图做自适应直方图均衡化或伽马校正,再重新跑预标注,往往就能捞回一大部分目标。
小目标密集场景下的漏检也很常见。远处整排的电动车、行人只有十几像素高,640 输入尺寸下模型几乎看不清楚,这时候一个直接的办法是调整模型输入尺寸,改用 960 或 1280。如果目标实在太小,还可以把原图切块,切成数个 640x640 的 patch 分别推理再合并结果。切块时需要留出耦合区域,避免目标正好被切在边界上一分为二。
重复框问题通常是 NMS 没有生效或者 IoU 阈值设得太高。密集人群里同一个行人被输出两个框时,iou=0.45可能无法合并它们,调到 0.5 到 0.6 就好。还有一种情况是人车重叠区域,行人在车前走过,模型同时输出一个高置信度的车框和一个低置信度的框,这时候开启 agnostic NMS 并按置信度保留最大的框,可以过滤掉这类干扰。
5.3 标注文件质量校验:上线前的最后一道保险
预标注文件如果直接交给标注平台,一旦格式有瑕疵就会被拒或者产生脏数据。我的做法是写一个几行代码的校验脚本,在交付前自动检查三类问题:坐标越界、宽高非正、类别 ID 不存在。
坐标越界的检测思路就是判断每个框的 x2 是否超过图片宽度、y2 是否超过图片高度,超过就把坐标裁剪到图像边界内。宽高非正的框说明模型的输出有异常,这类畸形框直接丢弃。类别 ID 不存在可能是类别映射表写错了,会导致后期训练时类别错乱。
校验跑完后,再生成一份标注分布统计:每张图的平均目标数、每个类别的目标总数、宽高比分布、目标面积分布。如果某个类别的数量异常少,很可能是预标注严重漏检,需要回到模型配置里检查。如果目标面积普遍异常小,则检查输入尺寸是否太小。这些统计指标看着不起眼,但实际上能防止很多“标注看起来没毛病、模型训出来一塌糊涂”的隐蔽问题。
6. 结果校验、人工审核与后续扩展方向
6.1 人工审核流程怎么和预标注配合
预标注生成的结果不是最终交付物,它只是把人工的工作量降到最低。审核环节我推荐“三层筛选法”:第一层只看低置信度样本和可视化预览图,把模型不确定的图都过一遍;第二层随机抽检 10% 的普通样本确认没有系统性漏检;第三层才是真正的全量审核阶段,主要是修框和补框。
如果数据量非常大,全量审核依然有压力,可以把审核界面按照“目标密度”排序。目标多的图优先审核,因为一旦模型在这些图上出了问题,影响的目标数量更多。目标只有一两个的图往往人工扫一眼就能确认,不需要花太多时间。
在具体操作上,导入预标注 JSON 到标注平台后,我习惯让审核员先理解模型的“脾气”:哪些场景容易漏检、哪些场景容易错检。比如模型经常把深色衣服的行人漏掉、把停在路边的卡车标成客车,审核员带着预判去检查,效率会成倍提高。第一轮预标注完成后,应该把审核数据记录下来,作为模型下一轮迭代的重点样本。
6.2 数据回流:让预标注模型越用越聪明
很多团队把预标注当成一次性工具,用完就扔,这其实吃亏了。正确的做法是建立“预标注—人工审核—模型迭代”的闭环:人工审核修正后的标注结果不直接流失,而是作为新的训练数据合并到原始训练集里,定期重新训练预标注模型。
第一次迭代可能提升有限,但经过三到五轮循环后,模型在业务数据分布上的精度会明显高于通用预训练模型。尤其是那些原本低置信度的困难样本,经过人工正确标注后加入训练集,模型在下一次预标注时对类似场景的表现会有肉眼可见的提升。这个过程就是主动学习的工程化实现——让模型主动挑选它最不确定的样本,优先让这些样本进入人工标注队列,从而用更少的标注量换取更大的模型收益。
实现回流时只需要在预标注流程里增加一个--update-dataset功能,把审核后的人工标注 JSON 按时段合并进训练数据集。同时保留一份人工标注历史,方便回溯每一轮数据修正的具体内容。
6.3 后续还能扩展什么方向
预标注工具本身是个很好的基座,它最大价值是培养了一条标准的数据生产管线。在这条管线上,可以继续扩展的方向不少。
第一个方向是加入目标跟踪。连续视频抽帧预标注的结果往往存在同一个目标在不同帧上被重复识别、ID 不稳定的问题。在预标注后接一个 ByteTrack 之类的跟踪算法,给每个目标分配稳定的 track ID,可以顺带输出目标的运动轨迹,后续做轨迹分析、车流量统计、逆行检测都会方便很多。
第二个方向是从矩形框进化为轮廓或实例分割。对严格车损检测、遮挡判断、精细标注的业务来说,矩形框不够用。在预标注框的基础上,调用 SAM 这类分割模型把框内目标分割成精确的像素级掩膜,生成 Polygon 格式标注,人工只需要在轮廓不准的少数区域做微调。这个流程比纯人工画多边形快得多。
第三个方向是类别扩展。目前只有 person 和 vehicle 两类,如果要扩展出 red-light、lane-line、traffic-sign 等类别,只需要在类别映射表里增加定义,同时用包含这些类别的模型权重替换运行参数。数据标注管线的整体架构基本不用动。
跑完几万张图像之后,我感受最深的一点是:预标注这件事看似简单,真正要落地反而需要很多细节打磨。从阈值设定到难例筛选,从坐标换算到性能调优,每一个环节都直接影响最终交付物质量。如果把模型、参数、审核流程沉淀成一套可复用的工具链,那它带来的效率提升就不是一锤子买卖,而是整个团队在后续每个新数据集上都能吃到红利的长线投资。