
最近一直在折腾人脸认证这边的东西刷到了一个叫 PLFM_RADAR 的活体检测项目顺手就拿真实业务场景测了一轮。先说结论这东西的思路和人脸反欺诈里经典的“雷达扫描式多维判活”逻辑很贴合不是那种拿一张静态图就硬分类的玩具方案。如果你是做金融开户、门禁考勤、线上实名认证的或者正在被“照片攻击”“视频回放攻击”折磨那这个项目值得花点时间看看。这篇文章我会把它的核心设计逻辑、关键实现细节、完整跑通流程以及我在实际部署中踩过的坑一次性讲清楚。1. 项目定位PLFM_RADAR 到底解决什么问题1.1 先拆一下名字PLFM 和 RADAR 分别指什么项目名叫 PLFM_RADAR拆开看其实是两个部分。PLFM 大概率是 “Platform” 的缩写表示这是一个面向平台侧、可以嵌入现有业务系统的工程化方案RADAR 则表达的是核心思路——“像雷达扫描一样”对目标人脸做多维度、多帧、多模态的信号采集和研判而不是只取某一帧做一次性判断。这个命名的含义挺准确的实际跑下来它确实不是“输入一张图输出一个活体分数”那么单薄而是组合了光学成像特征、时序动作特征、微纹理噪声分析等多个信号源再融合打分。活体检测这个方向的痛点其实不在于“能不能识别人脸”而在于“能不能识别出那张人脸是不是真的”。现在网上随便一搜高清照片、硅胶面具、屏幕翻录视频成本低到离谱。单靠人脸检测或者人脸比对根本抵挡不住这种攻击。PLFM_RADAR 解决的就是“如何在摄像头对面的是一个真实的人而不是一张图、一段视频、一个面具”这个核心问题。1.2 为什么业务方需要单独一套活体检测很多刚接触这块的同学会问人脸识别都做得挺准了为什么还要额外搞活体检测这里有个容易混淆的点。人脸识别解决的是“你是不是张三”活体检测解决的是“摄像头前面是不是一个真人”。这两个是串联关系不是替代关系。比如远程银行开户系统先做活体检测确认镜头前是个真人然后才做身份证和人脸的 1:1 比对确认这个真人就是身份证上的那个人。如果活体这关失守后面的比对做得再准也没意义因为攻击者可以直接拿一张受害者的照片怼到镜头前。我在实际项目里见过一个挺典型的场景某线上贷款产品的实名认证环节攻击者用另外一台手机播放受害者的视频对着镜头晃了几下居然就通过了当时的静态照片审核。原因就是检测逻辑太单一只看了“画面里有没有脸”没判断“这张脸是不是有真实深度和活体纹理”。PLFM_RADAR 这类方案要解决的正是这个环节的漏洞。1.3 它适合哪些业务场景和开发者从我实测的感受来看PLFM_RADAR 的定位比较偏向“可二次开发的工程参考”不是那种下载即用的黑盒 SDK。适合的人群有这么几类业务研发同学公司要做实名认证、风控审核需要一个能看懂原理、能改参数、能接进现有服务的活体检测方案PLFM_RADAR 提供了完整的思路和基础代码而不是只有一个 API 接口。算法工程师想研究活体检测的特征融合、分数阈值调整、攻击样本对抗这个项目的代码结构比较清晰方便做消融实验。安全风控从业者想了解当前主流的人脸攻击手段有哪些、反制手段是什么看这个项目的特征设计就能摸清门道。当然它也有一些天然的短板比如对硬件摄像头质量有一定要求、需要用户配合做指定动作或者保持特定姿态这些我后面在“坑”的部分会重点讲。2. 核心技术拆解多维度“雷达扫描”式判活2.1 特征一人脸的微纹理与噪声分析PLFM_RADAR 的第一个核心信号源是分析人脸区域的微纹理差异。这里用到了一个在很多老牌活体检测方案里都会出现的经典理论真实皮肤在成像时会呈现出特定的纹理细节比如毛孔、细小皱纹、皮沟皮丘而这些细节在照片或者屏幕翻拍里会因为二次成像而丢失或改变。具体到实现上它会把人脸区域裁切出来转成灰度图然后做高频成分提取。你可以把它理解成把图片放大很多倍之后观察“颗粒感”。真实皮肤的高频纹理是有机且不规则的而打印照片会有明显的网点阵列或墨点噪声屏幕翻拍则会有摩尔纹和像素栅格。PLFM_RADAR 会计算这些高频成分的分布特征比如纹理能量、方向梯度直方图然后量化成一个“纹理真实性”指标。这个原理听起来简单但落地的时候有几个坑。比如光线不好时真实皮肤也可能因为噪点过多被判成“假”所以项目里一般不会只凭单一纹理分数做决策而是把它作为一维输入送进融合分类器。另外不同手机的摄像头 ISP图像信号处理器风格差异很大有的手机自带强力美颜磨皮磨得毛孔都没了这会让纹理特征失效。PLFM_RADAR 的做法是在预处理环节加了一个自适应的锐化与增强步骤尽量把皮肤纹理信号拉回来。实测下来在开启中等程度美颜的安卓机上纹理维度依然能提供有效区分度但如果开“重度美颜”模式就需要靠其他维度来兜底了。2.2 特征二时序动作指令的验证只靠纹理是不够的因为现在的高清打印照片配合一些后处理可以模拟出一定的纹理效果。所以 PLFM_RADAR 引入了第二个维度——时序动作验证这也是它“雷达扫描”说的由来之一在用户认证过程中系统会随机下发一个动作指令比如“请眨眨眼”“请缓慢张嘴”“请左右转头”然后通过分析连续帧中的人脸关键点变化来判断用户是否真的在配合指令做动作。这里面有个关键设计动作指令必须是随机的。如果每次都是“眨眨眼”攻击者完全可以用提前录好的视频来绕过。PLFM_RADAR 里维护了一组动作指令库每次认证时从库里随机抽取一到两个动作顺序也随机。同时还会校验动作的顺序是否匹配、持续时间是否合理。比如要求“先眨眼再张嘴”如果视频里动作顺序反了就会被判定为可疑。时序验证的实现细节在代码里主要体现在两个地方一是人脸关键点追踪二是动作状态机。关键点追踪用的是 68 点或者 106 点的人脸关键点模型实时计算眼睛纵横比EAR、嘴巴纵横比MAR和头部姿态角Pitch/Yaw/Roll。EAR 和 MAR 的计算其实很简单就是取眼睛或嘴巴周围几组关键点的欧氏距离比值设定一个阈值来判断“眼睛是否闭合”“嘴巴是否张开”。头部姿态角的估计稍微复杂一点需要用到 3D 人脸模型和 PnP 求解。不过 PLFM_RADAR 里已经封装好了直接调用接口就行。动作状态机的逻辑是核心它会记录每一帧的动作状态空闲/眨眼/张嘴/转头然后按照预设的动作序列做匹配。如果状态跳变不符合预期比如没检测到“闭眼”就直接检测到“睁眼”就会产生一个动作异常标记。2.3 特征三深度与反光等光学信号第三类特征来源于真实人脸的物理光学特性。最典型的就是近红外深度信息不过这个依赖专用硬件普通 RGB 摄像头拿不到。PLFM_RADAR 在只使用普通 RGB 摄像头的前提下走了两条替代路线。一条是分析屏幕反光。当用户面对屏幕时真实人脸会因为屏幕光照产生微弱的镜面反射而照片或者平板翻拍的人脸反射特征是不一样的。具体来说真实人脸的鼻尖、额头、颧骨这些凸起区域的反射高光位置会随姿态微动而变化而平面打印照片的反射是整体的、不随姿态变化的。另一条是分析背景与前景的立体差异。真实人脸会有自然的边缘虚化景深边缘过渡是渐变的而照片翻拍通常会出现明显的纸边、屏幕边框或亮度跳变。PLFM_RADAR 会做一个前景分割然后把边缘区域的梯度变化特征也送入分类器。这些光学信号算是对前两个维度的重要补充尤其在攻击者用高质量面具的情况下微纹理和动作可能都能伪装但光学反射特性短期还很难完美模拟。2.4 特征融合与活体分数计算多维特征收集完之后PLFM_RADAR 没有简单地把它们相加取平均而是训练了一个融合分类器一般是梯度提升树或者多层感知机输入是所有维度的特征向量输出是一个 0 到 1 之间的活体置信度分数。这种做法的好处是可以通过训练样本自动学习每个维度的可信程度和相互关系。比如在光线很差的场景下纹理特征的置信度会下降但动作特征的稳定性还好在动作配合不到位的情况下动作特征会拉响警报但光学特征如果一切正常则可能是用户不熟练而不是攻击。融合模型会综合这些关系给出一个更合理的判断。关于阈值这是我在实际部署中特别留意的地方。模型输出的分数是连续的如何定阈值需要结合业务容忍度。如果你做的是高风险转账业务阈值要拉到 0.85 以上宁可误杀一部分真实用户也要减少漏网之鱼如果是门禁考勤这种低风险场景0.65 就可以用户体验优先。PLFM_RADAR 默认给的是 0.75但我建议业务方一定要拿自己的真实数据重新校准阈值不要迷信默认值。3. 实操部署跑通 PLFM_RADAR 的完整流程3.1 环境准备PLFM_RADAR 的运行环境不复杂但有两个版本需要注意推理版和训练版。如果你只是想在业务里集成只需要推理版环境依赖很少如果想在自己数据集上微调模型就需要搭完整的训练环境。基础依赖就那么几件Python 3.8PyTorch 1.9 以上OpenCV 4.x再加上 dlib关键点检测用或者项目自带的 PFLD 关键点模型。建议在 Linux 环境上跑Windows 上编 dlib 虽然也能跑通但有些编译坑比较折腾。显卡方面推理的话 GTX 1060 以上的 GPU 就足够了纯 CPU 跑也能跑但速度会慢不少一帧一帧地分析大概只有 6~8 FPS实时性受影响。提示装 dlib 之前先把 cmake 和 boost 装好不然编译会报错。如果实在不想碰 dlib可以换用项目里预留的 PFLD 分支纯 PyTorch 实现还省去一堆编译时间。3.2 主流程从视频帧输入到活体判决整个推理流程基本是一个标准管线取帧 → 人脸检测 → 关键点定位 → 分维度特征提取 → 特征拼接 → 融合分类 → 输出判决。第一步是取帧。PLFM_RADAR 默认支持接入摄像头实时流和离线视频文件两种方式。接摄像头的时候我建议自己加一个帧率控制不要每帧都跑全流程取 10~15 FPS 就够了。因为动作验证需要连续性帧率太高除了浪费算力没有太多收益太低则可能丢失关键动作瞬间。第二步是人脸检测默认用的是 RetinaFace 或者轻量级的 SCRFD。检测到人脸之后会先做个预判人脸框大小是否满足最小尺寸要求人脸角度是否太大如果人脸太远或角度太偏会直接提示用户“请靠近一点”或者“请正对屏幕”而不是继续跑后面的流程这样能省不少无效计算。第三步是关键点定位。人脸关键点模型会输出双眼、嘴巴、鼻子、轮廓等关键点坐标。PLFM_RADAR 在关键点基础上会进一步计算人脸的 6 自由姿态头部三维角度用于动作验证的转头检测。这里我建议在接入业务前先做一次关键点模型的“烟囱测试”让测试用户在纯色背景、柔和灯光下做正脸、左右转头、仰头、低头各拍几帧看看关键点是否稳定。如果某些角度下关键点抖动明显说明模型在你当前摄像头条件下不够稳需要换更高质量的关键点模型否则后续的姿态判断会非常不稳。第四步是分维度特征提取。纹理特征模块会对人脸区域做高频滤波提取纹理统计特征动作特征模块按时间窗口保存关键点和姿态数据在动作序列结束时统一计算光学特征模块则分析人脸边缘梯度和反光分布。这三个模块相互独立可以并行计算实测在 GPU 上三个模块单帧总耗时大概 15~20msCPU 会慢到 60~80ms。第五步就是特征拼接和融合打分。这三个维度的特征会统一转成向量有的维度是几十维有的是几百维拼接后输入融合分类器。分类器输出的活体分数会跟阈值做比较大于阈值则判定为“活体通过”否则进入人工复核或者直接拒绝。3.3 关键参数的选择逻辑跑通主流程之后有几个参数需要你根据实际场景调整。第一个是最小动作时长PLFM_RADAR 默认要求每个动作持续 0.5 秒以上才算有效。这个值要结合用户群体调整如果是给老年人做认证动作慢0.5 秒可能不够建议放到 0.8 秒如果是给年轻用户做高频次的高强度验证0.4 秒就够了太长的动作时长会明显拖慢整体认证体验。第二个是动作容错帧数。项目里默认是在连续 10 帧里允许有 2 帧异常超过就判定动作不合格。这个值的幅度会影响误杀率特别是摄像头帧率不稳定的时候稍微卡顿一下就容易连续掉帧。我自己的经验是把容错帧数放宽到 3 帧误报会少很多只要攻击检测的其他维度还在放一点点容错不会对安全性有太大影响。第三个是活体阈值刚才已经说过务必要用真实场景数据校准。这里给一个参考做法拿过去一周正常用户的认证视频做负样本全部应该是活体通过再拿公开攻击数据集或者内部红队拍的攻击视频做正样本全部应该是攻击画 ROC 曲线取等错误率点或者业务可接受的误杀点作为阈值。3.4 与业务系统的对接方式PLFM_RADAR 不是一个完整的服务更像是一个算法核心所以和业务系统对接的时候需要自己搭一层胶水服务。常规做法是封装成一个 gRPC 或者 HTTP 接口输入一段视频或者一个视频流地址输出包含活体分数、各维度子分数、动作验证结果和具体异常码的结构化结果。我建议输出不要只给一个“通过/不通过”最好把子分数也吐出来。比如纹理分数只有 0.4但动作和光学分数正常这个用户可能是手机开了重度美颜如果纹理和光学分数都正常但动作分数异常那大概率是用户不配合而非攻击。有了子分数风控系统可以做更细的规则比如“动作分数异常但其他正常 → 进入人工复核”而不是直接拒绝。对接工程量不大但有一个坑很容易踩视频格式兼容性。PLFM_RADAR 默认对输入视频要求是 MP4 编码或者原始 RGB 帧流。业务端如果是 H5 页面录出来的视频有时候是 WebM 格式底层的 OpenCV 解码不一定识别。建议在网关层统一做一次视频转码全部转成 H.264 的 MP4再送进活体检测服务能省掉很多莫名其妙的 bug。4. 常见问题与排查技巧实录4.1 昏暗环境下误杀率飙升这是我在测试中遇到的第一个大问题。光线不足时摄像头会自动拉高 ISO画面噪点显著增加纹理特征模块会把噪点误判为“不真实的纹理”导致真实用户被判定为攻击。排查方式很简单把测试环境的亮度从 300 lux 往下调每档亮度跑一组真实用户和打印照片攻击观察纹理子分数的分布变化。如果纹理分数随亮度下降而明显下滑说明当前阈值的鲁棒性不足。解决办法有几个方向。第一在预处理阶段加一个亮度自适应判断如果人脸区域的平均亮度低于阈值就提高融合分类器里动作和光学特征的权重降低纹理特征的权重。第二提示用户调整环境光或者开启屏幕补光这个体验略差但效果最直接。第三用低光照下的真实用户数据重新微调融合模型让模型自己学会在低质量纹理特征下怎么结合其他特征做判断。注意不要为了防照片攻击把纹理特征权重调得特别高那样会放大环境对误杀率的影响真实用户会骂娘的。4.2 美颜滤镜导致纹理特征失真另一个高频问题是手机美颜。现在的手机相机默认都会做磨皮轻则抹掉毛孔细节重则直接让皮肤看起来像塑料。PLFM_RADAR 的纹理特征在重度美颜下基本会失效纹理子分数会掉到和打印照片差不多的水平。这个问题的排查可以通过对比实验确认找几台不同品牌的手机分别开启美颜和关闭美颜对同一个真人录制视频看纹理分数的差异。如果关闭美颜时纹理分数正常、开启后掉得很厉害那基本可以实锤是香氛美颜干扰。应对策略有两个层面。产品层面在认证页面提示用户关闭美颜技术层面可以考虑用频域特征替代部分空间纹理特征因为美颜处理对低频信息影响较小真实人脸的频域能量分布仍然有可辨识的特征。PLFM_RADAR 在后期版本里也加入了频域特征分支但我实测下来最稳妥的还是在业务侧做一次美颜检测检测到深度磨皮痕迹后直接要求用户关闭滤镜再认证。4.3 动作验证阶段用户配合度低动作验证是误杀率的大头。很多人不理解“请眨眨眼”为什么要眨眼三次或者动作太快一闪而过系统还没捕捉到就直接判定失败。PLFM_RADAR 的动作状态机对动作的“完成度”比较敏感如果用户动作幅度太小、速度太快很容易触发动作异常。排查方法是在测试集里统计各动作类型的失败率。如果“眨眼”失败率明显高于“张嘴”说明当前摄像头帧率或者模型对细小动作不敏感。这时候要么提高关键点模型的精度要么在动作判定逻辑里增加放大系数。我在项目里选择了一个轻量做法在要求动作时界面动态显示动作示范动画同时实时指示“当前检测到眨眼进度 60%”用户能看到自己的状态配合度会显著上升误杀率能降一半以上。还有就是动作顺序。有些用户看到指令后会紧张把“先眨眼再张嘴”做成了“张嘴再眨眼”。如果业务上可以接受建议对顺序做一定的容错只要两个动作都出现了顺序反了也判通过如果必须验证顺序那就需要在引导界面上把顺序强调得很明确不能只有一个纯文字提示。4.4 高质量面具和 3D 打印模型的攻击前三个问题大都是误杀第四个问题是真正的安全性挑战。市面上已经出现高仿真的硅胶面具纹理、人脸关键点都没问题动作也能模仿。PLFM_RADAR 单纯靠纹理和动作特征面对这种攻击会很吃力。我实测过类似道具发现最后的防线往往在光学特征。面具和真脸在反光特性、边缘过渡上依然有差异尤其是额头和颧骨的镜面反射强度分布不同。PLFM_RADAR 光学特征模块里的边缘梯度分析和反光一致性校验在这种场景下比纹理和动作更可靠。如果你要对抗这种高等级攻击建议做两件事一是增加随机交互指令比如随机让用户展示某个侧脸角度面具难以瞬间切换二是接入多光谱或者近红外摄像头这是目前对抗面具攻击最硬的手段。当然这些要增加硬件成本需要根据业务风险级别来权衡。4.5 快速问题速查表为了让你排查时更方便我把上面提到的问题整理成了一个速查表标注了最常见的直接原因和最快的解决动作。现象最可能的原因排查方式快速解决真人在昏暗环境被拒纹理特征受噪声干扰调整亮度测试纹理分数变化低亮度时降低纹理权重用动作/光学特征兜底真人开美颜被拒磨皮抹掉皮肤纹理开关美颜对比测试业务侧提示关闭美颜或引入频域特征分支用户眨了几下眼仍失败动作幅度小、帧率低、状态机误判统计各动作失败率加动作动画引导放宽容错帧数照片能通过检测阈值过低或纹理权重不足用攻击集做验证拉高阈值校准融合模型权重视频回放能通过检测动作时序未校验或光学特征未生效检查动作序列日志开启随机动作指令加强边缘梯度违例检测4.6 一个容易被忽略的细节日志与可回溯性最后分享一个我踩过坑后才补上的经验——活体检测必须留足日志。业务上线后如果你的风控模型出了问题想复盘某个用户为什么被拒或者某个攻击为什么绕过了检测没有日志你根本无从下手。PLFM_RADAR 推理时要把每一帧的人脸框坐标、关键点置信度、各维度特征分数、融合分数、动作状态变化全部记录下来。这不是为了调试而是为了后续的取证和模型迭代。尤其是被判定为“攻击”的样本最好把原始视频片段保存一份设定合理的保留周期。这既是安全合规的要求也是持续优化检测能力的样本来源。另外日志格式要结构化方便做统计。我自己会额外落一张宽表每一行是一次认证请求字段包括各维度特征分数、动作结果、阈值、最后判决、耗时。有了这张表后续做阈值调整或者模型版本对比就非常方便不用再翻原始日志。结尾跑了这么一圈PLFM_RADAR 给我的整体感觉是它把活体检测这个看似单一的问题拆成了纹理、时序、光学三个可以独立理解、独立调优的维度而且整个代码结构比较干净适合拿来学习也适合拿来二次开发。我在实际部署中最大的体会是活体检测不是一个“模型调好就完事”的模块它在业务里的表现高度依赖摄像头质量、用户配合度、环境光线这些外围因素所以上线前一定要拿自己的真实设备、真实用户、真实攻击样本来做充分测试阈值和容错参数也要针对性调整。最后再提一句日志和子分数可回溯能力一定不要省它们会在后续迭代里帮你省下大量排查问题的时间。