基于人脸关键点的收费亭微笑服务AI评测系统落地实践 前阵子接了个高速公路收费服务质检的项目客户开篇就问了一个让做视觉算法的人听了想皱眉的需求能不能用算法盯着收费亭判断每个收费员的微笑服务达不达标说实话我第一反应是这是不是有点大材小用。等项目真的推进到现场我才发现让AI走进收费亭、把微笑服务变成可量化的指标背后要处理的工程细节和人的问题比训练一个识别模型要复杂得多。这个项目最后做出来了一套完整的收费亭微笑服务AI评测系统覆盖了几十个收费站的车道。今天把整个落地过程里我认为最值得说的东西写下来从需求定义、微笑指标的计算、现场硬件部署到服务窗口期判断、考核打分校准一次性讲透。无论你是做计算机视觉的同行还是交通行业里想引入AI做服务管理的运营人员这篇内容应该都能给你一些参考。1. 收费亭里的微笑考核为什么最后绕不开算法1.1 人工抽检的困局先交代业务背景。高速公路收费站的服务考核里有一项规定叫微笑服务收费员在服务司乘的整个过程中要保持自然微笑配合唱收唱付、文明用语。看起来就是一句考核要求但真落下去执行问题非常多。过去怎么查稽查员在监控中心翻录像从每个车道一天的视频里随机抽几个时段人工看收费员有没有笑。有次甲方跟我们吐槽说一个中型收费站一天有五六千辆车通过每个收费员一个班次要服务两三百台车稽查组一个月能抽查几百个片段就算很勤快了覆盖率大约只有1%到2%。这带来两个直接后果一是抽样太少服务质量的真实波动根本没被看见二是判定标准太主观同一个微笑片段甲稽查觉得笑容自然、加分乙稽查认为嘴角僵硬、应付了事同一段视频打分能差出二十分。后来甲方内部也试过加强现场巡查让管理员在车道外来回走用巡逻代替视频抽检。结果更麻烦。收费员一看到管理员走近就条件反射地挂上标准笑容人一走笑容立刻消失。这种人来疯式的管理查到的只是表演不是常态。1.2 需求边界识别行为规范而不是识别心情我们项目组第一次开需求会时甲方给了个很宽泛的说法能不能让AI自动看收费员笑没笑第一版我们对需求的理解是做一个表情识别系统判断收费员是高兴还是不高兴。这个方向在技术上完全可以做但仔细一琢磨就走偏了。收费员微笑服务不是为了表达我现在心情很好而是在履行工作规范。所以算法要回答的问题不是收费员此刻情绪如何而是收费员在服务司乘的这个过程中有没有按照规范做出微笑表情动作。这个边界区分很重要。它决定了后续所有的技术选型。情绪识别模型关注的是面部表情与内在情绪的映射而我们要做的是行为合规检测更接近动作识别表情动作量化。说直白点就是判断这个表情动作够不够得上服务规范里的微笑标准而不是判断这个人笑得开不开心。边界一旦清晰后面和甲方沟通技术方案就顺畅多了。1.3 算法必须回答的三个问题整个需求梳理下来算法系统最终要回答三个问题某个时间段内画面里的收费员是谁这个收费员在服务哪一辆车服务窗口期是什么时候开始、什么时候结束在服务窗口期内收费员面对司乘的那些帧里微笑动作是否达到规范标准这三个问题分别对应人脸识别/跟踪、服务过程切分、微笑强度评估。看起来很直接但每个问题落到现场都会拉出一堆细节。比如第二个问题一辆ETC车从进车道到抬杆离开全程不过十几秒怎么判断开始服务和结束服务第三个问题里收费员低头找零钱、侧身拿计重单的时候脸都没对着司机这些帧该不该计入微笑评估这些都是必须想清楚再动手的事。有一点我特别想提醒做类似项目的同行别急着上模型先把考核场景里的业务规则摸清楚。算法只是最后执行规则的机器规则定义错了模型再准也是白搭。2. 把笑拆成大数68个关键点与微笑强度SM2.1 关键点从哪里来微笑在人类眼里是一个整体印象但计算机没有整体印象它只能看数字。我们要做的第一步就是把笑得怎么样翻译成一组可计算的数字。我当时选的技术路线是人脸关键点检测。人脸关键点就是面部关键位置的坐标点比如左嘴角、右嘴角、上唇中心、下唇中心、鼻尖、左右眼角等。常见的有68点、106点、240点等不同密度。考虑到收费亭内边缘设备算力有限我们选了在移动端优化较好的轻量级人脸关键点方案在画面上检测出人脸后输出68个关键点坐标。这套方案的好处有两个一是结构化关键点坐标直接描述嘴部、眼部的几何形状不需要像深度特征那样黑盒解释二是轻量单帧处理十几毫秒就能完成满足实时性。对甲方来说后续如果被质疑某个判断不合理可以拿出具体证据这一帧嘴角上扬角度是8度嘴部张开度0.3所以我们判定为微笑有据可查。这种可解释性在考核场景里非常重要。2.2 微笑强度SM怎么算关键点有了接下来要定义微笑强度。我把微笑拆成三个肉眼可见的物理特征嘴角上扬角度微笑时嘴角轮廓整体向上提左右嘴角连线与水平线的夹角会产生正增量。嘴部张开程度自然微笑时嘴巴会轻微张开上下唇之间出现距离。脸颊隆起位移微笑时脸颊肌肉向上挤压脸部两侧的关键点位置会相对中立状态发生位移。每一帧图像我们基于68个关键点坐标算这三个特征值。下面是当时计算微笑强度SMSmile Magnitude的核心逻辑import math # 假设landmarks为68个人脸关键点坐标索引按dlib/通用68点规范 # 左嘴角48、右嘴角54、上唇中心点51、下唇中心点57 left_mouth landmarks[48] right_mouth landmarks[54] upper_lip landmarks[51] lower_lip landmarks[57] # 1. 嘴角上扬角度左右嘴角连线相对水平线的角度 angle math.atan2(right_mouth.y - left_mouth.y, right_mouth.x - left_mouth.x) angle_norm max(0.0, min(1.0, (angle - (-0.1)) / (0.2 - (-0.1)))) # 2. 嘴部张开度上下唇中心点距离 / 两外眼角距离归一化 mouth_open dist(upper_lip, lower_lip) / dist(landmarks[36], landmarks[45]) # 3. 脸颊位移左右脸颊关键点相对基准帧的垂直位移均值 cheek_shift (abs(landmarks[2].y - cheek_baseline_left) abs(landmarks[14].y - cheek_baseline_right)) / 2.0 # 综合微笑强度权重来自标注数据回归 sm 0.3 * angle_norm 0.4 * mouth_open_norm 0.3 * cheek_norm这里面的权重不是拍脑袋定的。我们采集了两百多段真实收费亭服务视频切片后让六名标注员独立给每一帧的微笑可见度打分从0到5分。再拿三个特征值和标注分数做线性回归拟合出合适的权重系数和归一化区间。最终SM落在0到1之间数值越高微笑动作越明显。经过和人工标注的比对SM在0.55以上时大多数人都会认为确实在微笑。所以我们把0.55定成了微笑帧的判定阈值。2.3 为什么不用现成的情绪识别模型项目评审时有人问过网上开源的开心/难过分类模型不是现成的吗直接拿来用不行吗这里我多说几句。通用情绪识别模型大多是在实验室数据集上训练的输出的是七个情绪类别比如开心、悲伤、惊讶、愤怒。它对笑脸的判断往往是一个二分类结果这是笑脸或者不是笑脸。但我们这个场景恰恰不只需要是不是笑还需要笑得够不够到位。服务考核要的是连续幅度和持续时间不是零和一。另外通用模型一进监控场景效果立刻打折因为训练数据多是正脸高清照片而真实场景里有逆光、侧脸、遮挡、低分辨率模型置信度会乱跳。更关键的是可解释性。收费员如果被算法判了微笑不达标人家肯定要问凭什么。通用情绪识别模型只能给出一个黑盒深度的预测结果连开发人员都很难讲清楚是哪个特征导致了判断。而关键点方案能把嘴角上扬几度、嘴巴张开多少作为证据摆出来员工服气管理人员也好做绩效沟通。这里我个人的经验是凡是涉及对人的考核评价能不用黑盒模型就不要用哪怕准确率稍微低一点点可解释性带来的落地优势也远远大于那点精度提升。3. 走进现场才发现三个看不见的敌人3.1 摄像头装在哪三轮改动后的最终方案模型在办公室测试集上跑得很好一到现场全露馅。第一个问题就是摄像头部署。第一版方案参考常见监控布局把摄像头装在收费亭室内正中正对收费员的正面。装完一看画面收费员座位离摄像机两米多人脸在画面里只占巴掌大小关键点检测大面积失效。更要命的是收费员在亭内活动范围不小服务时经常向右转身面向司机脸一偏正面机位拍到的就剩下半张侧脸。第二轮我们改成了桌面近景机位把摄像头立在收费员操作台侧面距离人脸约60到80厘米这样人脸的像素宽度能做上去。但新问题来了操作台侧面会挡住部分收费员的视线而且收费员伸手接卡的动作经常把摄像机整个挡住。三轮方案最后定型是在收费亭窗沿上方装一个带可调角度支架的工业摄像头镜头下倾约15度和人脸水平面形成一个自然的俯拍角度距离约80厘米焦距6mm。这样画面里人脸宽度能稳定在80到120像素同时不遮挡收费员操作。关键点检测对正脸最敏感这个俯角也在检测网络能接受的范围。多说一句测试时一定要用亭内实际的光线条件多录几段不同时段的光照对关键点检测影响非常大。3.2 口罩与帽子当嘴部不可见时项目运行期间有一段时间收费站要求全员佩戴口罩。人脸检测模型能找到人脸框但68个关键点落到口罩区域时嘴巴部分的坐标完全是外推出来的置信度低到没法用。嘴部特征全部失效单靠脸颊位移也撑不起来整个微笑检测基本瘫了。我们的应对思路是切到眼部微笑识别模式。心理学里有一个概念叫杜兴微笑真笑的时候除了嘴角上扬眼轮匝肌也会收缩表现为下眼睑微微上抬、外眼角周围出现细纹。我们改用眼睛区域的关键点来计算眼部开合度和外眼角梯度强度用这两个量代替嘴部特征。具体做法是计算左右眼的EAR值眼睑纵横比真实微笑时眼裂会明显变窄EAR数值下降同时计算外眼角局部区域的梯度强度捕捉鱼尾纹的生成。切换之后检测率恢复到七成左右但精度确实比嘴部特征低。所以我们提高了口罩模式下的微笑判定阈值并且把这类眼部关联微笑的片段标记为待人工复核优先级较高不直接一刀切纳入考核。3.3 逆光、反光与白平衡收费亭最大的环境坑是窗玻璃。摄像头的物理位置在亭内镜头难免会拍到收费员身后的窗户白天外部阳光一照玻璃反光经常把脸部的对比度压得极低人脸暗成一团。晚上车灯扫过来有时还会短暂过曝。我们做了三件事。第一把摄像头安装位置从玻璃正面的直射路径上挪开同时加一个简单的遮光罩用物理手段削弱直接反光。第二开启摄像头的宽动态WDR模式出图时再做一次自适应直方图均衡把暗部细节拉出来。第三手动固定白平衡避免夜间路灯、车灯这种色温多变的场景让肤色发生漂移因为肤色漂移会影响关键点网络的置信度。这一套组合下来有效识别帧率从最初的76%提到了93%。剩下的7%主要是极端强逆光或者严重遮挡我们的处理原则是不硬判标记为数据不足交给人工复核。4. 关键不是笑没笑而是服务窗口期内笑没笑4.1 把一次收费服务切成状态机最早我们犯过一个技术洁癖式的错误拿着连续视频流逐帧分析脸部表情只要某一帧检测到收费员在笑就认为这一单服务微笑合格。跑了一周数据发现全站合格率惊人地高再一看结果逻辑上出了大问题——收费员在亭里坐着等车的时候跟同事聊天笑或者低头看手机傻笑这些帧也被算进去了根本不算服务过程中的微笑。于是我们把一次收费服务定义成一个状态机用外部信号而不是视觉信号来标记服务起止空闲状态车道无车不采集任何服务数据。车辆进入车道下方感应线圈触发或车牌识别系统上报来车状态切到服务中。服务结束抬杆信号触发且车辆驶离感应区域状态切回空闲。只有服务中这个状态下的视频帧才进入微笑检测流程。这个改动是整套系统逻辑里最关键的一次校正。算法要判断的不是这十分钟里你有没有笑过而是你服务这辆车的时候有没有保持微笑。4.2 朝向判断哪些帧算面向司机服务窗口期内的视频帧也不是全都有用。收费员在这个过程里要完成一系列动作迎接车辆时面向司机、确认车型时低头看屏幕、取卡时侧身、递票时面向司机、找零时低头数钱。如果我们把低头数钱那几帧的表情也算进微笑评价里算法就会一直报不合格因为低头时嘴角状态根本检测不到。所以我们在微笑检测前加了一层头部姿态估计计算头部在三个方向上的旋转角yaw、pitch、roll只有同时满足yaw角度小于25度、pitch角度小于15度的帧才被认定为面向司机的有效帧。这些有效帧里再计算微笑强度。低头数钱、侧身拿卡、转头看屏幕的帧会被过滤掉不进考核数据。这样既保证了考核的公平性也把误判率压了下来。4.3 单笔业务怎么打合格或不合格有了有效帧和微笑强度单笔服务的评价逻辑就清楚了。我们设定了一套三层规则单笔服务窗口时长不小于5秒才参与评价太短的车比如前车故障、即停即走不评退回人工处理。计算微笑帧占比有效帧中SM大于0.55的帧占比。单笔服务合格线是微笑帧占比不低于60%超过80%且平均微笑强度超过0.65判为优秀低于60%则判为不达标。举个例子收费员处理一笔现金缴费业务服务窗口15秒每秒抽5帧共75帧有效帧。其中面向司机的帧有60帧这60帧里有42帧微笑强度达标占比70%这笔业务就是合格。如果这位收费员全程板着脸有效帧90帧里只有18帧嘴角有上扬占比20%系统直接判不达标。这套评价口径是跟甲方运营部门反复对齐过才定下的。他们最初的期望是只要笑了就算合格我们建议必须在面向司机的有效帧里达到一定比例才算合格最终甲方接受了后者。现在回看这个是让系统真正能落地的一个关键决定。5. 实测中排掉的三个看起来不算Bug的Bug5.1 ETC车一进一出一次服务被重复计数系统在测试站跑了两个星期我们检查日报时发现一个奇怪现象ETC车道的服务数量远大于实际交通流量某些车牌一天的服务次数高得离谱。排查链路从输出倒推。先看原始记录发现一辆ETC车在90秒内被系统划分成了三段服务而现场实际情况是车辆在缴费后栏杆抬起慢车在车道内缓缓蠕动中间还因为前车排队停了几秒。我们的状态机把一次物理服务切成了多个逻辑服务导致同一笔服务被重复评价且每段都不足5秒大量进入无法评估人工复核队列把人工复核量直接抬高了四倍。修复方案是给状态机增加冷却时间机制一次服务结束后60秒内不允许开启新的服务状态同时以车牌识别结果为主键同一车牌在同一车道的服务记录合并成一个会话。MOT视觉跟踪在这个场景里反而不是最可靠的主解因为车道拥堵时前车后车挤在一起跟踪ID很容易互换。5.2 低头、侧身、歪头长尾姿态带来的假阳性第二阶段测试里出现了另一类问题明明是低头缴费的侧脸帧算法却报成了微笑正在发生。我翻出误报截图仔细看原因很清晰——收费员低头时下颌线的弧度被关键点网络当成了嘴角上扬线嘴部特征值出现了一个假峰值。这个坑属于典型的模型外推误差。我们的姿态过滤确实挡掉了一部分大角度歪头但阈值的边界附近仍然有漏网之鱼。最终处理是双管齐下第一把姿态估计的前置条件从过滤后统计改成过滤后再检测凡是yaw或pitch超quote角的帧不参与关键点检测直接从源头上掐掉第二提高关键点检测的置信度阈值从0.7提到0.8。宁可少报一些微笑也不乱扣分。调整后假阳性率从8.7%降到2.1%。5.3 嘴在笑眼不笑被算法放过的职业假笑系统上线一个月后运营方跟我们反馈了一个很有意思的现象有些收费员发现算法看嘴部特征开始练嘴角上扬的肌肉记忆嘴上扬起标准弧度但眼睛没有任何笑意。人工看录像怎么看怎么别扭可算法却给了满分。这就是经典的假笑问题。解决办法是引入眼轮匝肌活跃度判断也就是前面口罩方案里用到的眼部特征。具体逻辑调整为一帧只有同时满足嘴部SM达标和眼部活跃度达标才记为真微笑帧光嘴角动、眼睛没反应标记为疑似机械微笑等级不纳入微笑帧占比。这个调整以后有个收费员私下跟我说以前对着镜子练嘴角弧度就够了现在得真的发自内心笑一笑不然眼睛那关过不去。这话虽然是玩笑但恰好说明指标设计在引导真实行为改变。5.4 怎么防模型自己退化只要系统在跑模型静默退化就会存在。起初我们整个项目组也没把这件事放在重点位直到有一天日报显示全站微笑达标率骤降20%。我们当时第一个反应是站点服务质量出了问题准备打电话跟站长沟通。结果多看了一眼数据分布发现所有收费亭、所有车道、所有班次全部同步下跌这就不是人的问题——再集体性的服务质量滑坡也不可能全站同时发生。查了当天硬件状态发现是因为连续阴雨天亭内光线整体偏暗摄像头自动增益把画面噪点放大了关键点检测稳定性下降SM普遍低估。从那以后我们建立了一套日监测机制每天统计各车道的SM分布、微笑帧占比、关键点置信度均值一旦全站指标出现超过15%的同步波动就会触发模型校准流程而不是直接怀疑收费员偷懒。这个先怀疑系统再怀疑人的排查顺序做AI质检项目一定要刻在脑子里。6. 算法分数要变成考核分数中间还有两道手续6.1 人工分与算法分的回归标定算法输出的达标、不达标、优秀三级评价要直接写进收费员的绩效表必须跟原有的考核体系对接。原来的考核表里微笑服务占总分100分里的20分。我们采用的方式不是让算法直接打20分而是让算法先算出一个基础服务得分再用人工复核结果做校准。单笔服务得分公式设为S 12 8 × (0.6 × 平均微笑强度 0.4 × 微笑帧占比)。举个例子某收费员一笔业务平均微笑强度0.7、微笑帧占比0.9这笔业务的得分就是12 8 × (0.42 0.36) 18.24分。为了让这个公式和人工评价对齐我们做了300段真实服务片段的回归标定六名业务专家先独立打分再和我们公式计算的分数做相关性分析最终线性相关系数控制在0.8以上甲方认可后这个公式才进入正式考核流程。这一步看起来是数据分析工作但实际决定了系统能不能被业务方接受——考核规则一旦出现算法说A、专家说B的对立整个系统的公信力就垮了。6.2 假阳性与假阴性输出不确定也是一种处理实测过程中算法误差不可避免关键是想清楚怎么处理误差。常见两类情况第一类是假阳性算法判定合格人工复核时看着不舒服。典型场景就是前面说的职业假笑。虽然我们加了眼部判断但仍然存在边界情况。我们的处理方式是给这类样本打上疑似机械微笑标签不直接判不合格而是推送给管理端人工复核由站长或稽查员二次确认。第二类是假阴性算法判不达标人工看视频发现收费员确实也在笑只是角度偏、遮挡算法没敢认。针对这种情况我们规定凡是有效帧少于15帧的服务会话算法不输出不达标只输出数据不足需人工复核同时把原始脱敏视频片段附在后面。加了一个无法评估分类后系统的整体争议率大幅下降。这个经验分享给做场景化AI落地的同学三分类的不确定永远好过二分类的硬判。6.3 申诉入口与数据留存给一线员工留退路最后一点是制度设计不是技术问题但对系统能否平稳运行影响极大。确定考核口径时我们坚持加了两条规则一是收费员对当天考核结果有异议时可以在后台系统发起申诉申诉后提取该服务会话的脱敏录像特征和关键点数据转到人工复核队列由值班站长做最终裁决二是所有用于考核的原始视频流只保存90天存储层做脸部区域的脱敏处理核查结束后自动清理。这个申诉入口刚开始被甲方认为是多此一举但实际运行后发现它极大缓解了一线员工的对抗情绪。收费员每天看到自己某笔业务被判不达标第一反应不是反思而是我不服。有了申诉路径情绪就有了出口。一个技术项目落到人的管理场景里光追求算法精度是不够的还得给制度留出呼吸空间。项目收尾的时候我回看最初那个能不能用算法看收费员笑没笑的需求觉得最后交付的其实不只是一套算法系统而是一整套把微笑服务从主观印象变成客观数据流程的机制。算法给每个人都做了一把统一的尺子但这把尺子不能抖得让人看得懂、够得着、有地方说理。我最大的体会是AI进收费亭最难的不是让机器学会看懂微笑而是让被看的人接受机器是一个不带偏见的监督者。我们项目组最后很欣慰的一点是这套系统成了收费员愿意开的玩意儿——他们每天上班第一件事是瞥一眼屏幕上的达标率变化慢慢有人在窗口比谁的笑更自然了。算法当然不会心情不好也不偏袒谁这是它比人强的地方。但真正让系统跑下去的永远是背后那些愿意接受它、甚至愿意跟它较劲的一线员工。