如果你要做目标检测或者视频目标跟踪,第一步往往不是调模型,而是先把训练数据准备好。标注一个视频里每个目标每一帧的位置,听起来不复杂,真做起来又磨人又容易出错。VATIC 就是干这个的开源视频标注工具:打开浏览器,在视频帧上给目标画框、打标签,它能借助帧间匹配自动延续轨迹,最后把标注结果导出成结构化数据。我 2020 年初接手一个视频数据集整理任务时选了它,但当时能搜到的教程几乎一边倒地推荐 Docker 一键安装,而我所在的环境里 Docker 并不是首选,于是被迫走了一遍"非 Docker"的完整安装流程。这一趟下来,真正花时间的不是工具本身,而是 Python 2、老版本 Django、MySQL 驱动、前端静态资源这些零碎的兼容性问题。这篇文章就是把当时从零到能标注视频的完整过程、踩过的坑和排查思路整理出来,给同样需要在裸环境里装 VATIC 的人做个参考。
1. 先搞清楚 VATIC 的工作逻辑,再谈安装
1.1 VATIC 到底解决什么问题
VATIC 是一个典型的"Web 前端 + 后端服务 + 视频帧处理管线"组合。标注员不需要安装任何客户端,打开浏览器访问一个页面,就能看到视频的连续帧。你在某一帧上拖出一个矩形框,选一个标签,比如"car"或者"pedestrian",VATIC 会尝试在后续帧里自动跟踪这个目标,把框延续下去;如果跟丢了,你只需要手动调整一下。这种交互方式明显是给"视频目标跟踪"标注场景设计的,和单纯给图片画框的工具思路完全不一样。
标注结果最终落到数据库里,可以通过脚本导出成带时间戳、标签、轨迹编号和坐标信息的结构化数据。训练检测模型或者跟踪模型的时候,拿这份数据做训练集就够了。理解这一点很重要,因为后面安装时你会发现很多配置都是围绕这个流程设计的:MySQL 管任务和标注,FFmpeg 负责把视频拆成帧,OpenCV 做帧间特征匹配,Django 负责页面和接口。
1.2 为什么我不直接上 Docker
VATIC 这种老工具,依赖链确实脆,Docker 镜像把整个环境冻起来,理论上最省事。但实际工作中"非 Docker"的需求非常常见:有的是内网离线环境,拉不了镜像;有的是服务器安全策略不允许跑容器;有的是需要改源码做二次开发,容器里改代码来回同步很别扭;还有的是想直接把它接进已有的 MySQL 和数据处理脚本,Docker 反而多了一层隔离。
我当时的处境就是第三种加第四种混合。所以我选择在裸环境里搭,整个过程虽然折腾,但好处是你能清清楚楚看到每一步在做什么,出了问题可以直接进代码里查,不用隔着容器猜。
1.3 依赖链拆解:Python 2 时代的遗产
VATIC 的主代码停留在 Python 2 时代,这是所有麻烦的根源。它依赖的组件放到 2020 年,每一个都可能变成坑:
| 依赖 | 作用 | 典型问题 |
|---|---|---|
| Python 2.7 | 运行环境 | 新系统默认只有 Python 3,Python 2 需要额外安装或编译 |
| Django 1.x | Web 框架和标注接口 | 老版本 API 和现代版本差异大,装新版本可能直接跑不起来 |
| MySQL + MySQL-Python 驱动 | 存储任务和标注数据 | 驱动编译需要 mysql 客户端开发库,Python 2 兼容版本难找 |
| OpenCV | 帧间目标追踪 | 新版不提供 Python 2 轮子,版本选择要小心 |
| FFmpeg | 视频拆帧 | 系统里不一定预装,且要能被脚本直接调用 |
| 前端 jQuery 系列库 | 标注页面交互 | 下载脚本依赖公共 CDN,网络受限时直接失败 |
这些依赖环环相扣:Python 版本影响 pip 可用版本,pip 版本影响依赖包能不能装,Django 版本影响数据库初始化命令,数据库驱动又影响 Django 启动。所以安装顺序和版本锁定非常重要,这也是我觉得非 Docker 安装最值得写清楚的部分。
2. 安装前的环境准备:先搭地基,再盖房子
2.1 系统依赖和编译工具
在开始碰 VATIC 之前,先把系统的编译环境和基础库准备好。VATIC 的几个 Python 扩展包都需要编译,比如 MySQL 驱动、OpenCV、Pillow,如果系统里没有编译器和对应的开发头文件,pip 安装到一半就会报错。
我当时的做法是先把这些装齐:C 编译器、make、Python 2 开发头文件、libjpeg 开发库、MySQL 客户端开发库。不同发行版包名略有差异,但在 Debian 系系统上思路一致。为什么一定要开发头文件?因为编译 Python 扩展时,代码里要 include 对应的头文件,系统里只有运行时库没有 dev 包,编译器找不到头文件就直接失败。这个错误信息经常是"Python.h: No such file or directory"或者"mysql_config: command not found",看到这两个报错,基本就是 dev 包没装齐。
2.2 Python 2 环境:优先用 pyenv 隔离
2020 年的时候,部分系统还自带 Python 2,但不是所有环境都有,而且我建议你不管系统有没有,都用 pyenv 单独装一个 Python 2.7 并创建虚拟环境。原因很现实:VATIC 老代码可能隐式依赖某些包版本,直接装进系统 Python 里容易和系统其他工具冲突;用虚拟环境隔离之后,就算把环境搞坏了,删掉重建就是,不影响系统。
我当时用 pyenv 安装了 Python 2.7.18,这是 Python 2 的最后一个发布版本,也是相对最稳的。安装前需要确认 zlib、readline、sqlite 等基础库的开发头文件都在,否则 Python 编译出来会缺模块,后面 pip 装包时会莫名报错。创建虚拟环境之后,整个安装过程都在这个环境里进行:
pyenv install 2.7.18 pyenv virtualenv 2.7.18 vatic_env pyenv activate vatic_env这里有一个容易被忽略的细节:Python 2 环境下能用的 pip 最高只到 20.x,装完 pip 之后不要手贱升级到 21 及以上,否则 pip 直接拒绝在 Python 2 里运行。我自己就吃过这个亏,升级完才发现打不开,只能重建环境。
2.3 先把 MySQL 准备好,避免后面反复改配
VATIC 默认把标注数据存在 MySQL,所以数据库要提前建好。这一步别偷懒用 root 直连,单独建一个专用账号更安全,也更符合后面多人协作的使用方式。我建库时特意指定了 utf8mb4 字符集,主要为了避免中文标签在写入时变成乱码:
CREATE DATABASE vatic_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'vatic'@'localhost' IDENTIFIED BY '这里填你的密码'; GRANT ALL PRIVILEGES ON vatic_db.* TO 'vatic'@'localhost'; FLUSH PRIVILEGES;MySQL 的版本我建议不要太新,虽然新版一般也能用,但老驱动对新版认证插件可能有兼容性问题。如果你发现后面 Django 连接时报认证相关的错误,优先考虑把 MySQL 用户的认证方式调回兼容模式,而不是去改代码硬扛。
3. 安装 VATIC:源码、配置、依赖和前端资源
3.1 拉取源码并看懂目录结构
源码直接用 git 拉下来就行。仓库地址你在开源社区里搜一下 VATIC 就能找到,这里不贴具体 URL 了,避免时间久了地址失效误导你。拉下来之后,先别急着敲命令,花两分钟看一下目录结构,后面排查问题会省很多事。
项目里几个关键区域要注意:public目录放前端静态资源,包括页面模板、图片、JavaScript 文件;www目录是 Django 主应用;根目录下放着几个入口脚本,比如加载视频的load_video.py、导出标注的dump.py、启动服务的脚本等。理解这些之后,你就能判断某个报错到底是前端问题还是后端问题。
3.2 修改数据库配置
数据库连接信息在 Django 的配置目录里,一般是一个叫settings.py的文件,也可能是单独的数据库配置模块。找到数据库配置那一段,改成你自己的库名、账号、密码和主机地址:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'vatic_db', 'USER': 'vatic', 'PASSWORD': '你的数据库密码', 'HOST': '127.0.0.1', 'PORT': '3306', } }这个地方看着简单,但我要提醒一点:老工具配置里可能还会带数据库后缀或者其他与时代相关的参数。如果你在启动时报出关于数据库引擎不支持的错,先确认 Django 版本和这个配置格式是不是匹配,不要急着改引擎类型,很可能是你把 Django 装成了新版本,和 VATIC 预期的不一致。这时候应该退回老版本 Django,而不是迁就新版本改代码。
3.3 安装 Python 依赖:不要一口气全装
项目一般会带一个 requirements 文件,里面是它声明过的依赖清单。但直接用pip install -r requirements.txt不见得一次成功,因为有些版本号可能已经找不到,或者和当前系统环境冲突。我当时的策略是:先把清单看一遍,把明显和系统绑定的、可能冲突的包拆出来单独装,其余用 pip 一次性装。
最终我的虚拟环境里实际跑起来的一组核心依赖包括:Django、MySQL-Python 驱动、Pillow、numpy、opencv 对应版本。OpenCV 这里要特别说一句,在 Python 2 环境下,新版轮子已经不可用了,必须找一个还支持 Python 2 的版本,如果你不想在这个环节浪费太多时间,可以直接试试从系统包或者老版本轮子里找。
安装命令大致是这样:
pip install -r requirements.txt如果 pip 中途因为某个包编译失败而中断,不要反复重试同一个命令。先看报错缺哪个头文件,补上对应 dev 包再继续,否则永远在同一个地方打转。
3.4 前端 JavaScript 库:非 Docker 安装最大的坑
VATIC 的页面交互依赖一批第三方前端库,比如 jQuery、jQuery UI、热键处理、气泡提示之类的组件。官方为了省事,提供了一个下载脚本,会从公共 CDN 把这些库拉下来放到public/js目录。理想情况下你只需要跑一下这个脚本,但在很多网络环境里,这个脚本基本是跑不通的。
我的建议是直接手动补齐。操作分三步:
第一,打开下载脚本,把里面需要拉取的文件清单逐条读一遍,看清每个文件应该放在哪个路径。第二,找到一个你能稳定访问的公共 CDN 或 npm 镜像,按清单把对应文件下载到本地。第三,按照清单里的路径,把文件放进public/js以及相关子目录。
这里还有个实用技巧:如果你漏了某个文件,其实不用猜,直接启动服务打开标注页面,按浏览器 F12 看 Console 面板里的 404 请求,哪个文件 404 就补哪个。这个方法比我第一次傻傻地把整个目录对比一遍快得多。
3.5 初始化数据库:老 Django 的 syncdb
依赖装好、配置改完,下一步是初始化数据库表。VATIC 使用的是老版本 Django,那个时代的初始化命令是syncdb,它会自动创建所有未建的表并询问你是否创建超级用户:
python manage.py syncdb注意,如果你看到的 Django 版本不再支持syncdb命令,说明依赖被装得太新了。老工具用了很多旧 API,强行用新版本 Django 可能不只是命令差异的问题,后续页面上还会冒出一堆兼容性报错。正规解法是退回 VATIC 预期的那一代 Django,而不是换新命令硬试。
创建超级用户这一步很重要,不然你等会儿登录不了标注页面。用户名、邮箱、密码按提示填就行,标注员账号可以在后面通过 Django 自带的后台去建。
3.6 加载第一个视频任务
数据库初始化完成后,可以尝试加载一个视频了。VATIC 的逻辑里有一个"任务"的概念:一个任务包含一段视频(或视频片段)、一组预定义标签和对应的标注入口。加载视频用根目录下的load_video.py,它内部会调用 FFmpeg 把视频拆成帧,再把这些帧的信息写入数据库。
我当时的典型加载命令是这样:
python load_video.py --offline --height 720 --label "car,pedestrian" demo.mp4 demo_task解释一下几个参数的作用。--offline表示直接把视频全部拆帧处理,不依赖流式处理,大多数本地使用场景都推荐加这个参数。--height 720是限制帧图高度,原视频如果特别大,不限制尺寸会把磁盘和数据库都撑爆,而且标注页面也会卡。--label用逗号分隔预定义标签,如果漏了这一步,标注时还得临时创建标签,容易造成标签不统一。最后两个参数分别是输入视频路径和任务名。
加载完成之后,脚本会输出一个任务编号和访问链接,记住这个编号,后面导出标注会用到。
4. 从加载视频到导出标注,完整流程走一遍
4.1 启动服务并登录标注页面
加载视频之后,启动服务。项目根目录一般自带启动脚本,如果你只是自己标注,可以直接用 Django 开发服务器跑起来。关键的一点是,标注页面要能正常加载视频帧,依赖前面的前端 JavaScript 资源和帧图路径都正确,所以启动之前先确认这两点。
启动后浏览器访问对应端口,用刚才创建的超级用户账号登录,你就能在任务列表里看到刚才加载的demo_task。点击进入就是标注画布。
4.2 标注操作的核心逻辑
VATIC 的标注操作并不难,难的是理解它的"自动追踪"机制。你在某一帧画一个框并打上标签,它会试图在下一帧找到这个目标并自动把框移过去。如果目标外观变化不大、画面不剧烈抖动,追踪效果是很不错的;如果目标被遮挡或者运动太快,就需要手动干预。
第一次使用不要上来就标正式数据,先拿一段只有一两个目标的短视频练习一下。把所有按钮、快捷键试一遍,搞清楚"保存"到底是只保存当前帧的框,还是保存整个轨迹的修改。这一步能帮你避免标到一半发现操作逻辑搞反了,白费半天功夫。
我个人习惯是先粗略地把所有目标画完框、打完标签,再逐帧回放检查轨迹有没有跟丢。逐帧回放时会有遗漏,所以我会重点检查目标被遮挡、快速转向、进画面和出画面的那几个关键帧。
4.3 导出标注结果
标注完成之后,用dump.py导出数据。基本用法是把任务编号传进去,用-o指定输出文件:
python dump.py -o labels.json demo_task导出的 JSON 结构在不同版本里可能略有差异,但核心字段是稳定存在的:对象标签、轨迹编号、帧号,以及这一帧上包围框的坐标。坐标一般就是左上角和右下角的像素位置,或者左上角加宽高。拿到这份数据之后,很多下游任务的格式转换都是围绕这些字段展开的。
举个例子,如果你想转成目标检测常用的 YOLO 格式,需要把每个框的坐标归一化到 0 到 1 之间,并按类别整理。这个转换脚本并不复杂,关键是把 VATIC 的坐标字段含义搞清楚再动手,否则坐标系统一错,后面训练就全错了。
4.4 多人标注时怎么管理任务
如果你不是一个人标注,VATIC 的用户系统可以派上用场:通过 Django 管理后台创建普通账号,把不同视频段分给不同账号去标注即可。实际使用中要注意任务权限的问题,最好让不同标记者之间看不到对方的未完成任务,避免误操作。老工具在这块功能比较朴素,所以分配任务时我会手动做一个任务和账号的对应表,这个工作用 Excel 管理比在工具里强行改权限更现实。
5. 我踩过的坑:问题排查实录
5.1 数据库驱动编译失败
症状:安装 MySQL-Python 驱动时,编译到一半报错,提示找不到mysql_config,或者找不到 Python 头文件。
原因:系统里没有装 MySQL 客户端开发库,或者 Python 2 的开发头文件没装。编译器需要mysql_config来定位 MySQL 的编译参数,也需要Python.h来了解解释器接口,缺一个都会失败。
处理:把对应的开发包补上,然后再重装驱动。这个坑基本属于"环境准备没做好"的连锁反应,所以我在前面章节专门强调先装 dev 包。
5.2 pip 报 SSL / TLS 错误
症状:在 Python 2 环境里用 pip 下载包时,报错提示 SSL 证书校验失败或者 TLS 版本过低。
原因:Python 2 自带的 SSL 模块对新的 TLS 协议支持有限,而 2020 年之后的 PyPI 服务端对协议版本要求已经比较严格,老 pip 根本握不上手。
处理:先把 pip 升级到 Python 2 能用的最高版本,如果仍然报错,再考虑配置 pip 使用兼容的软件源。这个操作要小心,别把 pip 升到不兼容 Python 2 的版本,否则整个环境就废了。
5.3 标注页面打开白屏,控制台报一堆 404
症状:页面能打开但布局混乱,JS 功能全没生效,浏览器控制台里大量 404。
原因:前端 JavaScript 库没补齐。下载脚本失败之后,public/js目录里缺少文件,页面引用了不存在的资源。
处理:我前面提过的排查顺序就很管用——先看下载脚本里的清单,再看浏览器 Console 里的 404 列表,缺哪个补哪个。这个问题其实很简单,但如果不理解事情的前因后果,很容易在 CDN 和网络配置上瞎折腾。
5.4 加载视频时 ffmpeg 找不到
症状:运行load_video.py时直接报错,信息里出现 ffmpeg 或者 avconv 相关的提示。
原因:系统没有安装 FFmpeg,或者安装后不在PATH环境变量路径里,脚本找不到可执行文件。
处理:安装 FFmpeg 并确认它在命令行里可以直接执行。另外,如果你的视频编码比较特殊,FFmpeg 版本太老也可能拆帧失败,所以尽量用较新的版本。
5.5 中文标签导出变乱码
症状:标注时中文标签正常,导出后变成乱码。
原因:数据库连接或建库时的字符集不是 utf8,老工具默认可能不是 utf8mb4。
处理:建库时显式指定 utf8mb4,连接配置里也要把字符集相关参数加上。这个配置最好在数据库初始化阶段一次性解决,等标了很多数据再改字符集,迁移数据很痛苦。
5.6 保存标注没反应
症状:画完框点保存,界面没有报错,但刷新后标注丢了。
原因:大多是前端请求失败或者后端没有正确接收到数据。先看控制台有没有请求报错,再看后端日志。前端 404 是常见原因,后端接口报错则通常是 Django 版本不匹配或者数据库写入失败。
我把这些高频问题整理成一张速查表,方便你直接对着排查:
| 症状 | 首要怀疑方向 | 快速验证 |
|---|---|---|
| 编译失败缺头文件 | dev 包缺少 | 看报错中的头文件名 |
| pip 无法下载包 | Python 2 / pip 版本 | 查看 pip 版本和报错 |
| 页面白屏或 JS 失效 | 前端资源缺失 | 浏览器 Console 看 404 |
| 视频无法拆帧 | FFmpeg 缺失 | 命令行执行 ffmpeg 验证 |
| 中文乱码 | 字符集配置 | 查看数据库编码 |
| 保存无响应 | Django 或前端请求 | 看后端日志和 DevTools |
6. 安装完成之后的工作流优化
6.1 把环境固化成脚本
非 Docker 安装最大的痛点是环境不可复现。这次装完之后,我做的第一件事就是把整个安装过程整理成一个可重复执行的安装脚本,并把所有 pip 依赖包提前下载成本地文件。这样即使下次换一台机器,或者在离线环境里重复部署,也不需要再从零踩一遍坑。
依赖离线打包的命令思路是:
pip download -r requirements.txt -d ./wheelhouse装好之后把wheelhouse目录和安装脚本一起拷贝到目标机器,用pip install --no-index --find-links=./wheelhouse来安装。这个方法把"能不能上网"这个变量彻底移除了,后续迁移环境非常踏实。
6.2 标注数据的后处理
VATIC 导出的 JSON 只是中间产物,实际训练之前,通常要转成你模型框架需要的格式。我在项目里写了一个很小的转换脚本,专门从导出的 JSON 中提取标签、轨迹编号、帧号和包围框坐标,再根据映射关系转成目标格式。这个脚本建议在正式标注开始之前就写好,因为你可以先用两条视频测试导出结果,确认字段含义,避免标完几百个视频才发现坐标理解错了。
6.3 关于版本锁定的一句切身体会
老工具最忌讳的是"顺手升级依赖"。VATIC 这种项目,代码里很多写法都是针对特定年代版本的依赖,升级一个包可能导致完全不同的接口行为。如果没有明确的 Bug 要修,不要动版本。我在使用过程中唯一一次把依赖装了新版,结果页面直接打不开,最后老老实实退回旧版本。这个教训的成本不高,但很值得记住。
6.4 后续还可以怎么扩展
如果你只是临时标注几十个小时的视频,非 Docker 安装完全够用,按照上面的步骤,一个下午就能跑起来。但如果你要把 VATIC 长期提供给一个团队使用,建议还是认真考虑把环境固化成镜像或者容器,原因不是非 Docker 装不了,而是长期维护一套脆弱的 Python 2 环境,成本会随着时间推移不断上升。反过来,如果你需要深入改代码、调试追踪算法、或者把标注流程集成进自己的工具链,裸露在外的环境反而更方便,直接改文件、直接重启服务就能看见效果。
根据我个人的体会,选 Docker 还是非 Docker,不用跟着教程走,而要看你后续打算怎么用这个工具。环境隔离和可复现性固然重要,但代码可改、问题可见、结构透明也同样重要。只要把依赖版本锁死、把安装过程脚本化,非 Docker 方案完全能够在实际项目中稳定撑起一套视频标注流程。