做视频数据集最大的痛点从来不是算法选型,而是标注。尤其是视频目标检测任务,动辄几千帧画面,一帧一帧画框能把人逼疯。我在2020年初接到一个内部项目,需要快速攒一批标注数据,专门去调研了一圈视频标注工具,最终锁定MIT开源的VATIC视频标注工具。它最大的特点是把人工标注和自动跟踪结合起来,标注员只需要在关键帧上画框,后台算法会帮忙把框延续到相邻帧,效率比纯手工高出一大截。
不过调研的时候发现一个很现实的问题:全网铺天盖地的教程都是基于Docker一键部署的,偏偏我们团队那台标注服务器出于统一管理考虑没有预装Docker环境,加上很多业务服务已经在裸机上跑着,实在不想为这一个工具打乱虚拟化规划。于是只能硬着头皮走非docker路线,自己手动把Apache、MySQL、PHP、Python和ffmpeg这一串依赖全部搭起来。这篇文章就是那次完整安装过程的记录,包括我踩过的坑,以及一些网上教程基本不会提的细节。如果你也在纠结要不要跳过docker手动装VATIC,或者已经装到一半卡住了,可以参考一下。
1. 为什么明明有docker版,我还要手动装
1.1 VATIC到底解决什么问题
先说清楚VATIC是干什么的,免得有人白折腾一趟。VATIC的全称是Video Annotation Tool from Irvine, California,一个用于视频目标标注的开源系统。它的核心解决思路是把对一段视频的目标标注从“逐帧画框”变成“关键帧画框+自动跟踪”。标注员打开网页,在某一帧画面里拖出一个目标框,标注这个目标是什么类别,后台会调用跟踪算法,自动把框扩散到前后几十帧里。标注员只需要在跟踪丢失或偏离的地方手动修正,然后确认,就能很快完成一个视频片段。
这套思路放在目标检测、行为识别、视频跟踪这类数据集的产线上非常实用。我手头这个项目需要一批“行人穿越路口”的视频片段,如果用普通标注工具一帧一帧抠,两个人干一周都未必能交付;用VATIC的半自动模式,时间能压缩到三分之一左右。这也是它十几年下来依然被人翻出来用、甚至还有人专门写非docker部署教程的根本原因。
你要理解的是:它本质上不是一个单纯的前端画框工具,而是一套“前端交互+后端跟踪计算”的完整系统。前端是PHP页面,负责把视频帧渲染在浏览器里,接收鼠标拖拽;后端是Python脚本,负责抽帧、跑跟踪算法、把结果写回数据库;MySQL在中间存所有标注数据;ffmpeg负责把视频拆成可标注的帧图片。这些角色缺一个都跑不起来。想清楚这条链路之后,非docker安装要做什么就一目了然了。
1.2 官方docker方案适合什么场景
MIT官方确实提供了一个Dockerfile,一条docker build加一条docker run就能把整个VATIC环境拉起来。如果你只是在一台有空闲Docker资源的机器上做短时间验证,或者想快速看一下界面长什么样,Docker方案非常省事,镜像里已经把系统依赖和配置都封装好了,不用关心底层装了哪个版本的PHP、MySQL。
但我那次没有选Docker,原因有三。第一,服务器上已经跑着内部业务服务,当时的环境里并没有预装Docker,单独为了一个标注工具去申请虚拟化资源,流程上要绕一大圈。第二,VATIC上游镜像停更多年了,基镜像里的系统库版本偏老,和当时的漏洞扫描基线对不上,安全同事那边就过不去。第三,也是最重要的一点,我们要在导出标注结果时对接自研的训练数据格式,直接改VATIC代码比包在容器里改、再重新打镜像要直观得多。
非docker安装的直接代价是,所有依赖细节都摊在你面前,每个环节都可能出问题。但好处也很实际:你清楚地知道每一步装了什么、为什么装它,后期要扩展、要修bug时,不用隔着一层容器猜来猜去。
2. 安装前需要理清的组件关系
2.1 系统环境怎么选
我这次安装在Ubuntu 16.04上完成。为什么选这个版本,不是因为我恋旧,而是VATIC的Python脚本和系统调用风格整体停留在Python 2时代。Ubuntu 16.04默认系统里Python 2和Python 3并存,安装Python 2的依赖包很顺手,PHP版本也还比较接近VATIC开发时期的5.x/7.0。如果你用的是Ubuntu 18.04之后的新系统,系统默认Python已经切到3.x,旧脚本很可能直接报语法错误,这时要么给代码打补丁,要么手动装一套Python 2.7环境,工作量会大不少。
选Ubuntu 16.04还有一个隐藏好处:它的软件源里还保留着python-opencv这个带Python 2绑定的包。到了18.04之后这个包基本没了,装OpenCV的兼容性麻烦事更多。
2.2 五大组件怎么协作
前面说过,VATIC要靠五个组件一起工作:Apache、MySQL、PHP、Python、ffmpeg。动工之前一定要把它们的协作关系理顺。
浏览器打开Apache提供的页面时,PHP代码会先请求MySQL,读取当前标注任务对应的视频帧信息以及已有的目标框记录,然后把帧图片渲染成页面里的画布。标注员在画布上拖出矩形框,PHP再把这个框的坐标和类别信息写回MySQL。Python脚本不参与这种实时交互,它的工作集中在任务准备和数据导出阶段:把上传的视频用ffmpeg抽帧,在抽取的帧序列上跑跟踪算法,或者把数据库里的标注结果导出成训练集格式。Apache是调度入口,PHP负责交互,Python负责计算,MySQL是中间仓库,ffmpeg是视频处理管线,缺一不可。
2.3 版本兼容的坑要提前踩
我吃过最大的亏是OpenCV版本兼容。VATIC后台脚本部分依赖OpenCV的旧接口,其中有些调用已经到了cv2.cv这个命名空间,OpenCV 3之后这个模块被移除了,直接ImportError。如果我一开始就装系统默认的新版OpenCV,连抽帧脚本都启动不了。所以安装之前我特意确认了一遍源里python-opencv对应的版本号,确保和代码的接口使用匹配,不符合就手动降级到兼容版本。
2.4 视频数据要提前规范化
安装软件之前,还有一件容易被忽略的事:准备视频数据。VATIC本身不负责视频转码,它默认你提供的视频可以被ffmpeg正常解码。如果你手里的素材是H.265编码、4K分辨率或者特殊封装格式,抽帧阶段会遇到很多莫名其妙的问题。我建议提前把待标注视频统一转成H.264+AAC编码的MP4,帧率也不要太激进,控制在25fps或30fps,这样抽帧稳定,标注时帧跳转也不会卡。
3. 逐项安装依赖
3.1 安装基础编译工具和软件包
一切从头开始。先更新软件源,然后装编译工具链。之所以先装build-essential,是因为后面有几个Python包需要现场编译,没有gcc和make会直接失败。接着把Apache、PHP、MySQL和git一次性装好。
sudo apt-get update sudo apt-get install -y build-essential python-dev python-pip git sudo apt-get install -y apache2 php libapache2-mod-php php-mysql sudo apt-get install -y mysql-server ffmpeg注意,这里的python-dev和python-pip都是针对Python 2的包,Ubuntu 16.04默认源里就有。如果你的系统已经更新到很新的版本,源里可能找不到这两个包了,需要先装Python 2本身,再从源码装pip。
装完之后先做一轮环境自检,确认每个组件都能执行:
php -v mysql --version ffmpeg -version apachectl -v这轮检查非常值得,能第一时间发现哪个包根本没装上,而不是等配置到一半才报错。
3.2 安装Python依赖
VATIC的Python脚本依赖NumPy、SciPy、OpenCV、Pillow和MySQLdb。Python 2环境下MySQL的Python驱动是python-mysqldb,这个包名跟Python 3时代的PyMySQL完全是两回事,不要搞混。如果后面你要在Python 3环境里跑,就得改代码里的import,细节不少。
我当时的安装命令如下:
sudo apt-get install -y python-numpy python-scipy python-opencv python-mysqldb sudo pip install pillow imageio提示:千万不要用
pip install opencv-python来装这个项目的依赖,这个包是给Python 3的轮子,Python 2里直接安装会报版本不支持。老老实实用系统源里的python-opencv最稳。
3.3 手动放一个更稳的ffmpeg
Ubuntu 16.04软件源自带的ffmpeg版本虽老,胜在稳定,处理常规H.264视频没毛病。不过我项目里的视频文件普遍比较大,抽帧压力不低,所以我还是手动下载了一个静态编译的新版ffmpeg,解压后放到/usr/local/bin,这样它会在系统自带的旧版本之前被优先调用。
sudo cp ffmpeg /usr/local/bin/ sudo chmod +x /usr/local/bin/ffmpeg放好之后执行which ffmpeg,确认输出的是/usr/local/bin/ffmpeg而不是/usr/bin/ffmpeg,否则后续抽帧脚本可能调用到老版本,出现一些诡异的参数兼容问题。
3.4 PHP和Apache扩展不能少
PHP要连接MySQL,需要php-mysql扩展;Apache要支持伪静态和前端路由,必须开启mod_rewrite,这一步装包时不会自动启用,要手动操作:
sudo a2enmod rewrite sudo service apache2 restart这里多说一句,很多人后面前端页面能打开,但接口全部404,大概率就是mod_rewrite没启用或者虚拟主机配置里AllowOverride没有设为All。这一个问题我后面专门有一节讲,但提前确认能省很多时间。
4. 克隆VATIC并配置虚拟主机
4.1 下载代码到服务器
代码我放在/opt/vatic,这样跟其他项目隔离得比较清楚,而且路径短,配置时不容易打错。需要注意权限问题,不要把整个目录都留给root,后面改代码、跑脚本都不方便。
cd /opt sudo git clone https://github.com/cvondrick/vatic.git sudo chown -R $(whoami):$(whoami) /opt/vaticVATIC仓库的目录结构大概会包含www、scripts、config.py、requirements.txt几个关键部分。www是Web根目录,所有浏览器访问的PHP和JS都在里面;scripts是Python命令行工具;config.py是数据库连接等总配置入口。每个版本的目录命名可能略有差异,以实际拉下来的仓库为准。
提示:如果你的网络拉GitHub不稳定,clone失败是常有的事,换个时间段重试,或者用国内可用的镜像源都行,这不影响部署后续步骤。
4.2 创建MySQL数据库和专用用户
MySQL启动之后,通过root进入命令行,创建数据库和用户。我强烈建议单独建一个应用专用账号,别让VATIC以root身份连数据库,否则一旦页面存在注入风险,整个数据库都暴露了。
CREATE DATABASE vatic CHARACTER SET utf8mb4; CREATE USER 'vaticuser'@'localhost' IDENTIFIED BY 'vaticpass'; CREATE USER 'vaticuser'@'127.0.0.1' IDENTIFIED BY 'vaticpass'; GRANT ALL PRIVILEGES ON vatic.* TO 'vaticuser'@'localhost'; GRANT ALL PRIVILEGES ON vatic.* TO 'vaticuser'@'127.0.0.1'; FLUSH PRIVILEGES;这里同时建了localhost和127.0.0.1两个用户,原因是Python的MySQLdb和PHP连接MySQL时采用的socket类型可能不同,一个走本地socket一个走TCP。后面如果发现连接总是失败,大概率就是漏了其中一个。
4.3 修改配置文件
VATIC的数据库配置在config.py里,把默认的配置改成你刚创建的用户名、密码和库名:
# config.py 中的数据库连接部分 database = { "host": "localhost", "user": "vaticuser", "password": "vaticpass", "dbname": "vatic", }改完配置后,先用一个最简单的Python语句验证数据库连接串对不对,别等部署完了再回来排查。
cd /opt/vatic python -c "import MySQLdb; conn = MySQLdb.connect(user='vaticuser', passwd='vaticpass', db='vatic'); print('数据库连接OK')"这一步能通,说明Python到MySQL的链路没问题,后面PHP出问题就是PHP侧的事,排查范围能缩小一半。
4.4 配置Apache虚拟主机
在/etc/apache2/sites-available/下创建一个站点配置文件,把DocumentRoot指到/opt/vatic/www,并配置目录选项。
<VirtualHost *:80> ServerName vatic.local DocumentRoot /opt/vatic/www <Directory /opt/vatic/www> Options FollowSymLinks AllowOverride All Require all granted </Directory> </VirtualHost>启用站点并重启Apache:
sudo a2ensite vatic.conf sudo service apache2 restart访问http://<服务器IP>/,如果能看到页面而不是默认的Apache欢迎页,说明Web层基本通了。如果只是空白或者403,优先检查目录权限和DocumentRoot路径。
5. 数据库初始化和业务配置
5.1 导入数据库初始化脚本
VATIC的建表语句一般以SQL文件形式存在于仓库里,常见位置是misc/schema.sql或install/schema.sql。找到后用命令导入:
mysql -uvaticuser -pvaticpass vatic < /opt/vatic/schema.sql导入完成后用SHOW TABLES确认一下表结构是否存在。我遇到过导入时因为SQL语句里用了CHARSET=utf8,而建库时指定的是utf8mb4,两者混在一起导致部分表建不出来。这种情况可以把SQL文件里的字符集统一替换成utf8mb4再导入。
5.2 处理用户编译和登录验证
VATIC原生设计是为众包场景准备的,登录和账号体系默认对接众包平台的身份验证。但内部工具链根本不需要这套,直接把验证逻辑绕过去或者手动插入一条管理员用户记录就行。
我的做法是:浏览代码搜索user和create_user相关的函数,搞清楚数据结构之后,在users表里插入一条带admin标记的记录,然后把配置里强制校验身份的开关关掉。这一步没有任何安装教程会细讲,但恰恰是很多人部署完打开页面却无法创建任务的直接原因。
5.3 先跑通抽帧验证
配置完数据库之后,别着急在网页端创建正式任务,先用命令行脚本把一段测试视频抽帧,验证ffmpeg和Python之间的调用链是否通畅。
cd /opt/vatic python scripts/extract.py --input sample.mp4 --output /tmp/vatic_frames --rate 5参数--rate 5表示每5帧取1帧,也就是每1秒约抽6帧。执行完去/tmp/vatic_frames目录数一下图片数量,正常情况下应该约等于视频总帧数除以5。如果抽出来是零张,优先检查ffmpeg路径和环境变量;如果数量对不上,可能是视频帧率处理有偏差,可以降低采样率再试。
6. 标注系统的实际使用流程
6.1 创建标注任务的关键参数
Web页面能够正常访问之后,进入系统创建一个新任务需要填写视频文件路径、采样率、目标类别列表。这里的视频路径是服务器上的实际路径,不是本地上传路径,所以要把视频先放到VATIC能访问的目录里。目标类别用英文逗号分隔,比如person,car,bicycle,这些类别最终会成为导出XML里的标注标签。
还有最关键的一项,任务输出目录的写权限。Apache的运行用户通常是www-data,如果输出目录是root创建的,标注结果保存时会直接失败,而且前台页面经常不报错,只往后台日志里写一条权限异常。这个坑让我白折腾过一个多小时。
6.2 画框与修正的操作逻辑
进入标注界面后,页面左边是当前视频帧,右边是目标列表和属性区域。操作流程很简单:先找到目标首次出现的关键帧,用鼠标拖一个初始框,选择类别,然后点击自动跟踪按钮,后台会生成后续若干帧的预测框。接下来就是逐帧快速检查,对跟丢或跑偏的框手动修正,确认无误后保存。
实际使用时你会很快体会到半自动跟踪的边界:目标运动平缓、形变小的视频,跟踪效果非常省力;但遇到遮挡、目标快速交叉、画面剧烈抖动的时候,后续预测框基本不能用,得老老实实手工一帧帧校正。所以创建任务时不要把采样率设得太高,否则修正工作量会非常大。
6.3 导出训练数据
标注完成后,用导出脚本把MySQL里的框坐标转成PASCAL VOC格式的XML。VATIC原生导出的就是这个格式,包含每帧每个目标的类别和边界框坐标。如果你想转成YOLO的txt格式或者COCO的json,写个几十行的小脚本转换就行,坐标数据都在数据库里,不会丢。
我建议导出之前先在后台统计一下任务里已完成和未完成的帧段数量。VATIC对漏标的帧段往往直接跳过,如果你不注意检查,导出文件会少掉某些目标,训练时模型就像瞎了一只眼,很难排查。
7. 遇到过的坑和解决办法
7.1 MySQL连接失败:密码明明是对的
这个问题的头号嫌疑是用户主机匹配。MySQL的localhost和127.0.0.1是两个不同的host,单独建了localhost用户后,Python通过TCP连接可能还是会被拒绝。解决方法是同时创建这两个用户,我在4.2节已经演示了。另一个常见原因是MySQL 5.7以后新装的系统默认采用auth_socket或caching_sha2_password认证插件,老版本PHP的mysql扩展不支持这种新插件,需要把VATIC用户的认证方式改回mysql_native_password:
ALTER USER 'vaticuser'@'localhost' IDENTIFIED WITH mysql_native_password BY 'vaticpass'; ALTER USER 'vaticuser'@'127.0.0.1' IDENTIFIED WITH mysql_native_password BY 'vaticpass';7.2 页面能打开但全站404
页面能打开说明静态资源正常,接口全部404说明伪静态路由没生效。按三个顺序排查:Apache是否启用了mod_rewrite,虚拟主机配置里AllowOverride是否为All,最后用apachectl -t检查配置语法。我那次就是AllowOverride写成了None,改过来重启Apache就正常了。
VATIC前端框架大量使用伪路径方式访问PHP后台,Rewrite失效时所有后台接口都会返回404。这个坑很隐蔽,因为没有明确的报错,只是看似“页面坏了”。
7.3 Python脚本报ImportError: No module named cv2.cv
这就是我在2.3节提过的OpenCV新旧接口不兼容。如果不想花大量时间改旧代码,我给代码加了一个兼容层,在脚本开头统一做别名映射,把旧的cv2.cv调用替换成新接口等价实现。这个方案改动小,能快速恢复大部分核心功能。
当然,更彻底的做法是把跟踪算法模块升级到OpenCV 4的API,但这相当于重写一小半后台代码,我建议先跑通全流程,然后按需改造。
7.4 ffmpeg抽帧很慢
如果服务器核心数少、内存有限,抽帧过程会明显拖慢整个任务创建。我的处理方法有两个:一是降采样率,从每2帧抽1帧改成每5帧抽1帧,数据量直接少一大半;二是把视频先用ffmpeg缩放到不大于1280x720的分辨率,抽帧再快不少。对于目标检测数据集,720p的标注精度通常已经够用,太高分辨率反而让标注员眼睛受累。
注意:抽帧是IO密集+CPU密集的混合任务,别在服务器业务高峰期大批量跑。我试过同时开好几个抽帧任务,直接把内存占满,最后系统进入swap疯狂换页,所有标注请求都开始卡顿。
7.5 中文标签乱码
数据库建库时如果没用utf8mb4,默认字符集会落成latin1,中文类别名存进去就是问号。另外PHP连接MySQL的session也要执行SET NAMES utf8mb4,否则链路中某个环节还是会转码。我建议在启动服务前统一检查数据库、数据表、连接串三处的字符集设置,这个检查最多几分钟,但漏掉的返工时间按小时算。
8. 最后说一点使用体会
真正把VATIC在这个裸环境里跑起来之后,团队连续用它标完了几千帧数据。我个人最大的体会是:装这类老工具,最难的不是装软件包,而是学会跟历史版本的代码共存。它的部分设计还停留在众包时代的思维方式,跟今天主流的深度学习工具链比确实不算贴心,但半自动跟踪的核心思路放到当下依然能打,尤其在视频目标检测数据生产上,它比很多现代标注平台更省力。
最后分享一个我一直沿用的技巧:启动服务前一定要把config.py里的日志控件打开,VATIC跑批处理任务时会在后台输出详尽日志。这些日志就是判断抽帧、跟踪、保存流程是否健康的关键,比反复刷新网页碰运气靠谱得多。如果你手里的服务器内存不紧张,把日志目录放到tmpfs上,标注高峰期能明显减少磁盘IO抖动,整个系统用起来更跟手。