ARTICLE DETAIL

资讯详情

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

基于OpenCV和Django的人脸识别系统课程设计指南

基于OpenCV和Django的人脸识别系统课程设计指南 简介基于Python、OpenCV、Django与人脸识别库开发的人脸识别系统完整课程设计源码适合高校学生完成图像处理、Web开发与人工智能综合项目时参考。项目已获导师指导并通过评审属于97分高分大作业代码完整、可直接下载运行。压缩包共130个文件包含19个Python源码模块、大量jpeg/png图片样本、pyc编译文件、sqlite3数据库、pb模型及TensorFlow数据文件等总计22.62MB目录结构清晰便于理清人脸检测、特征提取、模型加载与Django后端交互的实现逻辑。目前已有883人学习使用该资源。通过这套源码读者能够快速复现人脸识别全流程学习如何整合OpenCV图像处理、人脸库算法与Django框架搭建可交互系统同时获得课程设计报告的落地参考也可作为毕业设计或综合实训的模板是同类项目中少有的高完成度资料。1. 这门人脸识别课程设计到底在做什么一个能从浏览器完成注册和识别的完整系统先说一个反直觉的结论一套基于 Python、OpenCV、Django 和人脸识别库常见为 face_recognition 或 OpenCV 内置 LBPH做出来的人脸识别系统翻车最多的往往不是识别算法而是整套流程没打通。很多课程设计源码包里OpenCV 检测人脸、识别库做特征比对都能单独跑通结果到了 Django 这层照片传不进去、识别结果回不到页面上最后答辩只能开命令行硬凑。这套系统的目标是打通「上传或采集人脸 → 检测与特征提取 → 数据库比对 → Web 页面返回结果」的完整链路让你本地能跑、答辩可演示。适合正在做人脸识别课程设计的本科同学以及想把单脚本识别改造成 Web 服务、方便二次开发的从业者。2. 先看懂这套系统的骨架三个库的角色分工与识别主流程这套系统看着像三块技术拼在一起实际拆开就三层OpenCV 负责图像输入和预处理人脸识别库负责特征提取与比对Django 把前两步包装成浏览器里的页面。先分清边界后面写代码才不会把逻辑搅在一起。2.1 OpenCV 在系统里不是识别的主角而是取图和预处理的中转站很多第一次做这个课程设计的人会以为人脸识别算法是被 OpenCV「识别」出来的。真实分工是OpenCV 干的是取帧、灰度化、缩放、检测人脸框这一套预处理。人脸框一旦拿到真正做「画面里这个人是张三还是李四」的判断交给后面的人脸识别库。以 OpenCV 的 Haar 级联检测器为例它会在灰度图上用滑动窗口逐层扫描把每个候选区域交给级联分类器判断是不是人脸。这一步输出的只是「画面里有没有人脸、人脸框在哪」不是「这个人是谁」。常见参数 scaleFactor1.1、minNeighbors5 控制的是扫描密度和误报门槛这个参数在第三章的验证代码里会再展开。正因为检测足够快课程设计里一般把它放在识别的统一入口先裁脸再提取特征。OpenCV 的 DNN 模块还能加载 YuNet 这类现代模型精度比 Haar 好一些但对课程设计来说 Haar 够用而且模型随安装包自带不需要额外下载。选 Haar 的另一个理由是它不挑底层依赖装完 opencv-python 立刻能用这在答辩前夜特别友好。要识别物体的话流程也是同理先检测到目标物体框再做分类或比对人脸识别系统只是把「物体」特化成了「人脸」。2.2 人脸识别库选型face_recognition 和 LBPH 怎么选这一层决定整个项目的「上限」和「痛苦值」。常见两条路线一条是 face_recognition底层是 dlib 的 ResNet 模型把每张脸编码成 128 维向量另一条是 OpenCV 自带的 LBPH 人脸识别器用训练集学习局部二值模式直方图。两条路线我都跑过区别很实在。对比项face_recognitionOpenCV LBPH特征形式128 维浮点向量局部二值模式直方图模型依赖依赖 dlibWindows 下安装成本高随 opencv-contrib-python 一起装对姿态光照的容忍度较高侧脸和表情变化还能比较弱基本要正脸、均匀光照首次运行速度模型要加载一两秒基本秒开阈值调节方式欧氏距离0.4~0.6 之间调自定义置信度阈值答辩讲原理的难度要讲 128 维向量和距离度量讲直方图和训练集更好切入选型建议如果是课程设计优先 LBPH先把整条链路跑通face_recognition 作为加分项等 dlib 安装顺利之后再换上去对比效果。拿不准时把识别部分封装成独立函数两条路线只替换内部实现页面和数据库都不动这是最常见也最省事的做法。2.3 注册与识别的完整特征链路无论选哪条路线主流程是一致的。注册时用户上传一张人脸照片OpenCV 检测到人脸框后裁剪出人脸区域交给识别库提取特征特征以浮点列表形式存进数据库与姓名绑定。识别时新照片走同样的检测和特征提取再用新特征和库里所有特征一一比对返回距离最近的一位以及距离值距离小于阈值才认作匹配成功否则打回「陌生人」。这里有个容易被忽略的设计点数据库里存的不是照片本身而是特征向量。一百个人注册库里可能就一百行「姓名 一串数字」照片只是识别过程中的中间产物。好处是识别比对只做向量运算几十人的库毫秒级返回坏处是特征一旦丢失只能重新注册。所以我会额外保留一份原始照片目录相当于注册数据的后悔药。特征流转的终点是阈值判断。face_recognition 的距离阈值默认在 0.6 附近LBPH 的置信度必须靠实测压出来。阈值太宽会把不像的人放进来太严又让本人被拒建议答辩前用一批真实照片把距离分布打印出来后再决定取多少。3. 把环境一次装对Python 版本选择、OpenCV 与识别库的安装顺序环境问题在课程设计里占的坑比写代码还多。我见过最典型的翻车现场装 Python 时选了最新版然后 dlib 编译失败接着上网找各种 opencv 安装教程又装出两个版本的 OpenCV最后 import cv2 还能过LBPH 却找不到。版本范围和安装顺序定好能省下一整晚。3.1 为什么 Python 3.8-3.10 是课程设计最稳妥区间先说结论装 Python 时去官网下载 3.8 到 3.10 之间的版本。3.11 以上不是不行而是 dlib 和 face_recognition 的预编译轮子在部分平台跟不上容易从「装依赖」变成「编源码」。网上 python 安装教程很多核心就两条安装时勾选 Add Python to PATH装完用 python --version 确认是目标版本。用 VSCode 开发的话还要留意右下角的解释器路径。很多人依赖装在 A 环境VSCode 却指向 B 环境结果所有包导入失败。Django 选 4.x 稳定版即可它要求 Python 3.8 以上与上面建议的版本区间正好重合。Linux 上装 Python 优先用系统包管理器手动源码编译容易拖库没必要在这个环节冒险。3.2 安装命令从 pip 到 Windows 下 dlib 的三种救法我一般会先建一个独立虚拟环境避免污染系统 Python# 建议先建一个独立虚拟环境别污染系统 Python python -m venv venv # Windows 激活 venv\Scripts\activate # macOS / Linux 激活 # source venv/bin/activate # 旧版 pip 经常找不到新轮子先升级 python -m pip install --upgrade pip # Django 与 OpenCV 基础包 pip install django pip install opencv-python pip install opencv-contrib-python # 路线 A装 face_recognition会连带装 dlib耗时较长 pip install face_recognition参数说明opencv-python 提供基础图像功能人脸识别里的 LBPH、EigenFaces 这些 face 模块在 opencv-contrib-python 里。注意这两个包的 cv2 模块同名不能重复装后装的会覆盖前一个。face_recognition 那条命令会先把 dlib 装上需要 C 编译链Windows 下经常卡在这。失败时按顺序试三种救法先试指定老一点的 dlib 版本比如 pip install dlib19.24.0再装 Visual Studio Build Tools 里的「使用 C 的桌面开发」组件后重装还想省事就用 conda 建环境conda install -c conda-forge dlib让 conda 帮你找编译好的包。Linux 下相对好办把 cmake 和 libboost 相关依赖装上再走常规编译流程但 CMake 配置那一步容易卡在 boost 的 python 版本对不上记得先查系统 Python 版本。课程设计阶段没必要碰 OpenCV 的 CUDA 预编译轮子纯 CPU 推理完全够用。如果这些都不想折腾直接放弃 face_recognition走 LBPH 路线# 路线 B只用 OpenCV 内置 LBPH无需额外识别库 pip install opencv-contrib-python3.3 用十行代码验证环境和摄像头环境装完先别急着写 Django用一段小脚本验证三个能力OpenCV 可导入、摄像头可打开、人脸检测可返回坐标框。import cv2 # 打印版本确认不是被覆盖过的旧包 print(OpenCV version:, cv2.__version__) # 打开默认摄像头0 表示默认摄像头 cap cv2.VideoCapture(0) if not cap.isOpened(): print(can not open camera) exit(1) # Haar 级联的人脸检测模型自带在 cv2.data 里 detector cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) ok, frame cap.read() if ok: # 检测用灰度图比彩色图快很多 gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces detector.detectMultiScale( gray, # 输入灰度图 scaleFactor1.1, # 每层缩放比例越小越精细但越慢 minNeighbors5, # 邻居数量下限越大误报越少 minSize(64, 64), # 过滤过小区域避免把噪点当人脸 ) print(detected faces:, len(faces), faces) cap.release()逻辑说明CascadeClassifier 负责把模型文件读进来detectMultiScale 在灰度图上做多尺度扫描输出的 faces 数组里每个元素是 (x, y, w, h) 坐标框。scaleFactor 从 1.1 起步不要超过 1.2太大时小脸漏检minNeighbors 设成 5 是常规值场景里误报多就往上加。真机跑下来如果遇到 opencv python 拉流中断多半是驱动独占导致某几帧读取失败后面避坑章节专门说。提示这段脚本验证通过再进 Django 阶段。环境这关不过后面所有报错都会指向错误的方向。4. 把核心模块拼起来注册、识别、以及 Django 视图中的真实数据流环境就绪后核心代码就三块注册、识别、Web 路由。下面按 face_recognition 路线写核心逻辑封装成 recognition_core.py注册和识别放同一个文件Django 视图只负责对接这样换识别路线时不用动页面。4.1 人脸注册模块一张照片变成一条特征记录注册的本质是把人脸照片变成一条「姓名 特征」记录import json import sqlite3 import face_recognition def register_one_face(image_path, name, db_pathfaces.db): # face_recognition 内部按 RGB 处理直接用 load_image_file img face_recognition.load_image_file(image_path) # 定位画面里的人脸返回 top, right, bottom, left locs face_recognition.face_locations(img) if not locs: raise ValueError(no face found, use a front photo) # 提取第一张人脸的 128 维特征 enc face_recognition.face_encodings(img, known_face_locationslocs)[0] # sqlite 存不了 ndarray转成 list 再 json 化 feature json.dumps(enc.tolist()) # 建表feature 字段就用文本存 json conn sqlite3.connect(db_path) conn.execute( CREATE TABLE IF NOT EXISTS persons (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, feature TEXT) ) conn.execute( INSERT INTO persons (name, feature) VALUES (?, ?), (name, feature) ) conn.commit() conn.close() print(registered:, name)逻辑说明face_locations 拿到的坐标数组长度就是画面里的人脸数这里只取第一张课程设计演示时一张照片一张脸足够。face_encodings 默认会用 dlib 的 128 维模型把人脸编码成向量所以它比 Haar 检测重但精度高。feature 字段用 JSON 文本存一是人能看懂、便于排查二是 json.loads 回来就是普通列表再 np.array 成向量就能参与距离计算。参数说明db_path 默认放当前目录的 faces.dbDjango 项目里建议放到项目根目录或统一从 settings 读。注册口子如果想暴露在页面上写一个 POST 接口接收 name 和上传图片内部还是调这个函数。关键取舍是只存特征不存照片照片可以另开一个 backup 目录存档但识别时不要每次从照片重算特征那样会慢好几倍。想更稳一点给同一个人拍 3 张入库识别距离取最小几十人的规模查库开销可以忽略。4.2 人脸识别模块与全库比对并返回置信度识别模块读入新照片提取特征后与数据库全部已知特征做距离比较import json import sqlite3 import numpy as np import face_recognition def recognize_face(image_path, db_pathfaces.db, tolerance0.5): img face_recognition.load_image_file(image_path) locs face_recognition.face_locations(img) if not locs: return {result: unknown, distance: None} # 新照片里可能有多张脸全部提取 encodings face_recognition.face_encodings(img, known_face_locationslocs) # 读库把之前存的 json 特征还原成向量 conn sqlite3.connect(db_path) rows conn.execute(SELECT name, feature FROM persons).fetchall() conn.close() known_names [r[0] for r in rows] known_encs [np.array(json.loads(r[1])) for r in rows] results [] for enc in encodings: if not known_encs: results.append({result: unknown, distance: None}) continue # 与全部已知特征做欧氏距离取最近的那个 distances face_recognition.face_distance(known_encs, enc) idx int(np.argmin(distances)) dist float(distances[idx]) # 小于阈值才算认识否则是陌生人 if dist tolerance: results.append({result: known_names[idx], distance: dist}) else: results.append({result: unknown, distance: dist}) return results逻辑说明核心调用就一个 face_recognition.face_distance它把新向量和全部已知向量算成距离矩阵np.argmin 拿到最小距离那条。min 小于 tolerance 就认为匹配否则判定为陌生人。face_distance 把向量化和距离计算都封装好了不用自己写欧氏距离公式。返回 results 是为了兼容一张照片里多张脸的情况浏览器端直接循环展示。参数说明tolerance 是识别严格度的总开关0.5 属于中间值。演示时觉得匹配太松先收到 0.4本人频繁被拒再往回放 0.1。距离没有绝对正确的值它和注册照片的光照、角度强相关正式用之前建议拿几组照片打一张「距离分布表」再定阈值。LBPH 版本替换点只有「加载模型 predict」这一层数据库和视图逻辑完全不用动。4.3 Django 路由与视图识别逻辑变成浏览器里的一个按钮最后把识别包装成 Web 接口。按常规 Django 教程建好项目后创建一个 app你好可以叫 recognition然后写视图import cv2 import numpy as np from django.shortcuts import render from django.http import JsonResponse from .recognition_core import recognize_face # 上面封装好的函数 def upload_and_recognize(request): if request.method POST: # Django 把上传文件放在内存里不是磁盘路径 f request.FILES.get(face_image) if not f: return JsonResponse({error: no file uploaded}) # 关键把 bytes 解码成 OpenCV 图像而不是 cv2.imread data np.frombuffer(f.read(), np.uint8) img cv2.imdecode(data, cv2.IMREAD_COLOR) if img is None: return JsonResponse({error: decode failed}) # 人脸识别库从文件读取比直接传 ndarray 更稳 tmp_path /tmp/tmp_face.jpg cv2.imwrite(tmp_path, img) result recognize_face(tmp_path) return JsonResponse(result) # GET 请求时渲染上传页面 return render(request, recognition/upload.html)路由在 recognition/urls.py 里挂一条from django.urls import path from . import views urlpatterns [ path(recognize/, views.upload_and_recognize, namerecognize), ]逻辑说明这里最大的坑是 Django 上传文件对象没有磁盘路径cv2.imread 只吃路径所以先用 np.frombuffer cv2.imdecode 把上传 bytes 还原成图像。imdecode 出来的是 BGR 顺序的 ndarray直接 cv2.imwrite 成临时文件再把路径交给 recognize_face可以避开不同库之间色彩顺序不一致的问题是最省心的做法。如果不想写临时文件就得把 BGR 转成 RGB 再走 face_recognition 内部接口容易在颜色上翻车。参数说明request.FILES.get(face_image) 的键要和前端表单input typefile nameface_image保持一致。前端用 Ajax 上传时表单要带 enctypemultipart/form-data否则 request.FILES 一直为空。CSRF 中间件对 POST 有校验简化做法是在视图上加 csrf_exempt或者在页面表单里加 {% csrf_token %}二选一。还有一步容易漏在项目根 urls.py 里 include(recognition.urls)漏了页面只会 404。提示把 recognize_face 中用到的模型变量做成模块级全局变量避免每个请求重新加载模型。想在 Django 启动时就预加载写在 AppConfig.ready() 里最干净。5. 避坑与排查浏览器、摄像头和模型之间的五个现场5.1 摄像头拉流中断与黑屏现象Django 启动后页面上的摄像头预览要么黑屏要么运行十几秒后画面卡死控制台报 opencv 拉流中断或 cap.read() 返回 False。原因最常见是摄像头被两个进程同时占用比如浏览器还在预览后端又去 VideoCapture(0)。Windows 下摄像头驱动默认只允许一个进程独占后打开的一方直接失败。另一个原因是 cap.read() 在弱光环境丢帧代码里丢一帧就退出循环表现为视频流中断。解决确认只有一个进程占用摄像头读取循环里对失败帧做 continue 而不是 break进入识别前先 cap.grab() 一次清掉缓冲区。如果页面要长时间预览就用上传照片代替实时摄像头作为识别入口课程设计演示时这反而更稳不依赖现场摄像头。OpenCV 接口在 Python 和 C 下是同一套搜报错时查官网的 C 示例往往更全。5.2 Windows 下 dlib 安装失败现象pip install face_recognition 时dlib 从源码开始编译几分钟后报错找不到 CMake 或打不开 stddef.h。原因face_recognition 的完整链路依赖 dlib而 dlib 在 Windows 上需要 C 编译工具链默认安装的 Python 不带这些工具纯 pip 装 dlib 就触发源码构建。解决按顺序试三条路。先 pip install dlib19.24.0这个版本有较多预编译轮子不行就在 Visual Studio Installer 里勾选「使用 C 的桌面开发」后重装还不行用 conda 建环境conda install -c conda-forge dlib。最后一个保底方案是放弃 face_recognition改用 OpenCV LBPH第二章选型部分说过它零额外依赖。如果 import 阶段就报 no module named cv2先确认终端激活的是 venv 而不是系统 Python八成是解释器指错了。5.3 识别成另一个人或「陌生人」偏多现象注册后本人多次识别成功但换角度或光线后频繁返回 unknown或者两个人的脸被认成同一个人阈值怎么调都别扭。原因注册库太薄一个人只有一张正脸照片识别时人脸姿态和光照一变特征距离整体漂移。阈值单一化也是问题0.5 下误放进来0.4 下又把本人拒之门外。解决每个注册人多拍 3 到 5 张不同角度和光照的照片全部入特征库然后把识别返回的最小距离打印出来观察「同一人」和「不同人」的距离分布明显分开就取中间值重叠严重就回去补注册照片不要硬调阈值。LBPH 路线同理训练集里每人也至少放三张。5.4 中文名、中文路径与文件乱码现象注册姓名是中文页面上显示乱码把照片保存到本地时cv2.imwrite 直接报错。原因cv2.imread 和 cv2.imwrite 在 Windows 下不认中文路径这是 OpenCV 的历史遗留问题。自己直连 sqlite3 的辅助脚本没指定 text_factory 时读中文也可能乱码。Django 管理的 SQLite 一般没事问题集中在直接操作 sqlite3 的地方。解决中文路径读图用 np.fromfile 读成 bytes 再 imdecode写文件用 cv2.imencode 后再 tofilesqlite3.connect 之后设置 conn.text_factory str源文件统一保存为 UTF-8不要留 GBK 之类的历史包袱。这类问题定位很费时间排查时先写个最小脚本验证「中文路径 OpenCV SQLite」组合再回业务代码。5.5 识别请求首次卡顿与内存偏高现象第一次点识别按钮页面转圈好几秒持续识别几分钟后4GB 内存的开发机开始卡。原因face_recognition 的模型是懒加载第一次调用才把 128 维模型读进内存后续才快。Django development server 如果开多进程每个进程都会加载一份模型内存直接翻倍。解决在 AppConfig.ready() 里提前初始化模型并挂到全局识别函数复用。开发时用 manage.py runserver 的默认单进程模式保证只加载一份模型。内存吃紧的机器直接切 LBPH 路线这就是选型章节强调过的想让课程设计顺利跑在别人电脑上安装成本和内存占用也是需求的一部分。6. 把课程设计做出彩精度调优与答辩演示的三个技巧6.1 用多角度注册样本压出更稳的阈值精度上限基本由注册数据决定。给每个成员准备 3 到 5 张照片正脸、左右各偏 15 度、不同室内光照全部入库识别时取最小距离。想让阈值更有说服力写一个二十行的小脚本把「同一人」与「不同人」的距离分布打印出来阈值设在两类距离的中间。答辩时你能拿出真实数据说明为什么选 0.45 而不是 0.6比空口讲「阈值越小越严格」强得多。6.2 把识别结果接进 Django Admin 与签到记录实际演示时只弹一个姓名不够有完成度。常见做法是建一张识别记录模型存识别时间、姓名、距离、图片路径注册和识别都往里写一条然后注册到 Django Admin后台直接按时间筛记录。想再好看一点后台主题可以换 django-unfold要导出签到表把记录表转成 DataFrame 后写 pandas 的 to_excel 也很顺。清理测试数据时filter(...).delete() 比一条条删省事。登录这块走 Django 内置 session/cookie 就够了想用 token 再接 DRF不必在核心流程上加重负担。6.3 演示前的固定动作重置库、预置照片、WebSocket 作为进阶演示最容易翻车的不是算法而是现场照片角度和注册时差太远。我的习惯是演示前清空数据库重新现场注册同一人三张原始照片放在 backup 目录页面再预置一张本地照片作为无人脸时的兜底。想追求实时推送效果可以在同步识别跑通后用 Django Channels 把识别结果以 WebSocket 推给前端后台有新数据模板自动更新。这是进阶加分项别在核心流程没稳定前引入。这几年做识别相关的课程设计我养成了一个习惯永远先写一个不依赖 Web 框架的命令行版本把它从「也人脸 → 出名字」跑通再套上 Django 外壳。套外壳时重点盯三处上传文件解码、模型全局加载、数据库特征序列化。这三处不出问题整套系统基本就稳了。希望帮到你。本文还有配套的精品资源点击获取
返回列表