ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于Python+OpenCV+face_recognition的人脸识别门禁系统实现

基于Python+OpenCV+face_recognition的人脸识别门禁系统实现 简介这是一份基于Python的毕业设计人脸识别智能门禁系统项目面向本科及高职毕业设计、期末大作业和课程设计场景。源码带有注释系统已经调试可运行功能涵盖门禁管理、人脸识别等核心流程界面简洁操作直观适合新手部署、阅读与二次开发。资源包共262个文件体积约70.36MB文件类型以71个ts、37个vue前端页面和20个java后端源码为主另有SQL数据库脚本、jpg/png图片素材、mp4演示视频及各类工程配置文件可辅助理解前后端交互与运行效果便于按模块查阅。目前已有146人学习下载。包内目录结构清晰包含前端工程、后端代码、数据库配置和媒体素材覆盖从数据库设计到接口实现、页面展示的完整闭环读者可据此快速掌握项目框架、完成答辩讲解也可在此基础上扩展自己的毕业设计功能。1. 人脸识别智能门禁系统这个毕设选题为什么值得做人脸识别智能门禁系统这几年几乎成了毕业设计里的“网红选题”网上搜索能看到大量相关帖子但很多人下载回来才发现要么缺数据库、要么依赖装不上、要么代码跑不通真正能把摄像头打开、把真人脸认出来、再把开门记录写进数据库的成品系统并不多。这个基于Python的智能门禁项目核心用OpenCV加face_recognition做识别前端是Vue 3管理后台后端提供业务接口整体覆盖人脸录入、实时识别、开门控制、出入日志和考勤汇总这些毕业设计最关心的功能点。如果你是毕业设计或期末大作业要用Python做图像识别、物联网方向最值得关注的就是它代码带注释、前后端分离、工程化配置齐全拿到之后能照着看懂每一行而不是对着一个黑匣子瞎猜。整套东西拿到手能跑通、能顺着改就是它的核心价值。2. 人脸识别门禁系统架构与技术选型从摄像头画面到开门指令的完整链路2.1 三层架构识别服务、管理端、数据库各司其职先看整体架构。这个项目是一个典型的前后端分离结构前端是Vue 3后端是Python提供的API服务数据库用的是MySQL。访问控制场景里的数据流是这样的摄像头采集画面后传给识别模块识别模块把画面中的人脸检测出来提取特征向量再跟数据库里存好的注册特征做距离比对。比对通过后后端把“放行”指令返回给门控设备同时往access_log表里写一条记录。管理端负责的则是人的操作录入新用户、上传人脸照片、查看进出记录、统计考勤这些都是通过Vue页面调后端接口完成的。这个结构最大的好处是职责边界清楚。识别服务只负责图像处理和特征比对不掺和业务逻辑管理端只负责展示和调用不在前端放任何算法实现。这样你改登录页不会影响识别流程调识别参数也不会把页面搞挂。对于答辩来说这种分层能讲得很顺先画一张三层架构图再用数据流把每一层的输入输出说清楚评委基本就不会追问一些零碎的问题了。我拆项目时看了一下配置文件前端里有.env.development、tailwind.css、vue3.0和vue3.2的VSCode代码片段说明这个项目在开发时就是按规范的工程化流程来的。代码目录大致是后端Python源码负责启动识别服务和提供API接口前端Vue目录管理页面和样式数据库脚本单独放在sql文件里。2.2 识别链路检测、对齐、特征提取、比对四步人脸识别本身并不是一个单独的算法而是一条流水线。第一步是人脸检测从摄像头画面里把人脸的位置框出来。face_recognition库在这里默认用的是HOG特征加线性分类器画面中人脸不明显时也可以换成CNN模型速度会慢一点但更准。第二步是人脸对齐这一步在face_recognition库内部由shape_predictor_68_face_landmarks模型完成它定位双眼、鼻尖、嘴角等68个关键点然后通过仿射变换把人脸摆正消除头部倾斜的影响。第三步是特征提取。这一步把对齐后的人脸图输入到训练好的深度残差网络里输出一个128维的浮点向量。这个向量就是人脸的“数字指纹”同一个人在不同角度、不同光照下拿到的向量会接近不同人之间则差得比较远。第四步是特征比对把当前画面中提取到的特征向量跟数据库里所有注册用户的特征向量分别计算欧氏距离距离小于阈值就判定为同一个人。阈值在face_recognition里就是tolerance参数默认是0.6实际工程里一般会调到0.5到0.55之间更稳。2.3 技术选型为什么是Python OpenCV face_recognition Vue 3很多同学会问毕业设计人脸识别为什么不直接用OpenCV自带的LBPH或者上更重的DeepFace我的看法是这样LBPH算法实现简单但对光照变化非常敏感拍摄角度稍微偏一点识别率就拉胯答辩现场容易翻车。DeepFace、InsightFace这些框架效果好但依赖和模型文件都很重装上就得几个GB对一个毕设项目来说性价比不高。face_recognition库恰好是中间态底层用dlib的人脸检测和ResNet特征提取精度足够代码封装得非常友好两三行就能完成一次特征提取特别适合拿来快速验证方案。后端框架选Flask而不是Django也是合理的。这个项目本身没有大量复杂的业务页面API接口数量有限Flask轻量、路由直观写起来比Django简单很多。前端选Vue 3则是从管理后台场景考虑的Vue生态里的组件库可以直接拿来做表格和表单页面开发效率比原生JavaScript高一截。项目自带tailwind.css和iconfont.css说明前端样式是Tailwind加图标字体这种轻量组合不需要额外引入重型UI框架。模块技术选型主要作用前端Vue 3 Tailwind CSS管理后台、登录页、记录展示后端Python Flask业务API、识别流程编排识别OpenCV face_recognition图像采集、人脸检测、特征提取数据库MySQL用户信息、人脸特征、出入记录工程化VSCode片段、ESLint、EditorConfig代码风格统一、开发提效2.4 项目配置里藏着的信息从目录结构看设计习惯我解压这个项目后最先看的不是代码而是配置文件因为配置文件能反映一个项目的工程化程度。前端目录里放着.env.development这表示开发环境和生产环境的接口地址是分开配置的部署时不会因为改接口地址而手忙脚乱。.editorconfig和.eslintignore说明项目做了代码风格约束commit-msg说明提交代码时走的是规范提交的格式校验。这些细节单个看都不起眼但在毕业设计答辩中往“工程化实践”方向讲几句能明显拉开和其他只交了代码没交工程的同学的差距。提示mvnw.cmd看起来像Java Maven的包装脚本应该是某个辅助工具链的残留跟本项目Python运行没有依赖关系解压后不用管它。3. 环境配置与项目启动从零把这套人脸门禁跑起来3.1 Python环境准备与依赖安装这套系统的运行环境我建议用Python 3.8或3.9版本太新的Python在安装dlib时容易遇到编译兼容性问题。先把虚拟环境建好避免跟系统Python环境互相污染。python -m venv venv # Windows系统激活虚拟环境 venv\Scripts\activate # Linux/macOS系统激活虚拟环境 source venv/bin/activate虚拟环境建好之后接着安装依赖。项目根目录下通常会带requirements.txt直接一条命令装完pip install -r requirements.txt如果手头没有requirements.txt按这个列表自己装也可以pip install flask flask-cors pymysql opencv-python face_recognition numpy pillow这里说下几个关键依赖的作用flask是后端Web框架负责处理所有HTTP请求和响应flask-cors解决前后端分离下的跨域问题pymysql是Python连接MySQL的驱动opencv-python负责摄像头图像采集face_recognition就是人脸识别核心库它内部依赖dlib安装最耗时也最容易出问题。如果环境里同时有旧版本OpenCV和face_recognition建议装完后再验证一下版本兼容性。3.2 数据库初始化与连接配置数据库部分先在MySQL里创建一个空的数据库名字可以随意起比如face_access然后把项目里的SQL脚本导进去。SQL脚本一般就在代码压缩包的db目录或sql目录下里面有建库建表语句执行一下即可mysql -u root -p face_access.sql如果不想用命令行用Navicat或MySQL Workbench建表也一样。导完之后数据库里应该能看到三张核心表users用户表、access_logs出入记录表还可能有考勤相关的表。后端连接数据库的配置在config.py或app.py里无非是host、port、user、password、database这几项把它改成你自己的MySQL账号密码并确保charset设置的是utf8mb4否则后面中文会乱码。# config.py 中数据库连接配置示例 DB_CONFIG { host: localhost, user: root, password: 你的数据库密码, database: face_access, charset: utf8mb4, port: 3306 }3.3 后端识别服务启动后端服务是整个系统的核心启动前先确认摄像头是接好的。很多笔记本自带的摄像头索引是0外接USB摄像头可能是1如果启动后提示打不开摄像头先试一下把索引改成1。启动命令很简单python app.py如果一切正常控制台会输出类似“Running on http://127.0.0.1:5000”的信息。这时候系统已经在等待HTTP请求了。验证后端通没通可以浏览器直接访问一下接口地址或者用接口测试工具发一个GET请求能看到JSON响应就说明后端服务起来了。这里有几个容易出现问题的点如果是Windows系统摄像头的索引和访问权限可能会有问题。启动过程如果有报错优先看最后几行堆栈信息大部分情况是依赖缺失或数据库连接失败很少有真正复杂的逻辑错误。3.4 Vue管理端启动管理端是Vue 3项目启动前需要Node.js环境。建议用Node 16或18的LTS版本版本太新或太旧都可能出现依赖安装失败。在项目前端目录下执行npm install这一步会装前端的所有依赖网络状况不好的时候可能要几分钟。装完之后启动开发服务器npm run serve # 或者项目用的是Vite执行 npm run dev启动后浏览器访问http://localhost:5173Vite默认端口或http://localhost:8080Vue CLI默认端口就能看到登录页面了。前端访问后端接口的地址写在.env.development文件里如果后端跑在5000端口而前端的代理没有配置好就会看到接口请求报跨域错误。这时可以检查.env.development里的VITE_API_BASE_URL或VUE_APP_API_BASE_URL是否指向后端地址也可以检查vite.config.js里的proxy配置。3.5 首次刷脸全流程验证系统跑通后一定要完整走一遍“注册→识别→开门→记录”四步而不是只看到登录页就以为完成了。我第一次拆这类项目时就吃过这个亏页面打开了接口也能访问结果到了现场演示才发现摄像头根本调不动最后只能拿演示视频顶上去场面十分尴尬。完整的验证流程是这样的先在管理端登录进用户列表页面新增一个用户并上传一张清晰的正脸照片照片上传后后端会做一次人脸检测并提取特征存进数据库然后到门禁识别页面把摄像头对准自己的脸系统应该能识别出刚才注册的那张脸并显示放行动作最后回到记录列表确认刚才那条识别记录已经写进去了。这四个步骤全部通过才说明环境配置是完整的后面再改代码、调参数时才不会踩到环境坑。4. 核心功能模块与代码解读人脸注册、实时识别、出入记录怎么实现4.1 用户管理与注册模块从照片到特征向量入库用户注册是系统的起点也是人脸数据来源。注册流程说白了两件事把照片里检测到的face编码存下来并把用户姓名和这张脸绑定。后端接口一般是接收一个name字段和一张图片核心代码如下app.route(/api/user/register, methods[POST]) def register_user(): user_name request.form.get(name) image_data request.files.get(face_image) if not user_name or not image_data: return jsonify({code: 1, msg: 姓名和人脸图片不能为空}) # 将上传的图片读入内存并转成RGB image face_recognition.load_image_file(image_data) # 检测图片中的人脸位置默认使用HOG模型 face_locations face_recognition.face_locations(image, modelhog) if len(face_locations) 0: return jsonify({code: 1, msg: 未检测到人脸请正对摄像头重新拍摄}) if len(face_locations) 1: return jsonify({code: 1, msg: 检测到多张人脸请确保只有注册者本人入镜}) # 提取这段人脸对应的128维特征向量 face_encodings face_recognition.face_encodings(image, face_locations) encoding face_encodings[0].tolist() # 特征以JSON字符串形式存入数据库 cursor db.cursor() sql insert into users(name, face_encoding) values(%s, %s) cursor.execute(sql, (user_name, json.dumps(encoding))) db.commit() return jsonify({code: 0, msg: 人脸注册成功})这段代码里最值得注意的是最后的json.dumps(encoding)。128维特征向量是一个numpy数组不能直接存进MySQL的TEXT字段必须先序列化成JSON字符串读取时再反序列还原。注册时人脸检测的结果我要强调一下face_locations返回的是图片中所有人脸的位置如果一张照片里出现了两个人一定不能直接取第一张脸必须返回错误提示让用户重新拍。否则识别阶段会把一个用户绑定到两张脸上逻辑直接乱掉。4.2 实时识别与开门控制特征比对逻辑是核心识别接口是门禁系统的高频调用接口也是答辩时最容易被追问的部分。它做的事情是接收前端传过来的一帧画面检测人脸并提取特征然后和数据库里的所有注册特征逐一比对返回匹配结果。app.route(/api/access/verify, methods[POST]) def verify_access(): frame_file request.files.get(frame) if not frame_file: return jsonify({code: 1, msg: 未接收到图像帧}) # 读取帧并检测人脸 frame face_recognition.load_image_file(frame_file) face_locations face_recognition.face_locations(frame, modelhog) face_encodings face_recognition.face_encodings(frame, face_locations) if len(face_encodings) 0: return jsonify({code: 1, msg: 画面中未检测到人脸}) # 加载数据库中的所有注册用户特征 cursor db.cursor() cursor.execute(select id, name, face_encoding from users) rows cursor.fetchall() known_ids, known_names, known_encodings [], [], [] for row in rows: known_ids.append(row[0]) known_names.append(row[1]) known_encodings.append(np.array(json.loads(row[2]))) # 对画面中的每一张人脸进行比对 for encoding in face_encodings: distances face_recognition.face_distance(known_encodings, encoding) min_index int(np.argmin(distances)) min_distance float(distances[min_index]) if min_distance 0.55: user_id known_ids[min_index] name known_names[min_index] insert_access_log(user_id, name, min_distance, allow) return jsonify({code: 0, msg: 识别通过, user_id: user_id, name: name, distance: min_distance}) else: insert_access_log(0, unknown, min_distance, deny) return jsonify({code: 1, msg: 未识别请联系管理员, distance: min_distance}) return jsonify({code: 1, msg: 未检测到可识别的人脸})这里有一个很容易忽略的细节直接用face_recognition.compare_faces会返回一整个布尔数组但多个True匹配不一定是准确的那个人。我用的是np.argmin配合face_distance先找到距离最小的那一个再判断距离是否小于阈值。这样既保证了“取最匹配的人的姓名”又避免了compare_faces在阈值边界时出现多个True导致误开门的情况。tolerance取值0.55是我在室内光照下测过的经验值比库默认的0.6要严格一些能降低陌生人被放行的概率如果现场环境光照很差可以放宽到0.6但不要太高于这个值。4.3 出入记录与考勤日志数据结构设计出入记录模块本身不复杂关键是记录得完整、查起来方便。记录表至少需要这几个字段用户ID、姓名、验证时间、验证结果通过/拒绝、还有比对的距离。这样在管理端展示时可以按时间筛选、按姓名搜索还能把识别失败时的distance展示出来作为人工核验的依据。create table access_logs ( id int auto_increment primary key comment 记录ID, user_id int not null comment 用户ID0表示未识别人员, name varchar(50) not null comment 识别到的姓名未识别填unknown, distance float not null comment 最小特征距离越小越可信, status varchar(20) not null comment allow/deny, create_time datetime default current_timestamp comment 识别时间 ) engineInnoDB default charsetutf8mb4;考勤数据其实可以直接从access_logs里聚合出来统计某个用户当天第一条和最后一条记录就能得到上下班时间统计一天内status为allow的记录数就能判断是否有有效进出。我建议不要在access_logs上再加考勤字段保持日志表的纯净考勤结果另外用SQL聚合来算这样改动一条记录时不会影响已有统计逻辑。4.4 前端页面如何对接后端接口前端管理端里花时间最多的是用户列表页和识别页面。以用户列表页为例Vue组件里通常是先调用后端的用户列表接口把数据渲染成表格注册新用户时用上传组件把图片传上去// Vue 3 中注册用户的调用示例 async function handleRegister(formData) { const response await fetch(/api/user/register, { method: POST, body: formData // FormData对象包含name字段和faceImage文件 }) const result await response.json() if (result.code 0) { ElMessage.success(result.msg) } else { ElMessage.error(result.msg) } }前端调接口时最容易踩的坑是路径问题。开发环境前端跑在5173端口后端跑在5000端口直接用fetch(/api/...)会请求到前端自己的端口上。解决办法一般有两种要么在vite.config.js里配置proxy把/api前缀代理到后端地址要么把所有接口地址写成完整URL。.env.development文件里那个API地址变量就是干这个用的。确认一下前后端路径是否一致能省下不少跨域排查时间。提示前后端分离项目中几乎所有“接口通了但报错404”的问题都是请求路径和实际路由对不上检查顺序是路径前缀 → 端口 → 路由定义。5. 避坑指南人脸识别门禁最常见的五个坑与排查方法5.1 摄像头打不开或画面黑屏VideoCapture返回False现象后端启动正常但系统页面里摄像头区域一直是黑色或者控制台输出“摄像头打开失败”cap.read()时读取不到帧。原因常见的有三种。第一OpenCV默认调用的摄像头索引不对笔记本自带摄像头通常是0外接USB摄像头可能是1但部分笔记本反过来。第二Windows下OpenCV的VideoCapture在打开摄像头时会因为媒体框架冲突而失败。第三摄像头被其他程序占用比如Zoom、微信视频通话还开着。解决先写一个三行的脚本验证摄像头到底能不能被OpenCV读到import cv2 cap cv2.VideoCapture(0, cv2.CAP_DSHOW) # Windows下加CAP_DSHOW可减少兼容问题 print(摄像头打开:, cap.isOpened()) ok, frame cap.read() print(读取帧:, ok)如果返回False把代码里的0改成1再试一次如果两个都不行关掉所有可能占用摄像头的软件然后重插USB摄像头。还有一点要注意虚拟机里跑这个项目需要确保VMware或VirtualBox给虚拟机分配了USB摄像头设备。5.2 识别率忽高忽低同一人时过时不过现象按同一个人的照片注册后有时候一次就识别成功有时候连续试好几次都提示“未识别”跑着跑着又通过了像是玄学。原因人脸识别对光照和角度非常敏感。注册时传的是一张光照均匀的证件照实际识别时摄像头在暗光环境下特征向量距离会明显拉大。其次注册照片和识别画面的人脸姿态不一致比如注册是正面照识别的时候侧脸了过来68个关键点定位都会受影响。解决注册时尽量用现场摄像头实时拍摄的正脸照片不要上传手机里年代久远的老照片。如果项目支持多张照片注册同一人注册两张不同角度和光线的照片识别会稳很多。另一个可调项就是把识别接口里的tolerance从0.6降到0.55同时把检测模型从hog换成cnnCNN模型在低分辨率下的检测鲁棒性更高代价是单帧耗时增加但对门禁场景来说换来的稳定性更值。5.3 face_recognition依赖安装失败卡在dlib编译现象pip install face_recognition时在安装dlib的环节报错提示需要Visual Studio Build Tools、CMake或者直接出现“Failed building wheel for dlib”的红色报错。原因face_recognition的核心依赖dlib是一个C库在Windows上没有官方预编译wheelpip安装时只能现场编译源码。编译dlib需要完整的C编译工具链光有pip是不够的。解决第一个办法安装Visual Studio Build Tools时勾选“使用C的桌面开发”工作负载然后执行pip install cmake再回头装face_recognition。第二个更省事的办法在Anaconda环境下用conda install -c conda-forge dlibconda会直接下载编译好的二进制包绕开编译步骤。如果死活装不上也可以退而求其次用OpenCV的LBPH识别器替代face_recognition代码改动主要在特征提取部分但演示效果会打折扣不建议作为首选方案。5.4 中文姓名乱码或写入失败现象管理端新增用户后列表里的中文姓名显示成“”或者直接报错“Incorrect string value”。原因这是典型的字符集问题。MySQL表默认可能是latin1字符集存中文就会出问题。后端连接数据库时如果没有指定charsetutf8mb4连接本身的字符集也会不对。解决建表时明确指定编码已经建好的表可以改alter table users convert to character set utf8mb4 collate utf8mb4_unicode_ci;同时把后端数据库连接配置里的charset改成utf8mb4并且确认后端返回JSON时没有强制转义中文。Flask的jsonify默认就能返回中文但如果代码里用了json.dumps而没设置ensure_asciiFalse中文会变成\uXXXX的转义序列前端拿到后也能正常解析但排查问题时碰到乱码先按这三层顺序过一遍。5.5 重启系统后人脸数据丢失注册过的用户全部失效现象上午注册了几个测试用户中午重启了后端服务再打开识别页面发现所有注册用户都识别不出来了用户列表却是正常的。原因人脸特征只保存在了内存变量里。如果代码里用一个全局列表缓存了known_encodings每次启动时列表是空的只有进入识别流程才从数据库加载那按理说重启后也能加载回来。真正导致丢失的往往是注册接口把特征写进了数据库但加载逻辑没有从数据库读或者读的时候漏了解析JSON的步骤。解决确认注册时特征已经持久化到users表也就是能查到这个字段select face_encoding from users where nametest;再确认启动加载逻辑正确解析了JSON检查时在加载函数中打一行print(len(known_encodings))看重启后打印的数量对不对。如果输出是0说明加载逻辑没走到或SQL查询条件不对按这两步排查基本就能定位。6. 答辩加分技巧把毕设从“能跑”升级到“能讲清楚”6.1 演示脚本先定好注册、识别、异常三条线答辩现场最怕的是临时操作。我的做法是先写一份演示脚本把三个场景按顺序固定下来第一个场景演示正常注册新增一个用户并现场拍一张正脸照然后立即到识别页面刷脸开门第二个场景演示识别记录的可查性回到记录列表展示刚才那条allow记录顺便把识别出来的相似度距离指给评委看第三个场景演示异常处理让一个没注册过的人走到摄像头前系统返回“未识别”记录表里出现一条deny记录。这三个场景走完功能闭环就完整了。6.2 讲算法用“四步链路”检测、对齐、特征提取、比对答辩时被问到“你的人脸识别是怎么实现的”很多同学的答案都是“用了face_recognition库”。这样讲撑不住追问。换一种讲法先把检测、对齐、特征提取、特征比对四个阶段用一张流程图串起来然后重点讲特征提取这一步说明人脸被映射成128维向量比对时用欧氏距离作为相似度度量距离小于阈值就判定为同一个人。再补充一两个可调参数的实际经验比如tolerance取值和光照之间的关系评委就知道你是真的调试过这个系统而不是只跑了别人的代码。6.3 提前录一份备份演示视频这条是我自己的血泪教训。有一次我现场演示时主办方电脑的摄像头没有驱动折腾了五分钟都调不出画面最后只能硬着头皮口述功能。从那以后我每次答辩前都会提前录一份1分钟的功能演示视频放在U盘里和项目放一起遇到摄像头故障、光线太暗、设备不兼容这些情况直接播放视频顶上。视频里有完整的注册、识别、开门和记录展示画面配合口述讲解效果不会比现场差太多。开发文档里把技术架构、接口说明、部署步骤也整理成一份PDF跟演示视频一起放进交付包自己答辩时答案例顺手归档给导师也规范。希望帮到你。本文还有配套的精品资源点击获取
返回列表