简介这套基于深度学习的人脸门禁与 IPC 智能安防监控系统是一份面向高校毕业设计、课程设计及人工智能学习者的完整工程源码解决人脸识别、权限管理与实时监控联动等问题。资源为 25.58MB 的 zip 压缩包共 71 个文件以 C/C 源程序.cpp/.hpp/.h/.c为主辅以 RKNN 模型、JSON 配置、Shell 脚本、Makefile 与 Dockerfile便于跨平台编译与部署。项目按功能模块组织涵盖图像采集、模型推理、界面交互、数据管理与异常检测机制等多层设计整体结构清晰适合在嵌入式设备上运行与二次开发。目前已有 54 人学习可参考其模块划分与接口实现进行毕业设计或课程设计的改造升级。通过这份资源可了解从端侧采集、算法推理到界面展示的完整安防系统链路同时获得编译配置、部署脚本等工程化细节有助于快速搭建人脸门禁演示系统或扩展监控功能。1. 深度学习人脸门禁IPC监控这套系统到底在做什么先澄清一个高频误会这里的 IPC 是 Internet Protocol Camera网络摄像机不是操作系统里的进程间通信。基于深度学习的人脸门禁IPC智能安防监控说白了就是把园区或办公室里的摄像头一个人当两个人用——白天当监控探头抓异常有人走到闸机前又当人脸识别终端比对通过就从串口或继电器发一个开闸信号同时把抓拍到的脸、识别分数、经过时间全部落库。以前这套逻辑要拆两个项目门禁主机跑一套嵌入式程序监控平台跑另一套录像服务两个系统间的日志还对不上。现在用 Python PyTorch 就能把两端拉通模型、断线重连、告警联动全放进一个工程里。这个方向适合毕业设计、园区改造或者小团队做低成本门禁试点难点不在“跑通一个模型”而在怎么让它在真实摄像头画面里稳定工作一整天。2. 模型选型与训练从人脸检测到特征提取的实地对比做门禁之前先想清楚一个问题你要的是一个“能认出人”的系统不是一个“能检测到人脸”的演示脚本。检测到脸只是第一步门禁还得知道这张脸是谁、是不是活人、角度变化时还能不能认出来。所以整个识别链路至少包含三块人脸检测、人脸对齐、特征提取与比对。常见做法是检测用 RetinaFace 或 SCRFD识别用 MobileFaceNet ArcFace 损失函数整套流程用 InsightFace 的工程配方组合起来比从零搭 ResNet 靠谱得多也省下大量调参时间。2.1 人脸检测选型户外门禁为什么要选轻量又抗遮挡的模型门禁摄像头装在闸机上方人脸角度通常是俯视 15 度到 30 度还会出现帽子、口罩、逆光。传统通用目标检测模型 YOLOv5 也能框人脸但它对关键点回归的支持比较弱框出来之后没人眼坐标下一步对齐就麻烦。RetinaFace 最大的优势是一步回归五个面部关键点检测框和眼睛、鼻子、嘴角一起出来直接喂给识别模型前的人脸对齐省掉单独调关键点模型的环节。需要边缘设备跑的话SCRFD 是更划算的选择它把检测分支和识别得分分支做了特征复用同样精度下比 RetinaFace 少不少算力。选型另一条经验是别盲目追大模型。门禁场景只需要在 2 到 4 米范围内框出人脸目标分辨率不低于 32x32 就够用。我一般直接用 insightface 里带 ONNX 导出的 buffalo_l 或 antelopev2 模型前者在变老、遮挡场景更稳后者在正常光照下精度更高。如果你要训练自己的检测模型要注意数据里必须包含俯视角度和侧脸样本纯前额的公开数据集在真实门禁场景下会掉点掉到你想骂人。2.2 特征提取与损失函数为何 ArcFace 是这个场景的默认答案检测出人脸之后要把一张 112x112 的 RGB 图像压缩成一个固定长度的特征向量。人脸识别模型做的事情就是让同一个人的向量之间距离尽量近不同人的向量距离尽量远。传统 Softmax 分类只能告诉你“这人是谁”没法直接控制“不同人之间该拉开多远”。ArcFace 在 Softmax 的基础上给真实标签对应的夹角加了一个固定 margin训练时强制网络把同类特征压缩到一个小球面上不同类之间隔出一个明显的圆弧边界。门禁场景里用户体验全靠这个 margin 拉出来的区分度0.5 的 margin 和 0.7 的 margin在陌生人误识率上能差出一个数量级。MobileFaceNet 是专为移动端设计的轻量识别网络在 ARM CPU 上跑一次特征提取约 10 到 20 毫秒精度比 ResNet50 低一些但用在园区门禁完全够。如果是人流量很大的办公大楼可以换 IResNet50 放在 GPU 服务器上把所有摄像头的识别请求集中推理代价是网络延迟会多出 30 毫秒左右。2.3 数据准备与训练脚本从公开数据集到自建人脸库的完整走法训练识别模型最少需要两类数据底库你要放行的员工和训练集用来调模型的公开人脸集。公开数据集我习惯用 Glint360K 或 MS1MV2 做预训练这些数据量大但脏样本也不少直接训练容易学到奇怪的特征。正规做法是先在公开集上跑 30 到 50 个 epoch得到一个能区分一般人的预训练模型再用你自己采集的员工照片做最后微调。员工数据采集也有讲究每人至少 20 张覆盖正面、左右侧 30 度、戴不戴眼镜、早中晚光线不能只拍一张证件照就扔进底库否则现场光线一偏就识别失败。微调阶段的数据加载流程大致如下# train_face.py —— 人脸识别微调的最小骨架 import torch from torch.utils.data import DataLoader from torch.optim import SGD from model import MobileFaceNet from arcface_loss import ArcFaceLoss # 112x112 对齐好的人脸图每类一个文件夹 train_set FaceDataset(rootdata/glint_mini, img_size112) loader DataLoader(train_set, batch_size128, shuffleTrue, num_workers4, pin_memoryTrue) model MobileFaceNet(num_classes1000) optimizer SGD(model.parameters(), lr0.01, momentum0.9, weight_decay5e-4) criterion ArcFaceLoss(in_features512, out_features1000, s32.0, m0.5) for epoch in range(20): model.train() for imgs, labels in loader: features model(imgs) loss criterion(features, labels) optimizer.zero_grad() loss.backward() optimizer.step()这里s32.0是特征缩放因子把余弦相似度放大到合适的数值区间训练更稳定m0.5是角度 margin越大类间间隔越大但太大也会让同类样本难以收敛一般从 0.5 试起。训练完导出 ONNX 时要把最后的分类层去掉只保留特征向量输出因为比对阶段用的是余弦相似度不是 Softmax 概率。导出时记得锁住 BatchNorm 的统计量用torch.onnx.export的trainingFalse模式否则模型会在推理时用当前 batch 的均值和方差导致不同批次结果不一致这是很多人部署时翻车的隐藏坑。3. 接入 IPC 视频流ONVIF 发现设备与 RTSP 取流的落地细节模型再准没有画面进来都是白谈。IPC 接入这件事看着简单实际上一半项目的周期都耗在“跟摄像头打交道”上。不同厂商的海康、大华、宇视都有自己的私有协议但几乎所有设备都支持 ONVIF 标准协议和 RTSP 拉流。第一步先把设备搜索出来确认 IP、端口、通道号再拼 RTSP 地址这才是稳定的设备接入路子。直接拿着厂商 SDK 写换一个品牌就要重写一套得不偿失。3.1 用 ONVIF 协议搜索设备与获取 RTSP 地址ONVIF 的核心能力是设备发现和服务协商。把 IPC 和电脑接到同一个局域网用 ONVIF Device Test Tool 或 python-onvif-zeep 库发一个 WS-Discovery 广播设备就会回传自己的型号、IP、摄像头服务地址。用 python-onvif-zeep 的流程是这样# onvif_search.py —— 用 ONVIF 发现摄像头并获取 RTSP 流地址 from onvif import ONVIFCamera import socket # 先通过 WS-Discovery 发现设备实际项目中可用 nmap 扫 3702 端口 addr 192.168.1.64 username, password admin, YourPassword cam ONVIFCamera(addr, 80, username, password) media_service cam.create_media_service() profiles media_service.GetProfiles() for p in profiles: stream_uri media_service.GetStreamUri( {StreamSetup: {Stream: RTP-Unicast, Transport: {Protocol: RTSP}}, ProfileToken: p.token}) print(f{p.Name}: {stream_uri.Uri})这段代码连上设备后先取配置文件 Profile再按 Profile 拿到对应的 RTSP 地址。很多厂商会把主码流和子码流分别放在两个 Profile 里门禁识别场景只取子码流分辨率 640x360、码率 1024kbps 就够主码流留给录像。如果 GetStreamUri 报错先确认摄像头时间是否准确ONVIF 很多服务不校时会拒绝连接。RTSP 地址格式各家略有不同但拿到 StreamUri 后直接用不要手工拼接rtsp://user:passip:554/...猜路径。3.2 视频流解码与抽帧别再直接循环读帧拿到 RTSP 地址后最简单的方式是 OpenCV 的VideoCapture但直接这么干的人多半会栽在延迟上。OpenCV 底层对 RTSP 的缓存控制很弱默认会积压几十帧画面显示出来比实时慢 3 到 5 秒门禁识别就变成“人刷卡两秒后才开闸”。我一般用 FFmpeg 做单独的解码进程通过管道把最新帧递给 Python或者直接用 FFmpeg 的-vf fps参数按需抽帧。# 抽帧脚本每秒取 2 帧存成带时间戳的 jpg ffmpeg -rtsp_transport tcp -i rtsp://admin:password192.168.1.64:554/Streaming/Channels/102 \ -vf fps2 -strftime 1 frames/img_%Y%m%d_%H%M%S.jpg这里强制用tcp传输是因为 RTSP 默认走 UDPWi-Fi 或有线丢包稍高就会出现花屏、黑屏TCP 多花一点带宽换画面完整值得。fps2表示每秒只抽 2 帧做人脸检测门禁场景下一个人走到闸机前至少停留 1 到 2 秒2 帧足够捕获到正脸。如果摄像头是 4K 的务必在 IPC 后台把子码流分辨率和码率降下来否则多路摄像头会把磁盘带宽和 CPU 都吃满。还要提一句 OpenCV 的替代写法如果你还是想用 VideoCapture务必把缓冲队列改小# read_rtsp.py —— 降低延迟的 OpenCV 拉流写法 import cv2 cap cv2.VideoCapture(rtsp://admin:password192.168.1.64:554/Streaming/Channels/102) cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 只保留最新的 1 帧 cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 360) while True: ok, frame cap.read() if not ok: cap.release() time.sleep(1) # 断流重连前等 1 秒避免疯狂重连 cap cv2.VideoCapture(rtsp_url) continue # 人到闸机附近才做检测远端区域直接丢帧注意CAP_PROP_BUFFERSIZE并不是所有平台都生效Windows 上效果明显Linux 下某些发行版会忽略最终以实测为准。断流重连也是必须做的IPC 在雷雨天气或交换机重启时会断开 RTSP识别的进程不能一崩了之要像上面代码里那样先释放再重建重建失败就退避等待防止日志刷屏。4. 门禁控制与联动逻辑识别阈值、活体检测与继电器开关的配合图像链路通了接下来是门禁系统的灵魂——决策逻辑。脸识别出来只是一个特征向量怎么判定“放行”还是“拒绝”阈值定多少遇到照片攻击怎么办开锁信号怎么发出去这些都要在代码里安排明白。这部分做得好系统才叫门禁做得不好顶多算一个“人脸显示屏”。4.1 识别判定流程相似度阈值怎么定才不是玄学端到端的识别流程是这样的抽到一帧图 → 人脸检测得到 bbox 和关键点 → 用关键点对齐缩放成 112x112 → 送入 MobileFaceNet 提取 512 维特征 → 跟底库里的所有人脸特征算余弦相似度 → 取最高分和对应 ID → 得分高于阈值就开锁低于阈值就忽略。关键就在这个阈值很多新手随便填一个 0.6现场测试时发现谁都能开门或者谁都不让进。定阈值不能靠拍脑袋。正确做法是采集至少 100 个不同人的脸加上 20 个底库员工的脸分别提取特征画出“合法用户相似度分布”和“陌生人相似度分布”两张直方图两条曲线的交点附近就是阈值的起步区间。通常 ArcFace 特征相似度高的人会在 0.7 以上不相关的人在 0.2 到 0.4 之间中间留出了很大的空白区间。园区门禁我一般先设 0.65然后看一周误识率如果陌生人开了门就往上调到 0.7员工被拦就从 0.7 往回调这个调整过程需要记日志配合不能靠嘴上感觉。# decision_logic.py —— 识别结果判定与开锁动作 import numpy as np import serial threshold 0.65 def verify(embedding, db_embeddings, db_ids): # db_embeddings: (N, 512), db_ids: [str, ...] scores np.dot(db_embeddings, embedding) # 特征已归一化点积即余弦 idx int(np.argmax(scores)) if scores[idx] threshold: return db_ids[idx], float(scores[idx]) return None, float(scores[idx]) def unlock_serial(): # 常见门禁控制器接串口0x01 是自定义的开锁指令以厂家协议为准 with serial.Serial(/dev/ttyUSB0, 9600, timeout1) as ser: ser.write(bytes([0x01, 0x00]))点积代替单独算余弦相似度前提是特征已经 L2 归一化模型输出后要过一遍normalize否则数值范围是乱的。unlock_serial只是示意有些门禁控制器是网口模块发送 HTTP 请求有些是继电器闭合但核心逻辑都一样比对通过后只发一次开锁信号不能每帧都发不然人会一直卡在闸机口被反复刷开。4.2 活体检测只靠照片就能过那跟普通门锁有什么区别人脸门禁最大的安全威胁是打印照片和手机屏幕。只做 2D 特征比对的照片攻击很简单拿一张 A4 纸打印员工照片往摄像头前一放特征比对照样通过。活体检测至少要做一层实时校验。低成本方案是用 RGB 摄像头检测屏幕摩尔纹和反光但效果一般更可靠的是双摄像头或结构光方案——IPC 有红外通道的可以用红外图和可见光图同时做人脸检测对比两张图的人脸区域一致性打印照片在红外下通常会消失或变得很平。如果你没有红外通道退而求其次的做法是要求用户完成一个动作比如眨眼或左右转头。OpenFace 和 MediaPipe 都能实时输出眼睛开合度和头部姿态角识别到人脸后先判断张嘴或眨眼动作是否出现再送特征比对。代价是通行变慢每个人要多停一秒做动作。实际项目里我会把动作活体检测做成可开关的办公楼白天人流量大就关掉仅在高安全等级的机房门口强制开启。4.3 多摄像头联动通道分配与告警录像回放门禁系统还有一把隐藏钥匙识别结果的联动。摄像头既做人脸识别就要把“谁在几点经过了哪个闸机”这件事以结构化记录供回溯不能只在监控画面里留一段没人看的录像。我一般把识别结果和时间戳同步写入 SQLite再在录像服务里维护一份视频索引表记录每个摄像头的启动时间、存储路径、识别事件 ID。事后检索时按人员 ID 或时间段查表定位录像段从对应时间点前后各拉出 10 秒视频就是完整的证据链。这里有一个容易忽略的细节多路摄像头看到的是同一个人的不同角度像是抓行政楼的 3 号摄像机和 5 号摄像机同时看到一个人经过底库比对的都是同一张脸所以识别日志要去重。去重策略不是按时间而是按追踪 ID——用 IoU 跟踪连续几帧里出现的同一个 bbox确认是同一目标后在一段通行周期内只上报一次识别事件。5. 人脸门禁系统常见故障排查七个实测踩坑记录这部分是我在多个项目里反复踩过的坑录成常见问题供排查时对应现象定位。每一条都按“现象 → 原因 → 解决”来写你在现场遇到可以直接对着查比翻模型论文有用得多。5.1 取流与图像相关故障现象一白天识别率 99%晚上直接掉到 60%门禁没人敢用了。原因是摄像头在低照度下自动切成红外黑白模式红外画面里人脸纹理被抹平RGB 模型在灰度输入上特征提取质量大幅下降而且黑白画面下活体检测基本失效。解决办法分两级硬件上加白光补光灯让摄像头维持在彩色模式算法侧在训练数据里加入灰度图增强让模型对灰度输入不敏感。这两个措施一起做晚上识别率通常能回到 90% 以上。现象二RTSP 画面延迟越来越高后来干脆卡死。原因是 OpenCV 的 VideoCapture 缓冲队列积压了太多帧或 FFmpeg 解码进程跟主进程的管道没有及时消费。解决把抽帧独立成子进程FFmpeg 输出到 FIFO主进程只读屏幕上的最新帧代码里做队列溢出保护检测到内存积压超过阈值就主动清空重连。另外检查摄像头码率子码流超过 2Mbps 时交换机带宽可能已经打满。现象三换了台 IPCONVIF 报错找不到 Media Service。原因很多厂商默认不开启 ONVIF或者密码里带特殊字符导致 URL 解析出错。解决先到摄像头 Web 后台确认 ONVIF 开关打开RTSP 地址里的密码如果包含或/必须做 URL 百分号编码比如要写成%40。少部分设备 RTSP 认证走 DigestOpenCV 不支持时换 FFmpeg 加-rtsp_flags prefer_tcp参数再试。5.2 识别与门禁逻辑相关故障现象四员工挡在摄像头前门禁闪开又关反复刷开。原因是比对通过后开锁信号只发一次但人脸一直停在画面里下一帧又触发了一次比对继续发开锁指令继电器跟着反复吸合。解决加一个开锁冷却时间比如 N 秒内同一张脸 ID 不允许重复开锁代码里维护一个last_unlock_time字典到期前直接忽略新结果。现象五训练微调时 loss 震荡不下降识别率比预训练模型还低。原因是数据预处理不一致关键点对齐时用了不同的缩放比例或者输入图没有做成 RGB 统一通道顺序。ArcFace 模型的训练对对齐极度敏感五个关键点坐标错了 3 个像素特征就会漂移。解决把对齐函数固定下来训练、验证、推理共用同一个版本导出 ONNX 时把预处理写进模型里杜绝部署端和训练端不一致这是血泪经验。现象六陌生人用手机屏幕照片开了门。原因是活体检测未启用或强度太低单目 RGB 对手机屏幕的区分度有限。解决优先启用红外可见光双目校验没有硬件条件就把动作活体门槛提高要求眨眼加头部偏转两个动作都通过。低成本补救方法是在门禁机前贴一个“请亮出通行码”的提示诱使真实用户做动作同时也能让攻击者犹豫。现象七服务跑了一个月后人脸库加载越来越慢。原因每识别一次就把整个底库特征重新读一遍或者 SQLite 表膨胀后没有索引。解决底库特征一次性加载到内存人员脸数量超过一万时用 Faiss 建索引做 ANN 搜索比对耗时从几十毫秒压到几毫秒。改动底库后触发重载避免热更新时出现半新半旧状态。6. 部署验证与进阶调优用一张验收表收敛参数再谈和 STM32 嵌入式方案的取舍系统能跑只是开始让它持续稳定地跑才是真功夫。我验收一个门禁系统有一套固定的实测表不拍脑袋也不全信模型在测试集上的报告。表的核心指标有五个识别通过率、陌生人拦截率、平均识别延迟、断流恢复时间、开锁误触发率。识别通过率至少 99%正常光线下陌生人拦截率至少 95%延迟从人脸进入画面到闸机打开不超过 1 秒断流恢复时间不超过 5 秒。测的时候要分三种光线上午顺光、下午逆光、晚上补光每种跑 100 次通过测试数据说话。调优顺序也有讲究先调输入图像质量再调检测阈值最后才动算法模型。图像质量靠调节补光灯角度和摄像头曝光时间检测阈值按前面说的直方图法定切线模型不回炉就不乱回炉。如果最终精度不够优先考虑换更大的检测模型或多帧投票而不是无脑加大训练数据。到了嵌入式改造这一步很多人会问能不能换成基于 STM32 的人脸识别门禁系统STM32 这类 MCU 跑不了 MobileFaceNet 这种规模的模型即便跑起来内存和帧率都不够除非换带 NPU 的芯片。我一般这么选型简单人脸比对底库小于 50 人、识别帧率 1 到 2 帧可以用 RV1106 或 RV1103跑 0.5 TOPS 级别的 NPU要是想保留 IPC 联动、多路人脸抓拍、大底库检索直接上 RK3588 或树莓派 5 USB 摄像头开发周期短Python 生态能复用全部代码成本比 STM32 方案多一两百块但省下至少两周的移植时间。纯硬件成本敏感且不需要活体检测的场景才值得去啃 MCU 方案。最后说一个我踩过最深的坑项目上线后不要马上删除后台的调试日志至少要保留两周的识别画像数据和事件录像。有一次客户反馈“某员工总是识别失败”我翻开日志发现他每天下午四点半经过闸机摄像头刚好被西晒逆光直射人脸区域过曝到一片白。这种问题如果不留日志现场根本无法复现最后只能靠提高前端 HDR 和阈值适配硬扛过去。现在我的习惯是每次上线都同时记录识别得分、光照强度统计和人脸框位置用这些数据持续微调阈值和补光方向。只有把阈值、模型、硬件当作一体来迭代这套系统才真正从“能演示”变成“能值班”。希望帮到你。本文还有配套的精品资源点击获取