大家做视线追踪相关项目的时候,最容易犯的一个毛病是把模型在实验室里跑通一次、把注视点画在屏幕上,就认为“完事了”,然后拿着演示视频去汇报。可真要到产品化、对标测试、论文对比算法优劣的时候,才发现自己手里根本没有一套能说清楚“这套东西到底准不准、稳不稳”的依据。我用视线追踪做了三年多,从红外主动光照到纯RGB外观回归都折腾过,最深的体会是:没有一套完整的性能评估框架,你的算法再花哨也没法证明自己比别人强,甚至连自己下一步该优化什么都看不出来。
这篇文章我打算把视线追踪的基础知识和性能评估框架放在一起聊,重点不是再讲一遍论文里的公式证明,而是把我实际搭建评估系统时用到的思路、指标、计算方法和踩过的坑整理出来。无论是刚入门的研究生、正在做AR/VR眼动的工程师,还是想评估摄像头注视估计算法方案的团队,这篇文章应该都能帮你少走点弯路。
1. 视线追踪到底在追什么:先把概念捋清楚
1.1 什么是视线追踪
视线追踪,也叫眼动追踪、注视估计,本质上是根据人眼图像或者眼部特征,推断人的注视方向或注视点位置。这里有一个关键点要搞清楚:视线追踪不等于瞳孔追踪。瞳孔追踪只是在图像里找到瞳孔的中心位置,而视线追踪要把这个二维的瞳孔位置映射到屏幕坐标、场景坐标或者三维视线向量上。
举个例子,你在电脑上放一个摄像头,摄像头拍到用户的脸,算法框出左眼和右眼,找到瞳孔中心,再通过某种映射模型估算出这个人正在看屏幕上的哪个位置。这个过程的输出通常有两种:
- 屏幕注视点坐标,通常是二维的(x, y),单位是像素或者毫米,坐标系原点在屏幕左上角或中心。
- 三维视线向量,通常以眼球中心为起点,表示在相机坐标系或世界坐标系中的一束射线。
我做过的多数项目最终要的都是二维注视点坐标,因为下游业务比如广告注视热点分析、用户交互意图判断都是基于屏幕位置的。但如果你是做VR眼镜里的眼动交互,那更关心的往往是三维视线向量,因为它要跟虚拟场景里的物体做碰撞检测。
1.2 三大技术路线的取舍
视线追踪的技术路线这几年变化很大,但大致可以分成三大类:
第一类是主动光特征法。典型代表就是那些带红外灯珠的眼动仪,利用角膜反射和瞳孔中心之间的向量来估计视线。它的优点是精度高、鲁棒性好,能在一定光照范围内稳定工作,缺点是需要专门硬件,红外光源会增加成本和功耗,而且强日光环境容易出现反光点丢失。
第二类是外观回归法。用RGB或者灰度摄像头拍下人脸,然后通过CNN之类的神经网络直接从眼部区域回归出视线角度。这类方法的优点是硬件要求低,一颗普通摄像头就能干,缺点是对光照、头部姿态、个体差异都比较敏感,精度目前普遍低于主动光方案,但胜在部署成本低、场景灵活。
第三类是模型拟合法。它介于前两者之间,尝试通过拟合眼球三维模型(比如把眼球当成球体、虹膜当成圆盘)来解算出光轴方向,再用个体标定映射到视轴方向。这种方法的精度上限很高,但对模型参数的初始化和标定比较敏感,计算量也偏大。
我实际观察到的行业现状是:消费级头显里,主动光方案仍然占主导,因为要保证交互的低延迟和高精度;而手机前置摄像头、车载驾驶员监控这类对成本敏感、环境相对可控的场景,外观回归法逐渐成为主流。选哪条路线,本质上是一个成本、精度、鲁棒性和功耗之间的对赌,没有绝对好坏。
1.3 不同形态的视线追踪设备
除了算法路线,设备的物理形态也直接影响评估方式。
- 桌面式/远程式:摄像头固定在屏幕上,用户在屏幕前使用,头部活动空间有限。评估时以屏幕坐标误差为主。
- 头戴式/嵌入式:摄像头固定在眼镜、头盔或者VR设备内部,相机跟着人头动,算法通常输出三维视线向量。评估时以角度误差为主。
- 移动式前置摄像头:手机、平板上用,用户手持设备,距离和角度变化范围很大,评估难度最高。
不同形态下,性能评估的关注点差异非常大。桌面式设备你可以慢慢标定、求一个稳定的平均误差;头戴式设备如果标定太慢,用户早就不耐烦了;手机前置摄像头的距离一变化,瞳孔在图像里的尺度都会剧烈变化,同一个模型在不同距离下的表现可能天差地别。
2. 为什么性能评估框架这么重要
2.1 没有评估就没有优化
很多人会说“我的算法效果好”,但这个“好”到底是怎么定义出来的?是肉眼看了几个样本觉得准,还是跑了十个人的平均误差?如果连统一的评价标准都没有,你连自己的算法版本迭代都比不了,因为换一组受试者、改一个屏幕距离,误差波动可能比算法版本之间的差异还大。
我在做一个驾驶员注视区域识别项目的时候,一开始只统计了平均角度误差,结果发现算法在小角度注视区域(比如直视前方)表现很好,但在大角度侧视的时候误差明显放大。如果只看平均值,这个现象完全被掩盖了,也就没有动力去优化边缘视角。后来我在评估框架里加上了“按视角范围分桶统计”的维度,才看清楚问题出在训练数据里侧视角样本太少。可以说,评估框架决定了你能发现什么问题,而发现问题的能力决定了优化的方向。
2.2 性能评估框架由什么组成
一个完整的视线追踪性能评估框架,我认为至少包括四个部分:
- 数据采集协议:规定受试者坐姿、屏幕距离、环境光照、头部运动范围、标定点数量和顺序。
- 指标定义:明确用什么数学指标衡量精度,比如平均角度误差、标准偏差、鲁棒性百分位数。
- 数据处理流水线:包括去掉眨眼和异常样本的规则、坐标系的转换方法、时间戳对齐方式。
- 基线对比机制:要有统一的、公开的或内部的参考算法作为baseline,否则单看一个绝对值没有参照意义。
这四个部分缺一个,评估结果就容易被质疑。特别是基线对比这一点,很多团队内部评估的时候喜欢和自家上一版算法比,但完全不管和主流开源方案的差距,最后产品一上线,发现和竞品一比差距大得吓人。
2.3 评估框架和一次评测的区别
一次评测是“我现在测一次效果”,评估框架是“我随时都能测,而且测出来的结果可复现、可对比”。两者最大的区别在于标准化程度。
如果你只是临时写个脚本,让几个同事坐过来看一下屏幕上的标定点,然后算出均值,那这不是框架。框架要解决的是这些问题:换一个人做实验、换一台电脑、隔了三个月之后再跑同一套流程,结果是不是还一致?数据是不是还存在同一个位置、格式统一?指标计算的代码是不是同一个版本?只有这些都保持一致,才能把不同时间段、不同算法版本的结果放在一起横向比较。
我把评估框架比喻成一把固定的尺子。尺子如果每次都不一样长,你量出来的东西就没有任何可比性。很多团队不是算法不行,是尺子不行。
3. 核心指标拆解:准确度、精度、鲁棒性一个都不能少
3.1 准确度和精度:两个最容易混淆的概念
视线追踪领域最常用的两个词是Accuracy和Precision,中文经常都译成“精度”,但在评估时必须严格区分开。
准确度(Accuracy)是估计值和真实值之间的偏差,通常用平均角度误差(Mean Angular Error, MAE)来衡量,反映的是系统的系统性偏差。比如你让用户盯着屏幕正中心,算法输出平均偏向右上方5度,这就是典型的低准确度。
精度(Precision)是多次估计值彼此之间的离散程度,通常用标准偏差来衡量。如果用户盯着同一个点不动,算法输出一会偏左一会偏右、忽上忽下,离散度很大,那系统精度就差,人会感觉到注视点“发飘”。
放在视线追踪里,正确理解这两个指标的方式是:准确度高说明算法算得“准”,精度高说明算法算得“稳”。一个理想的系统应该既准又稳,但实际上很多系统的状态是“又准又抖”或者“稳定地偏”——后者往往更容易被忽视,因为平均误差数字看起来还行,实际使用体验却很糟糕。
我在评估一个头戴式眼动方案的时候,发现它的平均角度误差只有2度左右,远远满足需求。可实际戴上之后,用户反馈光标总在颤抖,后来一分析才发现,这2度的平均值其实是正负误差抵消之后的结果,标准偏差已经达到了1.8度,加上信号噪声,在视觉上就表现为毫无规律的抖动。从那之后,我看任何评估结果都会同时检查MAE和STD两个值。
3.2 鲁棒性:脱离场景谈精度没有意义
鲁棒性是视线追踪评估里最复杂、也最容易被忽略的维度。同一个模型,可能在全天均匀光照下误差只有1度,一到窗边侧光环境就变成5度;可能对不戴眼镜的人非常友好,戴上防蓝光眼镜后误差飙升。
衡量鲁棒性一般从几个维度切入:
- 光照变化:不同亮度、色温、光线方向下的误差分布。
- 头部姿态变化:正视、偏转、俯仰、侧倾情况下的表现,通常和视线角度耦合在一起。
- 用户个体差异:单双眼皮、瞳距、肤色、是否戴眼镜/美瞳、年龄导致的眼部纹理差异。
- 设备差异:同一算法在不同摄像头分辨率、帧率、镜头畸变下的表现。
要评估一个系统的鲁棒性,就不能只看单一条件下的平均误差,而要把这些条件拆开来,逐个变化、单独统计。比如固定光照、让受试者转头看固定目标点,衡量头部姿态的影响;固定头部位置、调节光源亮度,衡量光照的影响。这样每个因素的影响范围才能量化出来。
很多实际项目的验收指标只写了“平均误差小于某阈值”,这给算法实现者留了太多糊弄空间。如果验收标准里没有规定鲁棒性的测试条件,那实现者完全可以只在理想条件下调参,拿到一个好看的数字。
3.3 采样率、时延和中断率:系统级指标
除了看单帧的注视点误差,视线追踪是一个实时闭环系统,那么必须关注系统级的性能指标。
采样率决定时间分辨率,赫兹数越高,系统越能捕捉到快速的眼动变化。阅读场景下一般100Hz够用,但分析微扫视的话可能需要500Hz以上。
时延决定交互反馈的及时性。从用户眼睛真的看到某个位置,到系统输出注视点坐标,这个时间差就是端到端时延。对VR游戏这种强交互场景,时延超过50毫秒用户就可能感觉到“跟手性下降”,超过100毫秒体验会明显割裂。
中断率指单位时间内系统丢失眼部特征、无法输出有效注视点的比例。眨眼是天然中断,持续200-400毫秒,这是可以接受的;但如果因为头部运动、遮挡、光照剧烈变化导致频繁中断,用户的体验就会非常差。
这些系统级指标和前面的准确度、精度一样重要,但在实验室评估里经常被忽略。我建议评估框架里必须加入采样率和时延的统计,哪怕只是一个粗糙的平均时延值,也比完全没有强得多。
4. 怎么搭一套能落地的性能评估框架
4.1 环境搭建和打点设计
搭建一个视线追踪评估环境,核心是让测试条件可控制、可复现。我用过的方案是:一台显示器、一个固定位置的摄像头、一个固定距离的头托或者标记线,再加上一套自动播放标定点的脚本。
标定点数量取决于你要评估什么。如果你只是要一个总体平均误差,9点标定(3x3网格)基本够用;如果你想看不同视角区域的表现差异,最好用25点或者49点,把屏幕划分得更细。每个标定点出现时,让受试者先盯着它看,保证注视稳定200-300毫秒后再采集数据,避免眼球运动过程中产生的误差混入统计。
关键是要让受试者的头部保持相对固定。如果是桌面式摄像头方案,头部移动会在图像里造成瞳孔位置变化,这部分误差和算法本身的误差混在一起,很难隔离。我的做法是在屏幕上画一个大的半透明脸部轮廓框,让受试者自己摆正姿势,同时用头托固定眉心位置。这样测出来的误差才主要是算法和映射模型造成的。
4.2 角度误差的计算方式
视线追踪的误差计算有一个通用的度量单位——视角角度误差,因为视线追踪系统通常要适应不同的屏幕距离和屏幕尺寸。只报像素误差不方便统一比较。把像素误差换算成角度误差也很简单,前提是知道屏幕的物理尺寸、分辨率和用户的眼睛到屏幕的距离。
假设屏幕宽度是w厘米,分辨率为W像素,用户眼睛到屏幕的垂直距离是d厘米。某一点在屏幕上横向偏差了Δx_screen像素,那么对应的物理距离偏差是:
dx_cm = (w / W) * Δx_screen然后把这个横向偏差和纵向偏差合成为一个总的屏幕距离偏差:
d_cm = sqrt(dx_cm^2 + dy_cm^2)视线方向是从眼睛位置指向目标注视点,考虑斜视效应会把实际的空间距离系数略微放大或缩小,不过在屏幕尺寸不太大的情况下,可以简化处理,用眼睛到屏幕平面的垂直距离来计算角度:
angle_deg = arctan(d_cm / d) * 180 / π到这里,单个样本的误差就变成了一个角度值。把所有样本的角度误差求平均,得到的就是平均角度误差(MAE),计算所有样本角度误差的标准差,得到精度。
我在项目里通常会把这个计算逻辑封装成一个评估脚本,输入是每帧的算法输出坐标、对应的真实标定点坐标、屏幕尺寸和受试者距离,输出是MAE、STD、不同区域的误差热力图。
4.3 校准协议和样本筛选
校准协议对评估结果的影响非常大,必须提前定死。我的做法是:
- 采集开始前允许受试者做一次完整标定,标定点数与测试点数保持一致或者少于测试点数。
- 标定和测试使用不同的标定点位置,避免算法过拟合到标定网格上。
- 每个测试点采集多帧数据,去掉第一帧和最后一帧,避免受试者刚切换注视点时的眼动过渡段混入统计。
样本筛选是另一个容易出问题的环节。视线追踪数据里天然存在眨眼、眼睑下垂、视线移出屏幕等invalid样本。如果不过滤,这些噪声会把误差拉高;如果过滤得太狠,你又在挑选对自己有利的数据。
我的筛选规则非常简单且固定:瞳孔置信度低于阈值的帧直接丢弃;左右眼视线向量夹角过大的帧丢弃(大概率是两眼视线融合失败);单点采集时间内超过30%的帧被判定为无效,则该点数据整体重采或丢弃。这套规则定下来之后就不再改变,避免在对比不同算法版本时因为筛选标准不一致而产生不公平。
4.4 结果统计与复盘
评估跑完之后,我习惯打出一张“误差透视表”,按角度误差、双眼/单眼、头部姿态、屏幕位置、光照条件等维度统计平均值和分位数。重点看几个数:中位数误差、P90误差、P95误差,而不仅是平均值。
为什么要看P90和P95?因为平均误差低并不意味着体验好。如果一个系统90%的时间误差都在1度以内,但剩下10%误差飙到5度,平均下来可能只有1.5度,表面看着不错,实际使用中用户会时不时遇到光标乱跳,观感非常差。P90或者P95能反映出这种“尾部风险”。
我在每次算法迭代之后,都会把新旧两版算法在同一套评估框架下的MAE、STD、P90误差放在一张图里对比。哪一版更优、优势集中在什么条件区间、劣势在哪,一眼就能看清楚。
5. 常用数据集与基准:站在别人的肩膀上评估
5.1 三个绕不开的主流数据集
做视线追踪研究,很难绕开几个公开数据集。我自己用得最多的是下面这三个:
MPIIGaze是最经典的桌面式外观法数据集,包含15位受试者在三个月内日常环境下使用笔记本电脑的数据,光照和姿态都比较自然。它的特点是数据采集时间跨度长、个体内变化大,适合验证算法的跨时间稳定性,缺点是用网络摄像头拍的,分辨率不高,且没有真实验证视线角度标签,只有用标定板推算的近似值。
GazeCapture是目前规模比较大的移动视线追踪数据集,覆盖超过1450名受试者,用iPhone和iPad采集,包含大量真实使用场景。它的个体多样性很好,适合训练和验证设备无关的通用视线估计模型,缺点是受试者距离和屏幕相对角度不一致带来的噪声非常大。
ETH-XGaze是面向高精度视线估计的高分辨率数据集,包含110位受试者,数据是在受控的实验室环境下用高分辨率摄像头采集的,每个受试者都有多个摄像头视角和头部姿态。这个数据集的标签质量比较高,比较适合做三维视线向量回归的任务,缺点是环境光照相对单一,直接迁移到真实场景可能有掉点。
除了这三个,视线轨迹数据集、儿童眼动数据集等也各有用途,但如果你要搭一个评估框架做横向对比,MPIIGaze和ETH-XGaze是绕不开的标准benchmark。
5.2. 训练集和测试集怎么切才是公平的
这是很多人容易翻车的地方。视线追踪模型具有很强的个体相关性,同一个人的瞳孔特征、眼球形状、角膜曲率都有独特之处。如果你把同一个人的数据既放训练集又放测试集,模型看到的“人”在测试阶段已经见过了,评估结果会虚高到离谱。
我自己就踩过这个坑。第一次做数据划分时我用随机划分帧的方式,结果测试误差看起来只有0.8度,高兴坏了。后来改成按受试者划分,也就是同一人的所有数据只落在训练集或只落在测试集里,误差立刻涨到2.3度。这不是算法变差了,而是评估方式变公平了。
在数据集的实验设置里,“跨受试者”划分是主流标准,也就是测试集里出现的受试者在训练阶段完全不可见。更进一步,有研究者还会做“跨数据集”泛化测试,即模型在A数据集上训练、在B数据集上测试,用来验证模型的通用性。这种做法很残酷,但确实能暴露算法对训练集环境的过拟合程度。
5.3 实验室数据与现实场景的差距
就算你在MPIIGaze上跑出了SOTA结果,也不代表你的系统在实际场景里就一定好用。公开数据集的采集环境和真实部署环境有巨大的差异。
举个例子,公开数据集里受试者被要求注视屏幕上的标定点,行为模式相对“规矩”,头部很少有大范围快速运动。而真实场景中,用户可能一边走路一边看手机,屏幕在手里晃动,环境光线忽明忽暗,头部姿态变化幅度远大于数据集的分布范围。这些差异会导致模型在公开基准上表现优秀、在真实场景里翻车。
所以我在做产品级评估时,从来不会只依赖公开数据集的测试结果,而是一定会自建一套覆盖真实使用场景的小规模测试集。这个场景测试集的样本量不需要很大,但一定要包含真实设备、真实光照、真实用户行为。公开数据集的成绩用来对比学术方案,场景测试集的成绩用来判断产品能不能上线,两者缺一不可。
6. 实测中踩过的坑和排查思路
6.1 校准通过但测试一塌糊涂
这是最让人头疼的问题。用户按流程做完标定,屏幕上9个点标定完显示误差很好,但一到自由浏览状态,注视点就明显偏离。
我排查过不少次,最常找到的原因是:标定过程中受试者的头部位置和测试过程中不一致。标定时人坐得很正、脖子没歪,但进入自然浏览状态后身体不自觉往后靠、头部微微下低,哪怕偏移只有两三厘米,对于中长距离的屏幕注视估计来说,都会带来好几度的误差。
解决办法有两个方向:一是在算法层面引入头部位置补偿,把头部姿态和视线向量在统一坐标系里计算;二是在评估和产品设计中限制头部活动范围,或者加入“重新标定”的引导机制。后者实现成本低得多,很多消费级设备就是这么干的。
6.2 光照一变误差暴涨
外观法视线追踪对光照最敏感。我测过同一个模型,在均匀室内光下MAE是1.6度,拉开窗帘让侧面阳光照到脸上后,MAE直接跳到4度以上。原因很简单:光照变化会改变眼睛区域的纹理分布和阴影,模型提取到的特征发生偏移,而且瞳孔和虹膜的边界在强光下对比度下降。
应对办法无非几种:在训练阶段做大量光照增强,模拟不同光源方向;在部署阶段对图像做光照归一化预处理;或者直接用红外光源消除环境光干扰。具体选哪个取决于成本和精度需求,但评估框架里一定要把光照列为测试变量。
6.3 头一动就翻车
头部姿态变化带来的误差是视线追踪的经典难题。眼球运动范围总共就那么大,但头部转动带来的耦合效应非常复杂。很多模型在正脸时表现很好,头一偏就废。
为了定位是头部姿态估计的误差还是视线回归的误差,我的排查方法是把测试数据按头部偏航角分桶(比如每10度一档),分别统计每桶的误差。这样能精准定位问题出在哪个角度范围,然后针对性补数据或者改进特征融合方式。
6.4 时间戳不同步导致误差虚高
这个问题在实时系统里特别容易踩。摄像头画面上显示的坐标是某一时刻的位置,但视线算法输出的是另一个时刻的结果,如果你在评估时直接拿这两个时间去对,会因为延时导致系统性的空间偏差,尤其是在用户视线快速移动的时候,会看起来像是算法的误差变大了。
解决方法不复杂,但对齐逻辑必须在评估框架里写好:先让算法输出的每帧都带上输入图像的采集时间戳,在评估时用时间戳做线性插值或者最近邻匹配,把所有数据统一到同一个时间基准上。否则你测出来的“误差”里混着系统时延,算法本身改得再好,数据也对不上。
我刚做实时视线追踪时,就吃过这个亏。当时实测误差有2.5度,总找不到原因。后来把延时数据打出来,发现算法端到端延迟有120ms,其中图像采集和预处理占了将近一半。把时间戳对齐之后,扣掉时序偏差,算法本身的误差其实只有1.8度左右。从那之后我的评估脚本里永远都会先做时间同步,再做误差计算。
6.5 眨眼和部分遮挡的干扰
眨眼是视线追踪无法避免的生理现象。每次眨眼都会让眼睛在几十毫秒到两百毫秒内没有有效观测值,如果算法不及时丢掉这些帧,而是强行输出一个基于旧状态的估计值,误差就会非常大。
遮挡问题也一样。头戴式设备中,眼睑下垂、睫毛遮挡、镜框遮挡、美瞳导致的纹理变化,都会使模型提取不到有效特征。评估时如果把这些数据混进来,要么让误差虚高,要么掩盖了模型自身的真实问题。
我建议在评估框架里明确区分有效数据和无效数据,分别统计完整视线有效期的误差和系统失效时的恢复行为。前者反映算法的精度上限,后者反映系统的可用性,两者同样重要。
7. 我的一点实操心得
做视线追踪评估这几年,我最大的感悟是:评估框架不仅是一种检验手段,更是一种研发基础设施。它逼着你把“我的方案还不错”这种模糊感觉,变成“在光照A、姿态B、屏幕距离C的条件下,MAE是x度,P90是y度”这种清清楚楚的定量结论。
具体到实操,我有几个建议给正在做或准备做视线追踪的团队:
第一,评估框架要尽早搭建,不要等算法做完再补。我见过很多团队把评估拖到最后才做,结果发现数据集采集口径不统一、环境变量失控,整个测试数据作废重来。视线追踪的评估是一个受噪声影响很大的工作,只有当你用一套固定尺子反复量过之后,才会真正理解哪些误差是算法的、哪些是环境的、哪些是设备本身的。
第二,指标维度要“少而全”。少是指核心结论指标尽量少,可以聚焦在MAE、STD、P90、中断率这几个;全是指这些指标要在不同条件下分别统计,而不是只报一个总体平均值。我习惯用一张矩阵表,把光照、姿态、屏幕距离这几个变量排列组合,每一格填上对应的误差值,这样系统在什么条件下会崩,一眼就能看出来。
第三,重视无效数据统计。视线追踪系统不是每帧都能有效输出的, 无效数据比例直接决定了产品可用性。评估框架里一定要统计有效数据率、眨眼后恢复时间、头部运动中的中断频率,这些指标对于产品体验的影响一点也不比平均误差小。
最后再分享一个小技巧:定期用公开发布的主流模型当基线,把自家模型和它放到同一套评估流程里跑一遍。这样做一方面是真的能看出差距,另一方面在写论文或者对外汇报的时候,数据也更站得住脚。我自己的经验是,每次做这种对比都会发现一些平时没注意到的短板,然后用这些发现反推下一阶段的优化计划。
视线追踪的性能评估看起来是不那么“炫酷”的工作,但它决定了你的系统能不能从实验室走到真实场景。把评估框架搭扎实了,后面每一步优化才走得不心虚。