简介一份面向毕业设计、课程设计与期末大作业场景的Python人脸识别系统项目基于Django搭建Web后端整合OpenCV、face_recognition与Keras等库实现了人脸检测、特征提取、比对识别与后台管理等功能覆盖从数据处理、模型调用到页面展示的完整开发链路。压缩包内共158个文件包括17个Python源码文件、22个JavaScript脚本、7个HTML页面、6个CSS样式以及用于界面演示的GIF动图、训练好的HDF5模型权重和项目操作说明文档整体大小约14.87MB目录划分清晰便于定位前端、后端与模型资源。项目附带详细操作说明可直接运行与二次开发既能支撑高校人脸识别课程设计、毕业设计答辩也可作为计算机视觉与模式识别方向的学习案例帮助理解Django与深度学习模型的实际结合方式目录中还包含MD说明、配置文件等辅助内容。目前该资源已有1926人学习浏览。1. 课程设计整体思路与选型逻辑这份基于 Python OpenCV Django 的人脸识别系统源码包是我整理的一个比较完整的课程设计项目。它不只是一堆零散脚本的堆砌而是把“人脸采集 → 模型训练 → 实时识别 → Web端管理”这条完整链路都打通了。如果你正在做计算机、软件工程、人工智能方向的课程设计或毕业设计这个项目源码加上配套的项目说明文档基本可以直接拿来复现、二次开发或者作为答辩时的技术支撑材料。先花点篇幅聊聊技术栈选型的问题。很多人一提到人脸识别第一反应就是上深度学习的模型比如 FaceNet、ArcFace 这类。但在课程设计这个场景下我建议你先冷静一下。课程设计的关键是什么是逻辑自洽、流程完整、代码可解释同时在自己机器上能跑得起来。深度学习模型虽然在复杂场景下精度更高但依赖环境复杂、训练耗时而且在答辩时如果被问到原理一时半会解释不清楚反而容易丢分。那 OpenCV 自带的 Haar 级联分类器 LBPH局部二值模式直方图算法就非常适合这类项目。它有几个实打实的优势一是环境依赖简单pip install opencv-python就搞定二是算法原理相对容易讲清楚LBPH 是通过提取人脸局部的纹理特征构建直方图来做比对的答辩时画几张图就能说明白三是计算量小CPU 上就能实时跑不需要 CUDA 这样的硬件门槛。Django 的角色则是把底层的识别能力“包装”成用户能操作的 Web 服务。课程设计最怕什么最怕功能做了一堆但展示不出来。Django 的 MTV 架构天然适合搭一个带前端页面、数据库后台和路由控制的完整应用。你可以在网页上注册用户、上传照片再通过摄像头实时调取识别结果这种“前后端交互完整闭环”的体验感对于课程设计的评分来说是很加分的。我从这个项目里整理出来的源码结构大概是这样的核心的采集脚本负责用摄像头抓取人脸样本训练脚本负责生成模型文件识别模块实时比对画面中的人脸然后 Django 作为 Web 框架把识别结果、用户管理、考勤记录或门禁记录全部串起来。整套东西麻雀虽小但五脏俱全。2. 环境准备与依赖安装2.1 开发环境版本配置这个项目对环境的要求并不苛刻但版本坑还是有一些的。我在实际搭建过程中踩了不少坑这里直接给你一套验证过可以正常跑的版本组合依赖项验证版本说明Python3.8 ~ 3.10建议 3.8 或 3.93.10 个别库有兼容问题OpenCV-Python4.5.x ~ 4.8.x不要装 4.9 以上开发版API 变动较大Django3.2 LTS 或 4.1 LTSLTS 版本稳定资料多NumPy1.21 ~ 1.24注意与 Python 版本匹配dlib可选19.22.0用于人脸检测当前项目非必需可选装有一个点需要特别提醒OpenCV 的cv2.face模块LBPH 人脸识别器所在的位置需要额外安装opencv-contrib-python包。很多人只装了opencv-python结果一import cv2.face就报错“module cv2 has no attribute face”卡在这一步半天都过不去。2.2 安装过程实操记录我建议你用一个干净的虚拟环境来装避免把系统全局 Python 环境搞乱。用virtualenv或 Python 自带的venv都行# 创建虚拟环境 python -m venv face_env # 激活环境Windows face_env\Scripts\activate # 激活环境Linux / macOS source face_env/bin/activate # 升级 pip 并安装依赖 pip install --upgrade pip pip install opencv-python opencv-contrib-python pip install django4.1.7 numpy1.24.3装完之后可以快速验证一下import cv2 import django import numpy as np print(cv2.__version__) # 4.8.0 等 print(django.get_version()) print(cv2.face.LBPHFaceRecognizer_create()) # 验证 face 模块可用如果第三条不报错说明opencv-contrib-python装对了。这块是整个环境准备中最容易翻车的地方能跑通基本就稳了一半。3. 人脸识别核心模块的实现拆解3.1 人脸数据采集流程人脸采集是整个系统的数据源头这一步做不好后面训练出来的模型精度肯定会受影响。核心思路是用摄像头逐帧捕捉画面通过 OpenCV 的 Haarcascade 检测器框出脸部区域然后裁剪成固定尺寸的灰度图保存到以“用户编号”命名的文件夹下。import cv2 import os # 加载 Haar 级联人脸检测器 face_cascade cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) # 打开摄像头 capture cv2.VideoCapture(0) # 用户编号作为文件夹名例如 1、2、3... user_id input(请输入用户编号如 1、2、3) save_dir f./dataset/{user_id} os.makedirs(save_dir, exist_okTrue) count 0 while True: ret, frame capture.read() if not ret: break gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces face_cascade.detectMultiScale( gray, scaleFactor1.1, minNeighbors5, minSize(100, 100) ) for (x, y, w, h) in faces: # 画出人脸框方便使用者调整角度和位置 cv2.rectangle(frame, (x, y), (x w, y h), (0, 255, 0), 2) face_roi gray[y:y h, x:x w] face_resized cv2.resize(face_roi, (200, 200)) cv2.imwrite(f{save_dir}/{count}.jpg, face_resized) count 1 print(f采集进度: {count}) cv2.imshow(Face Capture, frame) if cv2.waitKey(1) 0xFF ord(q): break if count 100: # 每个人默认采集100张样本 break capture.release() cv2.destroyAllWindows()实操经验采集样本时尽量多换几个角度和表情——抬头、低头、左右侧转、微笑、严肃这样训练出来的模型对不同姿态的鲁棒性会更理想。我自己试过只在一个固定角度采集的样本实际识别时稍微换个角度识别率就明显掉下来了。另外注意采集环境的光线最好在自然光充足且均匀的室内环境避免顶光直射造成脸部阴影过重。3.2 LBPH 模型训练原理与参数调优说到训练我需要花点篇幅把 LBPH 的原理讲透。LBPH 全称是 Local Binary Pattern Histogram核心思想分三步第一步把图像划分为若干小单元格例如 8x8 的网格。第二步对每个像素点与其周围像素比较灰度值大小大于邻域中心记作 1小于记作 0这样就会得到一个二进制序列转换成十进制就是该像素的 LBP 值。第三步对每个网格内的所有 LBP 值统计直方图把所有网格的直方图拼接起来就形成了一张人脸的特征描述子。这么做的妙处在于LBP 值只关注像素之间的相对大小关系而不是绝对灰度值所以它对光照变化有一定的不敏感性。当然它的短板也很明显——对大幅度姿态变化和遮挡比较敏感这也是为什么前面强调采集样本时要多角度采集。训练代码很简洁OpenCV 把底层的训练和预测都封装好了import cv2 import os import numpy as np recognizer cv2.face.LBPHFaceRecognizer_create() faces, labels [], [] for user_id in os.listdir(./dataset): user_path f./dataset/{user_id} if not os.path.isdir(user_path): continue for img_name in os.listdir(user_path): img_path f{user_path}/{img_name} img cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) faces.append(img) labels.append(int(user_id)) # 训练模型并保存 recognizer.train(faces, np.array(labels)) recognizer.save(./models/trainer.yml) print(模型训练完成)这里有几个可以直接抄作业的经验第一图片统一尺寸。我上面采集时 resize 到 200x200训练时保持同样尺寸否则 OpenCV 内部会强行缩放但效果不如统一尺寸来得稳定。第二识别置信度的阈值设置。predict()方法返回两个值——标签和置信度。置信度越低代表与训练样本的匹配度越高。我实测下来的参考范围是小于 50 属于匹配度非常高50~80 属于可接受范围大于 80 基本就完全不匹配了。你可以按这个标准设置阈值来控制识别的严格程度。第三数据均衡。每个用户尽量采集相同数量的样本万一某个用户只采集了 10 张而其他人都是 100 张模型会被“带偏”训练出来的分类边界会明显偏向样本多的那一方。3.3 实时识别模块的实现细节实时识别就是把训练好的模型加载起来对摄像头每一帧画面做检测和比对。这个流程在逻辑上并不复杂但有两个细节要特别注意一是视频帧要转成灰度图后再传给识别器这和采集、训练阶段的预处理保持一致二是要有一个“锁定机制”来避免同一张脸在连续的几十帧里被反复识别、记录多次。比如设定一个冷却时间或者记录上一次识别的时间戳间隔 5 秒之后再允许新的识别记录写入数据库。import cv2 import time face_cascade cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) recognizer cv2.face.LBPHFaceRecognizer_create() recognizer.read(./models/trainer.yml) user_names {1: 张三, 2: 李四, 3: 王五} last_recognized_time 0 capture cv2.VideoCapture(0) while True: ret, frame capture.read() if not ret: break gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces face_cascade.detectMultiScale(gray, 1.1, 5, minSize(100, 100)) for (x, y, w, h) in faces: face_roi gray[y:y h, x:x w] face_resized cv2.resize(face_roi, (200, 200)) label, confidence recognizer.predict(face_resized) # 置信度越低匹配度越高我这里设定 80 为阈值 if confidence 80: name user_names.get(label, Unknown) draw_color (0, 255, 0) now time.time() # 冷却时间 5 秒防重复识别 if now - last_recognized_time 5: print(f识别结果: {name}, 置信度: {confidence}) last_recognized_time now else: name Unknown draw_color (0, 0, 255) cv2.rectangle(frame, (x, y), (x w, y h), draw_color, 2) cv2.putText(frame, name, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, draw_color, 2) cv2.imshow(Face Recognition, frame) if cv2.waitKey(1) 0xFF ord(q): break capture.release() cv2.destroyAllWindows()4. Django Web 集成与业务逻辑闭环4.1 Django 项目结构与数据模型设计光有本地摄像头识别还不够课程设计要想拿高分一定要体现“系统化”和“业务闭环”。我这里的做法是用 Django 把整个识别流程包装成一个带用户管理、识别记录查询和后台管理的 Web 系统。简单来说前端页面负责录入用户、上传照片Django 后台负责把新用户的照片写入数据集文件夹并重新训练模型识别页面调用摄像头实时识别再把结果写入数据库最后提供一个记录查询页面展示每一天的识别历史。先看数据模型这是整个 Web 系统的地基from django.db import models class User(models.Model): user_id models.IntegerField(uniqueTrue, verbose_name用户编号) name models.CharField(max_length50, verbose_name姓名) photo_count models.IntegerField(default0, verbose_name照片数量) created_at models.DateTimeField(auto_now_addTrue, verbose_name创建时间) class Meta: verbose_name 用户信息 verbose_name_plural verbose_name def __str__(self): return self.name class RecognitionLog(models.Model): user models.ForeignKey(User, on_deletemodels.CASCADE, verbose_name用户) image models.ImageField(upload_tologs/, nullTrue, blankTrue, verbose_name抓拍照片) confidence models.FloatField(verbose_name置信度) recognized_at models.DateTimeField(auto_now_addTrue, verbose_name识别时间) class Meta: verbose_name 识别记录 verbose_name_plural verbose_name def __str__(self): return f{self.user.name} - {self.recognized_at}这里的RecognitionLog表是把识别结果落库的关键后面所有“考勤记录”、“访问记录”之类的扩展功能都可以基于这张表来做。我用外键把每条记录关联到具体的用户上这样查询会非常方便。4.2 视图函数与识别流程串联Django 的视图层是整个业务的调度中心。用户在前端页面上传照片后视图函数要做的事包括把照片保存到临时目录 → 用 OpenCV 检测人脸并裁剪 → 更新采集数据集 → 删除旧的模型文件 → 重新训练 → 返回结果给前端。import os import cv2 from django.shortcuts import render, redirect from django.conf import settings from .models import User, RecognitionLog BASE_DIR settings.BASE_DIR DATASET_DIR os.path.join(BASE_DIR, dataset) MODEL_PATH os.path.join(BASE_DIR, models, trainer.yml) def register_user(request): if request.method POST: user_id request.POST.get(user_id) name request.POST.get(name) photo request.FILES.get(photo) # 省略部分参数校验逻辑... # 保存上传的照片并用 OpenCV 检测人脸 temp_path os.path.join(BASE_DIR, temp, photo.name) with open(temp_path, wb) as f: for chunk in photo.chunks(): f.write(chunk) face_cascade cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) img cv2.imread(temp_path) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) faces face_cascade.detectMultiScale(gray, 1.1, 5, minSize(100, 100)) user_dir os.path.join(DATASET_DIR, str(user_id)) os.makedirs(user_dir, exist_okTrue) for i, (x, y, w, h) in enumerate(faces): face_roi gray[y:y h, x:x w] face_resized cv2.resize(face_roi, (200, 200)) cv2.imwrite(f{user_dir}/{i}.jpg, face_resized) # 更新用户表并重新训练模型 user_obj, created User.objects.update_or_create( user_iduser_id, defaults{name: name, photo_count: len(faces)} ) retrain_model() # 这个函数内部会遍历 dataset 并调用 recognizer.train return redirect(recognition_list) return render(request, register.html)这里有个容易被忽视的坑Django 的update_or_create返回的是(对象, 是否新建的布尔值)新手经常会漏掉这个解包操作导致数据写入失败。另外训练模型是 CPU 密集型操作如果一次上传的人脸照片太多HTTP 请求可能会超时建议在视图函数中先返回“正在处理”的提示使用异步任务比如 Celery来做模型重训练但在课程设计阶段可以先用同步方式凑合毕竟数据量不大。另外一个很实用的小技巧是RecognitionLog里我预留了image字段用来保存识别时的抓拍截图。这可以让你的系统在识别记录页面展示“谁在什么时候出现过”的照片证据这个功能在答辩演示时非常抓眼球比单纯显示文字记录要有说服力得多。4.3 前端页面与模板渲染Django 模板这一层我不建议做太复杂的页面因为课程设计的重点在识别逻辑而不是前端炫技。但页面至少要包含三个模块用户注册页采集/上传照片、实时识别页可以嵌入视频流、记录查询页。!-- recognition.html 核心片段 -- div classcontainer h3实时人脸识别/h3 video idvideo autoplay muted playsinline/video canvas idcanvas styledisplay:none;/canvas button idcaptureBtn开始识别/button div idresult/div /div script const video document.getElementById(video); const canvas document.getElementById(canvas); const ctx canvas.getContext(2d); // 需要 HTTPS 或 localhost 下浏览器才允许调用摄像头 navigator.mediaDevices.getUserMedia({ video: true, audio: false }) .then(stream { video.srcObject stream; }) .catch(err { console.error(摄像头调用失败: , err); }); document.getElementById(captureBtn).addEventListener(click, () { canvas.width video.videoWidth; canvas.height video.videoHeight; ctx.drawImage(video, 0, 0, canvas.width, canvas.height); const base64Data canvas.toDataURL(image/jpeg); // 通过 Ajax 发送给 Django 后端进行识别 fetch(/api/recognize/, { method: POST, headers: {Content-Type: application/json}, body: JSON.stringify({ image: base64Data }) }) .then(res res.json()) .then(data { document.getElementById(result).innerText data.name ? 识别结果: ${data.name} : 未识别到人脸; }); }); /script这个设计其实是在做“自动化考试”把浏览器的视频帧通过 Ajax 传到 Django 后端由后端的 OpenCV 识别器返回结果再渲染到页面上。有人认为 OpenCV 在 280x360 的灰度图上做 LBPH 识别只要几十毫秒这样的链路完全可以在 CPU 上跑通不会有什么性能压力。5. 部署疑难杂症与排错速查5.1 摄像头调用的常见问题这里整理了我在实际开发和部署中遇到的几个高频问题直接贴出排查思路和解决方案。问题现象可能原因解决方案cv2.VideoCapture(0)返回 False摄像头被其他程序占用或驱动未安装先关闭可能占用摄像头的软件如微信、钉钉、OBS再运行检测设备管理器确认驱动正常浏览器摄像头黑屏浏览器权限未放行或域名不是 HTTPS/localhost在浏览器地址栏左侧点击“网站设置”允许摄像头权限本地调试务必用 localhost 访问module cv2 has no attribute face只安装了 opencv-pythonface 模块在 contrib 包里pip install opencv-contrib-python后重启内核LBPHFaceRecognizer_create报 AttributeErrorOpenCV 版本过旧或过新回退到 4.5~4.8 版本API 最稳定Django 部署后静态文件 404未执行 collectstatic修改 settings.py 的 STATIC_ROOT 后运行python manage.py collectstatic5.2 识别准确率不理想时的调优方向如果你发现识别率总是差强人意先不要急着换算法按下面这个优先级去排查第一优先检查训练样本质量。样本数量太少比如每个人只有 10 张、光线差异过大、照片角度过于单一都会严重影响 LBPH 的表现。先把样本补足到 100 张以上保证多角度、多表情、光线均匀。第二优先检查人脸检测框的准确性。Haar 级联分类器在侧面脸、低头场景下经常检测不到或框选不准。可以调整detectMultiScale的参数比如把scaleFactor从 1.1 调整到 1.05更精密的缩放扫描检测更准但更慢把minNeighbors从 5 降低到 4允许更多的候选框通过观察效果变化。第三优先检查预处理。在送入识别器之前除了灰度化还可以做直方图均衡化cv2.equalizeHist来增强对比度减少环境光照的影响。这个操作对 LBPH 的提升非常明显而且代价极小face_roi gray[y:y h, x:x w] face_roi cv2.equalizeHist(face_roi) # 直方图均衡化 face_resized cv2.resize(face_roi, (200, 200))第四优先检查置信度阈值是否合理。如果系统经常把不是用户A的人识别成用户A说明阈值设得太宽松了调低一些比如从 80 降到 60如果经常识别出“Unknown”说明阈值设得太严格稍微放宽一点。5.3 Django 运行时的问题Django 在开发环境跑得很顺畅但一部署到服务器上就各种问题。这里说两个最常见的一个是ALLOWED_HOSTS。Django 4.x 默认是不运行非 localhost 域名访问的如果你用服务器 IP 访问页面需要在settings.py里把 IP 加进去ALLOWED_HOSTS [*] # 课程设计阶段直接放行所有生产环境千万别这样写另一个是数据库迁移。每次修改了models.py之后必须依次执行两条命令python manage.py makemigrations python manage.py migrate经常有人改了模型不迁移就直接运行结果报no such table的错误其实数据库里根本没建好表。6. 课程设计答辩的展示思路最后聊点题外话关于课程设计答辩时的展示角度。代码能跑起来只是基础分要让老师觉得你的项目有深度展示时应该强调三个点第一系统架构的完整性。从数据采集、模型训练、实时识别到 Web 端的业务记录形成了完整的闭环不是一个孤立的算法 demo。可以画一张简单的系统架构图说明每一层的作用和接口关系。第二工程化思维。比如在实时识别中加入 5 秒冷却时间防止记录重复、在注册用户后自动重新训练模型、在数据库中用外键维护用户和识别记录的关联关系——这些细节虽然小但能证明你不只是会调库而是在认真考虑系统的健壮性。第三明确的改进方向。答辩老师经常问“你还能怎么优化”千万不要说“不知道”。你可以主动提出如果换成深度学习模型如 FaceNet可以提升复杂场景下的识别率但代价是更高的算力需求如果加入更多的样本增强旋转、缩放、亮度变换可以提高模型的泛化能力如果使用 Redis 做缓存可以提升并发场景下的响应速度。哪怕没有实际做过这些优化提出合理的技术路线也能证明你真的思考过。我自己在这个项目上写得最多的一段代码反而是采集脚本里那句print(f采集进度: {count})。为什么因为在实际操作中没有进度提示的时候你根本不知道摄像头对不对准了、有没有在正常保存图片。很多细节看着不起眼但只有真正动手跑过一遍才会知道哪一步最容易卡住。这个项目的源码里保留了这些“实战痕迹”拿来做课程设计的底子我觉得比直接抄一段只有核心算法的 demo 要实在得多。本文还有配套的精品资源点击获取