news 2026/10/28 1:06:54

基于Atlas200DK的人脸识别门禁系统源码与部署全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Atlas200DK的人脸识别门禁系统源码与部署全解析

简介:基于Atlas200DK的人脸识别智能门禁系统完整项目资料,适合计算机、人工智能、物联网等专业学生用于毕业设计或课程设计。系统借助Ascend310 AI处理器与Hi3559图像芯片,完成实时人脸识别、体温检测、门禁联动与异常报警;整体由管理系统与门禁设备系统组成,设备端包含基于ACL的C++模型推理应用,管理端采用Tornado+Bootstrap构建Web服务,前后端协作路径完整。压缩包共175个文件,大小约52MB,以C++头文件与源码、Python脚本、om模型文件为主,同时提供proto协议文件、配置文件、前端资源及项目构建说明,层次清晰便于阅读。已有735人学习下载,适合有一定编程基础的学习者参照部署流程快速运行,亦可作为二次开发的基础平台。包内附有项目说明与运行部署文档,上手门槛进一步降低。

1. 用 Atlas200DK 跑人脸识别门禁:这套源码到底给了你什么

手里拿到这套“基于 Atlas200DK 的人脸识别智能门禁系统源码+模型+运行部署文档”时,第一反应别急着解压。它是一整套边缘 AI 落地方案:昇腾 310 板卡上跑人脸检测与识别,比对通过后控制继电器开锁,源码、预训练模型、部署文档三件套齐全,属于毕设里少见的“能直接上板子跑”的项目。适合两类人:一是选题落在嵌入式 AI 的毕业生,二是想快速验证人脸识别门禁机原型、但又不想从 Linux 驱动开始啃的工程师。真正劝退人的不是识别算法本身,而是环境、模型转换和板端联调这三关——这篇文章就按这个顺序把路踩平。

2. 先搞懂这套门禁系统的整体链路:从摄像头到开锁的每一环

2.1 人脸识别门禁机的四段式架构:检测、跟踪、识别、控制各管一段

人脸识别门禁机里跑的从来不止一个神经网络。常见做法是把整条链路拆成四段:先做人脸检测,帧里没有人脸时根本不用往下走;检测到人脸后接一个轻量跟踪器,避免每一帧都重跑检测;稳定的人脸区域送入识别模型提取特征向量;最后拿特征向量去注册库比对,相似度超过阈值才触发 GPIO 开锁。

检测端常见选型是 RetinaFace、YOLOv5-face 这类同时输出边界框和人脸关键点的模型,因为后面裁剪对齐需要关键点坐标。识别端的主流是 ArcFace 及其轻量变体 MobileFaceNet,这类模型把输入人脸映射成一个 128 维或 512 维的特征向量,比对用余弦相似度,阈值一般在 0.4 到 0.7 之间。把检测和识别拆成两个独立模型而不是端到端一把梭,好处是识别特征库不受检测模型升级影响,换检测模型时底库不用重训。

这套架构里还有个容易被忽略的点:门禁场景的“误开”和“漏开”代价不对等。漏开最多是用户多刷两次脸,误开会直接放陌生人进门。所以设计上要刻意偏向“宁可慢一拍,也别乱开门”,后面第 6 章会专门讲怎么把误识别率压下来。整个链路的性能瓶颈通常不在某个模型的精度,而在帧率、预处理流水线、特征比对耗时之间的配合。

2.2 拆开源码包先看目录:运行部署文档比代码更值钱

我接过不少这类 zip 包,目录结构大同小异。常见分法是四个目录:src 放板端推理代码和门禁控制逻辑,model 放预训练模型和 ATC 转换脚本,docs 放运行部署文档,tools 放制卡、标定、抓图这类辅助工具。拿到压缩包以后别急着编译,先把 docs 里那篇运行部署文档通读一遍。这类文档通常会把环境版本、固件烧录步骤、模型转换命令写得非常具体,很多坑其实文档里已经预警了,只是信息是散的,你得先有个全局认识再动手。

有个血泪经验要提前说:不要相信“源码拿到就能编译”。Atlas200DK 的交叉编译环境、CANN 版本、板端运行环境这三者经常不一致,源码本身没变,环境变了就会编不过或跑不起来。所以正确顺序是:先按运行部署文档把基础环境搭通,再编译源码里的示例,最后才编译自己的业务代码。如果一上来就编主工程,报错信息会把你埋了——你根本分不清是环境问题还是代码问题。

2.3 Atlas200DK 的角色定位:为什么是 Ascend 310 而不是树莓派

很多人会问,门禁逻辑这么轻,树莓派不能干吗?能干,但体验差一截。树莓派用 CPU 推理,YOLOv5s 在 1080p 输入下跑不到实时帧率;而 Atlas200DK 用的昇腾 310 芯片提供 8 TOPS INT8 算力,配合板载 8GB 内存,跑轻量人脸模型余量很大。更关键的是它带独立的 DVPP 图像处理单元,能硬解码 H.264/H.265 视频流、硬件缩放和格式转换,这些恰恰是视频门禁最吃资源的部分。

这套系统里 Atlas200DK 的定位就是边缘节点:摄像头推 RTSP 视频流进来,板端完成解码、检测、识别、比对、开锁全流程,不依赖云端。断网时门禁照样工作,这是它比“摄像头+云识别”方案最大的卖点,也是毕设答辩时可以重点讲的东西。实际部署时,前端摄像头只管采集推流,所有智能逻辑都下沉到板卡上,注册人脸库也可以本地化管理,隐私上更说得过去。

3. 环境搭建与板端初始化:CANN 版本选错会让你一夜回到解放前

3.1 从制卡开始:TF 卡镜像与官方制卡脚本的坑

Atlas200DK 本身不带操作系统,常见做法是把厂商提供的 Ubuntu 镜像写到 TF 卡里,然后从 TF 卡启动。制卡不是简单地用 dd 把镜像怼进卡里,官方提供了专门的制卡脚本,它会先解压镜像、分区、写 bootloader,一套流程做完才是一张能启动的卡。

# 在 Ubuntu 开发机上执行,把官方镜像写入 TF 卡 # /dev/sdb 是 TF 卡设备节点,不同机器不一样,用 fdisk -l 确认 python3 make_sd_card.py local /dev/sdb

逻辑说明:这个脚本接收两个参数,local表示使用本地已下载的镜像包,/dev/sdb是 TF 卡的块设备路径。脚本执行时会自动格式化整块设备,不需要手动分区。参数里最容易翻车的就是设备节点选错——如果选到硬盘,脚本会毫不犹豫地把它清空。

制卡还有个隐形坑:TF 卡品质直接影响启动稳定性。杂牌卡或者写入速度太慢的卡,制卡过程能成功,但板子启动时经常随机卡死在 uboot 阶段。有条件就选官方列表验证过的卡,容量 16GB 以上、读写速度 Class 10 起步。另外制卡脚本执行完后,建议先插回板子确认能进入系统,再继续装后面的工具链,避免带着一张坏卡排查半天。

3.2 CANN 工具链与系统版本的强绑定:先对版本再动手

CANN 是昇腾板卡的软件栈,驱动、固件、工具链三者的版本是强绑定的。装错版本的典型后果是:芯片初始化失败,或者模型加载时报“model file is invalid”之类的错误。我踩过的坑是驱动和 toolkit 版本不一致,npu-smi 能看到芯片,但一跑推理就报错,排查了很久才发现是版本错位。

安装顺序有讲究:先装驱动和固件,确认npu-smi info能正常显示芯片信息,再装 CANN toolkit。常见的 toolkit 安装包是一个 .run 文件,安装命令如下:

# 板端以 root 执行,安装 CANN 工具链 chmod +x Ascend-cann-toolkit_*.run ./Ascend-cann-toolkit_*.run --install # 安装完成后验证芯片状态 npu-smi info

逻辑说明:chmod +x给安装包加执行权限,--install参数让安装包按默认路径安装,一般落在/usr/local/Ascend下。安装过程中如果提示依赖缺失,用 apt 补齐对应库再重试。npu-smi info正常显示芯片温度、版本、占用率,说明驱动固件层已经通了。

注意:CANN 版本和驱动固件版本必须配套。版本搭配表以官方文档为准,不要混用大版本,比如 CANN 5.x 配 5.x 对应的驱动固件,别拿 6.x 的 toolkit 去配老驱动。

我一般会先装一个“最小可用环境”:驱动、固件、toolkit、样例代码,全装完先跑通官方自带的推理样例,再进自己的项目。这样后续任何报错都能快速二分——是环境问题还是业务代码问题。

3.3 开发机与板端的环境变量:一次 source,到处编译

CANN 安装完后不会自动生效,必须 source 环境变量脚本,否则编译时找不到acl/acl.h,运行时也会报找不到动态库。常见做法是把环境变量 source 命令写进~/.bashrc,每次登录自动加载。

# 将以下内容追加到 ~/.bashrc source /usr/local/Ascend/ascend-toolkit/set_env.sh export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/runtime/lib64:$LD_LIBRARY_PATH

逻辑说明:set_env.sh会把头文件路径、库路径、工具路径全部写进环境变量;第二条 export 是手动把 runtime 的 so 库路径补进去,避免运行时找不到libascendcl.so。不同版本的安装路径可能有差异,先ls /usr/local/Ascend看一下实际目录名。

提示:x86 开发机上交叉编译 aarch64 目标程序时,set_env.sh指向的是 x86 的工具链,编译出的二进制不能直接拷到板子跑。我一般直接上板子源码编译,省掉交叉编译链的维护成本——Atlas200DK 编译一个小型 C++ 工程也就几分钟,完全等得起。

环境搭建到这一步就算通关了。判断标准:板端能跑通官方提供的任意一个 acl 推理样例。跑不通就先别往下走,回头检查版本搭配。

4. 人脸模型转 OM:精度、性能和玄学都藏在这一步

4.1 从 ONNX 转出两个 OM:检测模型与识别模型

在 Atlas200DK 上,PyTorch 模型不能直接跑,必须先用 ATC 工具把 ONNX 转成昇腾的 OM 离线模型。这套门禁系统里通常需要转两个模型:一个人脸检测模型,一个人脸识别模型。转换的命令结构是一样的,差异主要在输入尺寸和预处理配置。

以检测模型为例(比如 YOLOv5s-face 结构),先把 PyTorch 权重导出成 ONNX,再用 ATC 转换:

atc --model=yolov5s-face.onnx --framework=5 \ --output=face_det --input_format=NCHW \ --input_shape="images:1,3,640,640" \ --soc_version=Ascend310 \ --insert_op_conf=aipp.cfg \ --precision_mode=allow_fp32_fp16

逻辑说明:--model指定输入 ONNX 文件,--framework=5表示 ONNX 格式(Caffe 是 0,MindSpore 是 1,TensorFlow 是 3,这个数字经常有人记错)。--output是生成的 OM 文件名,--input_format=NCHW和--input_shape声明输入的维度布局,这里以固定 batch 为 1、3 通道、640x640 为例。--soc_version=Ascend310必须与板卡芯片型号一致,填成 Ascend710 这类型号转换能成功,但加载到 310 上直接报错。--insert_op_conf指定 AIPP 预处理配置文件,下一步细说。--precision_mode=allow_fp32_fp16允许模型里部分算子降精度到 FP16 跑,换取更高吞吐。

识别模型(比如 MobileFaceNet)的转换命令几乎一样,只要把--input_shape改成模型的真实输入尺寸,一般是 112x112。这里有个新手容易绕弯的地方:检测模型输出的是检测框,识别模型输入的是裁剪后的人脸图,两套输入尺寸完全不同,AIPP 配置也要各配一份,不能共用。

4.2 AIPP 预处理参数:RGB/BGR、均值和 crop 一个不对就翻车

OM 模型在板端执行时,图像输入可以走 AIPP 硬件预处理单元,自动完成缩放、裁剪、颜色格式转换、减均值、归一化,省掉 CPU 的预处理开销。但 AIPP 配置号称“玄学”,参数不对,模型推理结果直接漂移。最常见的是色序问题:OpenCV 拉出来的帧是 BGR,而模型训练时用的是 RGB,AIPP 里input_format没配对,检测精度会莫名其妙掉一半。

一个检测模型的 AIPP 配置模板如下:

aipp_op { aipp_mode: static input_format: RGB888_U8 mean_value: 104.0 117.0 123.0 csc_switch: false src_image_size_h: 640 src_image_size_w: 640 crop: true load_start_pos_h: 0 load_start_pos_w: 0 crop_size_h: 640 crop_size_w: 640 }

逻辑说明:input_format定义输入到 AIPP 的像素格式,RGB888_U8表示 8 位 RGB;mean_value是训练时的减均值参数,三个值分别对应 RGB 三个通道,必须以训练预处理为准,不同模型差异很大;crop相关参数决定是否在硬件上做裁剪,src_image_size必须和送入 AIPP 的图像真实尺寸一致,否则硬件会按错误参数读取数据。

参数说明里最容易踩的坑是mean_value和csc_switch。mean_value填错了不会报错,只会让模型精度悄悄变差,这种“翻车”最隐蔽。csc_switch控制是否做颜色空间转换,如果输入已经是 RGB 就不要开,开了等于二次转换,颜色直接偏掉。我建议把 AIPP 配置和训练时的预处理代码放在一起逐行核对,尤其是均值、方差、通道顺序三个点。

4.3 用 msame 验证 OM:先别急着接摄像头

模型转换完别直接上代码,先用 msame 工具验证 OM 能不能正常推理。msame 是社区里常见的模型推理验证工具,用法不复杂:

# 在板端执行,用一张测试图验证 OM 是否正常 msame --model=face_det.om --input=test.jpg --output=./out

逻辑说明:--model指定 OM 文件路径,--input可以是单张图片或一个目录,--output是推理输出结果保存目录。运行结束后,正常情况会输出模型推理耗时和输出张量信息。如果这一步就报错,说明 OM 本身有问题,先回头检查 ATC 参数和 AIPP 配置,不要带病进业务代码。

输出是二进制文件,怎么判断结果对不对?用工具把输出数据按模型输出格式解析出来,画框对比原图。检测模型输出一般包含 NMS 之后的目标框坐标、置信度和类别。如果检测框全是乱的,或者所有人脸都没框出来,基本可以锁定是预处理参数问题。这一步虽然枯燥,但能帮你省下后面联调时的大量抓瞎时间。

4.4 后处理与轻量化:NMS 放哪跑,yolov5s 还能怎么压

检测模型转换完成后,ONNX 里的 NMS 后处理算子通常不会进 OM,也不会跑在 NPU 上。常见做法是让模型输出原始检测结果,然后在 CPU 端做解码和 NMS。这也是板端代码的一部分,后面第 5 章会碰到。如果你发现模型输出的原始数据量很大,需要手动解析 anchor 信息,别慌,这是正常现象。

性能不够的时候,方向有两个:第一个是降低输入分辨率,把 640x640 降到 416x416,检测精度会有轻微损失但推理时延能降 30% 以上;第二个是用 ATC 的 int8 量化功能,前提是手里有足够的校准数据。yolov5s 本身已经是轻量模型,做门禁场景在 310 上的余量是够的,正常跑 640 分辨率、25 帧率没有压力。真正需要优先优化的是识别模型的输入裁剪和特征比对逻辑,这些 CPU 活容易成为瓶颈。

5. 推理代码与门禁联调的七个常见坑:从 RTSP 拉流到 GPIO 开锁

5.1 RTSP 拉流与 DVPP 硬解码:为什么 OpenCV 直接读会卡

很多第一次上 Atlas200DK 的人会习惯性用 OpenCV 的 VideoCapture 去读摄像头 RTSP 流,结果发现帧率上不去、CPU 占用拉满。原因不难理解:OpenCV 走的是 CPU 软解,一路 1080p 的 H.264 流就吃掉大半 CPU,剩下的算力再跑检测和识别,系统就卡死了。正确做法是把视频流解码交给 DVPP 硬解单元。

常见做法是先用 FFmpeg 拉流,把 H.264 裸流取出来,再喂给 DVPP 的 VDEC 模块解码,解码后的 YUV 数据可以直接作为 AIPP 的输入。这里给一个验证 RTSP 流的命令,用来确认摄像头的编码格式和分辨率:

# 在开发机或板端执行,查看摄像头流的信息 ffprobe rtsp://user:password@192.168.1.64:554/stream1

逻辑说明:ffprobe会输出视频流的编码格式、分辨率、帧率等关键信息。看到h264编码就没问题;如果显示hevc(H.265),后面 DVPP 解码时要确认固件是否支持对应格式,不支持就得去摄像头后台切成 H.264 编码。分辨率建议控制在 1080p 以内,DVPP 的解码能力有限,超过规格会丢帧或花屏。

5.2 加载 OM 与执行推理:ACL 接口的最小可跑骨架

板端推理代码基于 ACL(Ascend Computing Language)接口,最小可跑骨架就四步:初始化、设置设备、加载模型、执行推理。下面给一个加载检测模型的 C++ 骨架:

#include "acl/acl.h" int main() { // 1. 初始化 ACL,加载驱动相关配置 aclInit(nullptr); // 2. 设置当前进程使用的设备,0 表示第一张板卡 int32_t deviceId = 0; aclrtSetDevice(deviceId); // 3. 创建 context,推理必须挂在 context 上执行 aclrtContext context = nullptr; aclrtCreateContext(&context, deviceId); // 4. 加载 OM 模型 uint32_t modelId = 0; aclmdlLoadFromFile("face_det.om", &modelId); // 5. 把输入数据的 buffer 绑定到模型输入描述符 // inputData 指向一帧图像数据,inputSize 是字节数 aclDataBuffer* inputBuf = aclmdlCreateDataBuffer(inputData, inputSize); aclmdlInput* input = aclmdlCreateInput(); aclmdlSetInputData(input, 0, inputBuf); // 6. 执行推理 aclmdlOutput* output = aclmdlCreateOutput(); aclmdlExecute(modelId, input, output); // 结束后按相反顺序释放资源,这里省略 return 0; }

逻辑说明:aclInit是全局初始化,必须在任何其他 ACL 调用之前;aclrtSetDevice指定进程绑定的设备;aclrtCreateContext创建执行上下文,后续模型加载和推理都依赖这个 context。aclmdlLoadFromFile把 OM 文件加载进设备内存,返回一个modelId句柄。执行推理时,先把输入图像的物理地址包成aclDataBuffer,再绑定到输入描述符,最后aclmdlExecute触发 NPU 计算。

参数说明里最容易忽略的是inputData的来路。如果是走 DVPP 解码出来的数据,它是一块设备内存地址,CPU 不能直接读;如果是用 CPU 读图再拷到设备,要确保内存是昇腾专用申请的内存,不能是普通的 malloc 数据直接传。用错内存类型,推理结果要么全零,要么程序直接崩溃。这个骨架部件虽然短,但每一行都对应一个最基础的坑。

5.3 GPIO 控制继电器开锁:电平、脉冲宽度和安全逻辑

识别通过后,最后一步是控制 GPIO 拉高电平,驱动外部继电器模块开锁。常见做法是用 sysfs 接口操作 GPIO,虽老但简单直接:

#include <fcntl.h> #include <unistd.h> void unlock_once() { // 导出 GPIO66,按板卡原理图选择实际引脚 int export_fd = open("/sys/class/gpio/export", O_WRONLY); write(export_fd, "66", 2); close(export_fd); // 设置为输出模式 int dir_fd = open("/sys/class/gpio/gpio66/direction", O_WRONLY); write(dir_fd, "out", 3); close(dir_fd); // 写高电平触发继电器 int val_fd = open("/sys/class/gpio/gpio66/value", O_WRONLY); write(val_fd, "1", 1); usleep(1000 * 1000); // 保持 1 秒,让门锁弹开 write(val_fd, "0", 1); // 拉低电平,释放继电器 close(val_fd); }

逻辑说明:这段代码先导出 GPIO 节点,这是 Linux 下操作 GPIO 的标准流程;随后把引脚方向设为输出;写1触发继电器吸合,延时 1 秒后写0释放。GPIO66 只是示例,具体编号要查 Atlas200DK 的 40Pin 排针原理图,不同版本可能不一样。

参数说明里两个关键点:一是脉冲宽度——开锁保持时间一般 500ms 到 2s 之间,太短门锁弹不开,太长继电器线圈持续通电会发热甚至烧毁;二是继电器驱动电路最好加续流二极管,否则断电瞬间的反向电动势可能打坏 GPIO 引脚。另外,开锁动作要放在独立线程里做,别阻塞主推理循环,否则门禁会变成“开一次锁卡几秒”。

5.4 排查清单:五个真实踩坑记录

坑 1:ATC 转模型报错,算子不支持现象:转换到一半弹出类似“unsupported operator”的报错信息,模型文件位置都不确定。 原因:ONNX 里使用了昇腾当前版本不支持的算子,常见于 Focus、部分自定义激活函数。 解决:先用网络可视化工具打开 ONNX 检查结构,把不支持的算子替换成等价实现,比如 Focus 可以用 slice+concat 重写,然后再导出 ONNX。这个坑在转换老版本 YOLOv5 权重时出现概率很高。

坑 2:OM 加载失败,提示模型文件无效现象:aclmdlLoadFromFile返回错误,日志里写“model file is invalid”。 原因:OM 文件是在另一套 CANN 版本下转换的,版本不兼容;或者--soc_version填错,比如 310 的板子用了 710 的配置。 解决:确认板端 CANN 与 ATC 工具版本一致,重新转换 OM。不要试图找“兼容模式”,直接重转最快。

坑 3:推理输出全零或纯随机数现象:模型能跑,但输出张量数据全是 0,或者完全不符合预期。 原因:输入数据没正确拷贝到设备内存,或者 AIPP 的色序/均值配置错乱。 解决:先用 msame 验证 OM,确认模型本身没问题;再回头查代码里aclDataBuffer绑定的内存地址是否来自 DVPP 或正确的设备内存申请接口。色序排查最直接的方法是把送入 AIPP 的图保存下来,肉眼确认是不是正常的人脸图。

坑 4:RTSP 画面花屏或黑屏现象:解码出来的图像色彩不对、有马赛克,或者直接黑屏。 原因:摄像头编码格式不是 H.264,常见是 H.265;或者码流的分辨率超过 DVPP 解码能力上限。 解决:用ffprobe看流信息,确认编码格式和分辨率。去摄像头后台把主码流切成 H.264,或者换到子码流试试,子码流一般分辨率较低,解码压力小很多。

坑 5:人脸识别门禁机频繁误开锁现象:注册库里没有的陌生人,偶尔也能触发开锁动作。 原因:相似度阈值设得太低,且没有做人脸质量过滤,模糊的、侧脸的、光照极差的人脸也被拿去比对。 解决:调高阈值只是第一步,更可靠的是加“两次命中再开门”策略和模糊检测,具体做法在第 6 章展开。门禁场景安全优先,宁可漏开也不要误开。

6. 让误识别率降下来的三个实践:阈值、质量过滤与重试机制

6.1 先给检测框做人脸质量过滤

识别模型对输入人脸的质量极其敏感。一张模糊到 30 分的人脸,识别模型照样能吐出一个特征向量,但那个向量和注册库里的特征根本对不上,也会出现“谁都像又谁都不像”的尴尬结果。常见做法是在送入识别前先做质量判断:拉普拉斯方差衡量清晰度,亮度均值衡量曝光,人脸框大小衡量距离。质量不合格的帧直接丢弃,不进入比对流程。下面是一个清晰度判断的 Python 片段,方便快速验证阈值手感:

import cv2 def face_quality_ok(roi_gray, blur_threshold=30): # 拉普拉斯方差:值越小越模糊 lap_var = cv2.Laplacian(roi_gray, cv2.CV_64F).var() return lap_var > blur_threshold

逻辑说明:cv2.Laplacian计算图像二阶梯度,方差越大表示边缘越锐利、画面越清晰。blur_threshold是经验值,暗光环境下可能误杀,需要按实际摄像头位置标定。这个函数的作用是在比对前把低质量人脸挡在门外。

6.2 识别结果别只比一次:两次命中再开门

单帧比对天然不稳定,光照抖动、摄像头噪点、人脸微动作都会让相似度涨落。我一般会加一个两帧确认逻辑:连续两帧或三帧都匹配到同一个人,且相似度都超过阈值,才触发开锁。这个策略对误开锁的抑制效果非常明显,代价只是多等一帧的时间,对门禁场景完全可以接受。实现上用一个临时缓存保存上一帧的识别结果,当前帧结果与上一帧做 ID 一致性判断即可。

6.3 特征归一化与阈值标定

最后说一个容易被忽略的细节:特征向量必须做 L2 归一化再算余弦相似度,否则不同样本的向量长度差异会直接破坏阈值的全局可比性。注册库里的特征和实时提取的特征都要过同一套归一化流程,阈值才有意义。标定阈值时,采集 20 个以上真人和陌生人的样本,画出相似度分布,取两类分布之间的分界点,而不是拍脑袋填一个 0.6。

这套门禁系统我最开始把阈值调成 0.4,熟人刷脸很顺,但陌生人误开概率也上来了;调到 0.5 又开始漏开。后来把质量过滤、两帧确认、归一化三件事都做齐了,阈值反而可以稳定在一个区间内不再纠结。门禁这种场景,最重要的教训就是:让人等半秒可以,让不对的人进去不可以。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 1:05:33

Crux 2.0发布:LinkBoy十三周年特别版,图形化到文本编程的桥梁

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:05:33

STM32F1驱动DHT11温湿度传感器开发实战:从入门到排坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:04:51

USB PD与Type-C全解析:从快充协议到OTG线与数据线区别

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:04:49

北斗短报文+4G双模通信:破解渗压计野外无信号难题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:04:14

恒模算法盲均衡MATLAB实现:从原理到参数调试实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:03:45

基于HC32F334的3kW两相交错全桥LLC数字电源设计解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华