安防通行场景下的人脸抓拍识别,说白了就是把"摄像头画面里出现的人脸"这件事,变成"一条带时间戳、带特征值、可被检索的结构化记录"。听起来简单,但真正落地过的人都知道,从RTSP拉流到最终1:N比对出结果,中间任何一个环节没处理好,轻则识别率上不去,重则整个通道卡死、内存爆掉。我前后做过几个园区和写字楼的通行项目,踩过的坑足够写一本小册子,这里把整套链路拆开讲清楚,包括选型逻辑、参数计算、实测数据和那些文档里不会写的经验。
这篇文章适合谁看:正在做或准备做人脸抓拍识别项目的开发、集成商技术负责人,以及想搞清楚"抓拍"和"识别"到底差在哪的工程人员。我会从整体架构讲到每个模块的具体实现,重点放在"为什么这么选"和"实际会出什么问题"上,而不是罗列API文档。
1. 先搞清楚抓拍与识别的边界在哪里
很多人一上来就把"人脸抓拍"和"人脸识别"混为一谈,结果方案设计阶段就埋了雷。这两个环节在系统里承担的责任完全不同,对硬件和算法的要求也不一样,必须分开设计。
1.1 抓拍解决的是"有没有脸、脸够不够好"
抓拍的核心任务是从连续视频流中检测出人脸目标,并筛选出质量最高的那一帧保存下来。它关心的是:画面里有没有人脸、人脸尺寸够不够大、角度偏不偏、清不清晰、有没有被遮挡。抓拍环节通常跑的是人脸检测模型(比如RetinaFace、SCRFD这类),输出的是人脸框坐标和关键点。
抓拍的质量直接决定了后续识别的上限。我见过太多项目,识别率死活上不去,排查半天发现是抓拍阶段选出来的图就是糊的、侧脸的、或者只有半张脸。这时候再牛的识别算法也救不回来。所以抓拍阶段一定要有质量分筛选机制,不能检测到就存。
1.2 识别解决的是"这张脸是谁"
识别环节拿到抓拍输出的高质量人脸图之后,先做人脸对齐(根据关键点把脸摆正),再提取特征向量,最后和底库里的特征做比对。1:N识别就是拿一张人脸去和底库里N个人比对,找出最相似的那个。这里常用的就是ArcFace这类度量学习模型,输出512维或更高维的特征向量,用余弦相似度衡量。
关键点在于:抓拍和识别可以部署在同一台设备上,也可以分离。小规模场景(比如单门禁)通常一体化设备搞定;但如果是多路摄像头汇聚到中心做比对,就必须分离,抓拍在前端或边缘,识别在中心服务器。
1.3 通行场景对两者的特殊要求
安防通行和普通的人脸考勤不一样,它对实时性和通过率要求极高。一个人走到闸机前,从进入画面到闸机开门,理想情况要在300到500毫秒内完成整个"抓拍-识别-决策"链路。这就要求抓拍要快、识别要快、底库检索要快。
另外通行场景的人脸是"主动配合"的——人会正对摄像头、会停下来,这比那种在人群中随机抓拍要友好得多。但反过来,通行场景对误识率(把A认成B)几乎是零容忍,因为放错人进门是安全事故。所以阈值设置上,宁可拒识(让人再刷一次),也不能误识。
2. RTSP拉流:整条链路最容易翻车的地方
视频流是整个人脸抓拍系统的输入源,而RTSP是安防摄像头最通用的取流协议。这一环看起来只是"连上摄像头拿画面",实际上坑最多,尤其是多路并发和长时间运行的稳定性问题。
2.1 RTSP取流的基本流程与常见地址格式
RTSP本身是个控制协议,真正的视频数据是通过RTP传输的。一次完整的取流大致是:客户端发DESCRIBE请求获取媒体描述(SDP),然后SETUP建立传输通道,PLAY开始播放,数据通过RTP包源源不断过来,最后TEARDOWN结束。
海康威视网络摄像头的RTSP地址通常长这样:
rtsp://用户名:密码@IP地址:554/Streaming/Channels/101其中101代表1号通道的主码流,102是子码流。主码流分辨率高、码率高,适合抓拍;子码流分辨率低,适合做实时预览或低算力场景。大华的一般是:
rtsp://用户名:密码@IP地址:554/cam/realmonitor?channel=1&subtype=0subtype=0是主码流,1是子码流。测试的时候如果手头没有真实摄像头,可以用一些公开的RTSP测试地址先跑通链路,验证解码和抓拍逻辑没问题,再换成真实设备。
注意:很多摄像头默认只允许一定数量的并发RTSP连接,超过就会拒绝或踢掉旧连接。多路场景一定要确认设备的并发上限。
2.2 拉流方式选型:OpenCV、FFmpeg还是专用SDK
这是选型阶段最纠结的问题。我三种都用过,说下实际感受。
用OpenCV的cv2.VideoCapture拉RTSP是最省事的,几行代码就能跑。但它底层也是调FFmpeg,而且对RTSP的容错很差——网络一抖动,它不会自动重连,直接返回空帧,你得自己写重连逻辑。更麻烦的是它的缓冲机制,默认会缓存一堆帧,导致你拿到的画面延迟好几秒。做实时抓拍这基本不可接受。
FFmpeg直接调用灵活得多,可以控制缓冲、可以设超时、可以只解码关键帧。但需要自己管理解码后的帧格式转换,代码量大一些。如果追求稳定,我一般用FFmpeg子进程拉流,通过管道把原始帧读进来,再用Python解码。
专用SDK(比如海康、大华的设备SDK)稳定性最好,支持断线重连、支持回调取帧,但绑定厂商,换品牌就要重写。如果是单一品牌的大项目,用SDK是省心的选择。
| 拉流方式 | 稳定性 | 延迟控制 | 开发成本 | 适用场景 |
|---|---|---|---|---|
| OpenCV | 差 | 差 | 低 | 快速验证、单路demo |
| FFmpeg | 好 | 好 | 中 | 多路生产环境 |
| 厂商SDK | 最好 | 好 | 中高 | 单一品牌大项目 |
2.3 多路并发的资源账要提前算
假设你要接16路1080P摄像头做抓拍,每路25帧。如果每路都全帧解码,那就是每秒400帧1080P图像要处理,光解码就能把CPU吃满。所以生产环境必须做取舍。
我的做法是:抓拍不需要每帧都处理。人脸在画面里停留通常有1到2秒,25帧的流里抽5到8帧做检测完全够用。抽帧策略可以是固定间隔(比如每3帧取1帧),也可以基于运动检测动态抽帧。这样16路实际处理量降到每秒100帧左右,一台中等配置的服务器就能扛。
解码这块,如果服务器有GPU,优先用GPU硬解(NVDEC),能大幅降低CPU占用。没有GPU就用CPU软解,但要控制路数,一般8路1080P软解就是单台机器的舒适上限了。
2.4 断流重连与时间戳对齐
RTSP流断掉是常态,网络波动、摄像头重启、交换机抖动都会导致断流。重连逻辑必须做,而且要做得聪明:不能一断就疯狂重连,要有退避策略,比如第一次等1秒,第二次等2秒,指数增长到30秒封顶。
时间戳对齐是另一个容易被忽略的点。多路摄像头的画面时间如果不统一,事后检索"某人在A点出现又在B点出现"就会错乱。建议所有摄像头开启NTP对时,抓拍记录里存的是绝对时间戳而不是相对帧号。
3. 人脸检测与质量筛选:抓拍的核心工序
流拉进来了,接下来就是从画面里把人脸"捞"出来,并且只留下值得送去识别的好脸。这一步做得好不好,直接决定后面识别率的天花板。
3.1 检测模型的选择与推理加速
人脸检测模型这几年迭代很快。早期用MTCNN,精度还行但速度慢,多级级联的结构在CPU上跑不动。后来RetinaFace出来,单阶段检测,精度高,但模型偏大。现在工程上用得比较多的是SCRFD和YOLO系列的人脸变体,速度和精度平衡得比较好。
选模型的时候别只看论文里的mAP,要看实际场景。通行场景的人脸通常比较大(占画面比例高),不需要检测超小人脸的能力,反而更看重速度和侧脸检测率。我一般会拿自己项目的实际画面去测几个候选模型,看哪个在"人脸占画面1/4到1/2"这个区间表现最好。
推理加速方面,如果部署在边缘设备(比如带NPU的安卓门禁机),要用模型转换工具把模型转成设备支持的格式(如RKNN、NCNN)。如果部署在服务器,用TensorRT或ONNX Runtime加速。实测下来,同一模型用TensorRT比纯CPU推理能快5到10倍。
3.2 质量分怎么算才合理
检测到人脸不等于能用来识别。一张侧了60度的脸、一张被口罩遮了大半的脸、一张运动模糊的脸,送去识别只会拉低准确率。所以要有质量筛选。
质量分通常由几个维度加权:人脸尺寸(像素面积)、清晰度(拉普拉斯方差)、姿态角(偏航、俯仰、翻滚)、遮挡比例、亮度。每个维度归一化后加权求和,超过阈值才保留。
这里有个经验:尺寸和清晰度的权重应该最高。我见过有人把姿态权重设得很高,结果正脸但模糊的图被保留,侧脸但清晰的图被丢弃,识别率反而下降。实际上清晰的正脸当然最好,但清晰的侧脸经过对齐后识别率也不差,而模糊的图无论什么角度都没救。
阈值设置要结合场景调。通行场景人脸大、配合度高,阈值可以设高一点,保证送进识别的都是精品;如果是通道式随机抓拍,阈值要放低,否则可能半天抓不到一张合格的。
3.3 去重与最优帧选择
同一个人经过摄像头,会被连续多帧检测到。如果每帧都存,会产生大量重复记录,浪费存储也拖慢检索。所以要做去重。
去重的逻辑是:对同一个人脸目标做跟踪(用IOU或简单的卡尔曼滤波),在跟踪周期内只保留质量分最高的那一帧。跟踪周期一般设1到2秒,或者按帧数算,比如连续30帧内只留一张。
这里有个细节:最优帧的选择不能只看单帧质量分,还要考虑"这张脸是否完整走完了整个出现过程"。有时候人刚进画面时脸是完整的但偏小,走到画面中间时脸最大最清晰,快出画面时又被边缘裁切。所以最优帧往往出现在中间段,跟踪时要持续更新最优帧,直到目标消失才落盘。
4. 特征提取与1:N比对:识别环节的工程细节
抓拍产出的高质量人脸图,接下来要变成特征向量,再和底库比对。这一环算法相对成熟,但工程上仍有不少讲究。
4.1 ArcFace特征提取的输入规范
ArcFace是目前人脸识别的主流方案,核心思想是通过加性角度间隔损失让同类特征更紧凑、异类特征更分散。用的时候要注意输入规范:模型通常要求输入是112x112或112x96的RGB图,且要按训练时的归一化参数处理(一般是减均值除标准差)。
人脸对齐不能省。直接用检测框裁剪出来的脸,如果人脸是歪的,特征质量会明显下降。要用检测到的5个关键点(双眼、鼻尖、双嘴角)做仿射变换,把脸摆正到标准姿态再送进模型。这一步能带来几个百分点的识别率提升,成本却很低。
特征向量的维度一般是512维,归一化后存成float32。一个人512维float32是2KB,10万底库就是200MB,内存完全放得下。所以中小规模底库可以直接全量加载到内存做暴力检索,没必要上向量数据库。
4.2 1:N比对的检索策略
1:N比对就是把待识别特征和底库N个特征逐一算余弦相似度,取最高分。N小的时候(几千到几万)暴力检索完全够用,一次比对也就几毫秒。N大了(几十万上百万)才需要近似最近邻检索(如Faiss的IVF索引)。
通行场景的底库通常不大——一个园区几千人,一个写字楼几万人,暴力检索绰绰有余。我一般直接用矩阵运算:把底库特征堆成一个N×512的矩阵,待识别特征做矩阵乘法,一次算出所有相似度,numpy几行就搞定,速度极快。
阈值设定是1:N的关键。和1:1验证不同,1:N的误识率会随N增大而上升。N=10000时,如果阈值设0.5,误识率可能就到万分之一了。通行场景我一般把阈值设在0.6到0.65之间,宁可让人多刷一次,也不能放错人。
4.3 底库管理与特征更新
底库不是建好就不动的。人员进出、离职入职,底库要能实时增删改。特征更新有个坑:同一个人在不同时间、不同光照下拍的照片,特征是有差异的。如果只用一张注册照,遇到光照变化大的场景识别率会掉。
我的做法是给每个人存多张特征(3到5张,覆盖不同角度和光照),比对时取和待识别特征最相似的那张作为该人的得分。这样能显著提升鲁棒性,代价只是底库大几倍,完全可接受。
底库更新要支持热更新,不能重启服务。用内存数据库或带锁的字典结构,增删改时加读写锁,保证比对线程读到的是一致的快照。
5. 通行决策与联动:从识别结果到闸机开门
识别出结果只是中间态,最终要变成"开门"或"不开门"的动作,并驱动闸机、门禁等设备。这一环的可靠性直接关系到用户体验和安全。
5.1 决策逻辑与防尾随
决策逻辑看似简单——相似度超阈值就开门,但实际要考虑很多边界。比如同一个人连续被识别到多次,不能每次都发开门指令,要有去重和冷却机制。一般设一个冷却窗口,比如3秒内同一个人只触发一次。
防尾随是通行安全的重要一环。人脸识别只能确认"有人刷了脸",但无法阻止后面的人跟着进去。要配合红外对射或双目摄像头做人数统计,确保一次只过一个人。这块如果做不好,再准的人脸识别也形同虚设。
5.2 与闸机的通信方式
闸机通信常见的有几种:继电器干接点(最简单,开/关信号)、RS485/RS232串口(能传更多状态)、TCP网络(现代闸机常用)。干接点最可靠,不受协议影响,但只能单向控制。网络通信能拿到闸机状态反馈,但依赖网络稳定性。
我一般用干接点做主控制,网络做状态监控。这样即使网络出问题,开门功能不受影响。接线时注意继电器的常开常闭选择,以及开门信号的持续时间(一般200到500毫秒)。
5.3 识别失败的兜底方案
再好的系统也有识别失败的时候——人脸角度太偏、光线太暗、底库没录入。这时候要有兜底:一是语音和屏幕提示"请正对摄像头再试一次",二是提供刷卡或密码作为备用通行方式,三是有人工呼叫按钮。
兜底方案不是可有可无的,它决定了系统在异常情况下的可用性。我见过一个项目没做兜底,结果有员工因为戴了新的眼镜识别不了,堵在门口进不去,最后只能砸门。这种体验事故完全可以通过一个备用刷卡器避免。
6. 实测中的性能数据与调优经验
理论讲完了,说点实测的东西。下面这些数据来自我做过的一个园区项目,16路1080P摄像头,底库8000人,供参考。
6.1 各环节耗时拆解
| 环节 | 平均耗时 | 备注 |
|---|---|---|
| RTSP解码(单帧) | 8ms | GPU硬解 |
| 人脸检测 | 15ms | SCRFD,TensorRT加速 |
| 质量筛选 | 2ms | 纯CPU计算 |
| 人脸对齐+特征提取 | 20ms | ArcFace,TensorRT |
| 1:N比对(8000底库) | 3ms | 矩阵运算 |
| 合计 | 约48ms | 单帧全链路 |
单帧48毫秒,意味着理论上每秒能处理20帧。但实际多路并发时,GPU要分时处理,16路抽帧后总处理量约每秒100帧,需要GPU有足够的算力余量。实测用一张中端GPU(如T4级别)跑16路抽帧抓拍,GPU利用率在60%到70%,还有余量。
6.2 识别率与误识率的实测表现
在园区实际场景下(员工配合、光照正常),1:N识别首位命中率能做到98%以上,误识率控制在十万分之一以下。光照差或戴口罩的情况下,命中率会掉到90%左右,这时候质量筛选和多次尝试就很重要。
有个反直觉的发现:把质量阈值调高,整体通过率反而上升。原因是低质量的图送进识别,要么识别错要么识别不出,导致用户要反复刷。而只保留高质量图,虽然单次抓拍可能筛掉一些帧,但一旦有合格帧,识别几乎必中。所以质量筛选不是"损失",而是"提纯"。
6.3 长时间运行的稳定性问题
跑一周不出问题不难,跑三个月不出问题才是本事。长时间运行最常见的两个问题是内存泄漏和句柄耗尽。内存泄漏往往出在图像缓冲没释放、特征向量没回收;句柄耗尽通常是RTSP连接没正确关闭。
我的做法是加监控:定时打印内存占用、连接数、各环节耗时。一旦发现内存持续增长或连接数不降,立刻排查。另外给拉流进程加看门狗,异常退出自动重启,保证单路故障不影响整体。
7. 部署形态选择:边缘一体机还是中心服务器
最后聊聊部署形态,这是方案设计阶段就要定的事,直接影响成本和架构。
7.1 边缘部署的适用场景
边缘部署就是把抓拍和识别都放在前端设备上,比如带算力的安卓门禁机或边缘盒子。优点是延迟低(不用传图到中心)、带宽省(只传结果不传图)、隐私好(人脸图不出设备)。缺点是算力有限,底库不能太大,一般几千人以内。
安卓门禁机这类设备现在很流行,本质是一台带NPU的安卓设备,跑轻量化的人脸检测和识别模型。选型时要注意NPU的算力(TOPS)和内存,以及是否支持你需要的模型格式。有些设备只支持特定框架转换的模型,选之前一定要确认。
7.2 中心部署的适用场景
中心部署是摄像头只负责取流,抓拍和识别都在中心服务器做。优点是算力集中、底库可以很大、便于统一管理和升级。缺点是对网络带宽有要求(要传视频流),延迟略高。
大规模场景(几十路以上、底库几万以上)基本都得走中心部署。这时候服务器选型要考虑GPU算力、内存容量和网络吞吐。我一般建议GPU留30%以上余量,方便后续加路数或升级模型。
7.3 混合部署的折中方案
实际项目里最常见的是混合:前端做抓拍(因为抓拍算力需求相对小),把抓拍到的人脸图传到中心做识别和比对。这样既省了传视频流的带宽,又能在中心用大底库和强算力。传输的是压缩后的人脸小图(几十KB),比传视频流(几Mbps)省太多了。
混合方案的关键是前端抓拍的质量要过关,因为传到中心的就是最终送去识别的图,没有二次筛选机会。所以前端的质量筛选阈值要设得合理,既不能太松(传一堆废图),也不能太严(漏掉合格图)。
整个链路走下来,我的核心体会是:人脸抓拍识别项目的成败,算法只占一半,另一半全在工程细节上。RTSP拉流的稳定性、质量筛选的合理性、阈值设定的场景适配、异常情况的兜底,这些才是决定项目能不能真正跑起来的关键。算法可以买、可以调,但工程上的坑只能一个个踩过来。如果你正在做类似的项目,建议先把拉流和抓拍这两块打磨扎实,识别环节反而是最容易标准化的部分。