资讯动态

Python机器学习人脸识别系统:从源码到报告,期末大作业实战指南

发布时间:2026/10/13 0:17:15 来源:尧图企业网站定制
简介这份资源是面向高校学生与Python初学者的机器学习人脸识别系统完整项目包可直接用于期末大作业、课程设计或自学练手。项目以Python实现人脸检测与识别核心流程并附带一份完整报告文档帮助读者理解算法思路与工程结构。压缩包共4个文件包含2个py源码文件、1份pdf报告和1份md说明文档整体约631KB体积轻便下载后简单部署即可运行。源码中带有详细注释新手也能看懂适合作为课程设计参考或二次开发基础。目前已有283人学习下载说明其在同类作业资源中具有一定认可度。读者可获得可运行的人脸识别系统源码、配套报告文档以及清晰的代码注释既能直接用于作业提交也能借此掌握机器学习在人脸识别中的实际应用方式对提升项目实践能力有较高参考价值。1. 从一份期末大作业说起人脸识别系统到底难在哪每年期末季GitHub 和各类资源站上「Python 机器学习人脸识别系统源码报告」的检索量都会暴涨。很多人拿到压缩包解压、装依赖、跑main.py然后卡在摄像头打不开、识别率惨不忍睹、报告不知道怎么写这三个坑里。这份标题背后其实是一套完整的工程链路数据采集、人脸检测、特征提取、分类器训练、GUI 集成、实验报告撰写。它适合两类人——一类是赶期末大作业的学生需要一套能跑通、能改、能写进报告的完整方案另一类是想入门机器学习落地的新手想找一个有明确输入输出、能快速看到效果的项目练手。人脸识别听起来玄乎拆开看无非是「找到脸 → 对齐脸 → 把脸变成一串数字 → 比对数字」。真正让人翻车的地方不在算法本身而在数据质量、环境配置和参数调优。下面我按实际做项目的顺序把这套系统从零到跑通讲清楚包括每一步的命令、参数含义和常见报错。2. 技术选型为什么用 OpenCV face_recognition 而不是从零训 CNN2.1 三条主流路线的取舍做期末大作业级别的人脸识别常见有三条路一是从零训练 CNN二是用 OpenCV 的 LBPH 算法三是用 dlib/face_recognition 这类预训练模型做特征比对。从零训 CNN 需要几千张标注人脸和 GPU期末周期内基本不现实LBPH 简单但对光照和角度极其敏感稍微换个方向就认不出face_recognition 底层是 dlib 的 ResNet 人脸特征提取单张图编码成 128 维向量比对欧氏距离即可精度够用、代码量少、CPU 也能跑。我一般推荐 face_recognition OpenCV 的组合。OpenCV 负责摄像头读取、图像预处理和 GUI 显示face_recognition 负责检测和编码。这样分工清晰报告里也好写检测用 HOG 或 CNN编码用 ResNet分类用距离阈值。2.2 环境搭建Python 版本和依赖安装的坑Python 版本建议 3.83.10太新的版本 dlib 编译容易失败。Windows 上装 dlib 是最容易翻车的一步因为需要 CMake 和 Visual Studio 的 C 编译工具。最省事的做法是直接装预编译的 wheel。# 建议先建虚拟环境避免污染全局 python -m venv face_env # Windows 激活 face_env\Scripts\activate # Linux/Mac 激活 source face_env/bin/activate # 安装核心依赖指定版本避免兼容问题 pip install opencv-python4.8.1.78 pip install face_recognition1.3.0 pip install numpy1.24.3 pip install pillow10.0.1opencv-python负责图像和摄像头操作face_recognition封装了 dlib 的检测和编码接口numpy做向量运算pillow处理中文路径下的图片读写。版本号不是随便写的numpy 1.24 以上和旧版 dlib 有 ABI 冲突opencv 4.8 在 Windows 上对 DirectShow 摄像头支持更稳。如果pip install face_recognition卡在编译 dlibWindows 用户可以去下载对应 Python 版本的 dlib wheel 文件手动安装再装 face_recognition。Linux 用户先sudo apt install cmake build-essential再装。这一步没有后悔药装不上后面全白搭。2.3 项目目录结构怎么组织一份能写进报告的源码目录结构要清晰答辩时老师一眼能看懂。我一般这样分face_project/ ├── dataset/ # 每人一个子文件夹存人脸样本 │ ├── person_01/ │ └── person_02/ ├── encodings/ # 存放训练好的 128 维特征 │ └── face_encodings.pkl ├── src/ │ ├── collect_faces.py # 采集样本 │ ├── train_model.py # 训练编码 │ ├── recognize.py # 实时识别 │ └── gui.py # 图形界面 ├── report/ # 实验报告 └── requirements.txtdataset下每人一个文件夹文件夹名就是标签名。encodings存 pickle 文件避免每次启动都重新编码。src放四个脚本职责单一报告里可以逐个截图说明。3. 数据采集与预处理样本质量决定识别上限3.1 用 OpenCV 采集人脸样本的完整脚本数据采集是整个系统最容易被忽视、却最影响结果的环节。很多人随便拍几张就开跑结果识别率上不去回头怪算法。我的经验是每人至少 20 张覆盖正脸、左右偏转、戴眼镜/不戴眼镜、不同光照。import cv2 import os # 采集参数 person_name person_01 save_dir os.path.join(dataset, person_name) os.makedirs(save_dir, exist_okTrue) # 加载 OpenCV 自带的人脸检测器 detector cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) cap cv2.VideoCapture(0) # 0 表示默认摄像头 count 0 max_count 30 # 每人采集 30 张 while count max_count: ret, frame cap.read() if not ret: print(摄像头读取失败检查设备占用) break gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces detector.detectMultiScale(gray, 1.3, 5) for (x, y, w, h) in faces: count 1 # 保存灰度人脸区域统一尺寸 face_img cv2.resize(gray[y:yh, x:xw], (200, 200)) cv2.imwrite(f{save_dir}/{count}.jpg, face_img) cv2.rectangle(frame, (x, y), (xw, yh), (0, 255, 0), 2) cv2.imshow(Collecting, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()detectMultiScale的三个参数要理解第一个是灰度图第二个1.3是每次缩放比例越小检测越慢但越全第三个5是邻域阈值越大误检越少但漏检越多。采集时保存的是灰度图并统一缩放到 200×200这样后续训练不用再做尺寸归一化。max_count设 30 是经验值太少模型不稳太多采集时间长且冗余。3.2 样本清洗哪些图必须删掉采集完不要直接训练先人工过一遍。以下几类图必须删检测框明显偏了只框到半张脸的、光照过曝或全黑的、模糊到看不清五官的、同一人重复度极高的。这些脏数据会让编码向量偏移导致同一个人被识别成不同人。清洗可以用一个简单脚本批量看图和删除也可以直接在文件夹里肉眼过。我一般会写个脚本把所有人脸拼成一张大图一眼扫过去有问题的记下文件名删掉。import cv2 import os import numpy as np def make_contact_sheet(folder, cols6, thumb100): files [f for f in os.listdir(folder) if f.endswith(.jpg)] rows (len(files) cols - 1) // cols sheet np.zeros((rows * thumb, cols * thumb, 3), dtypenp.uint8) for i, f in enumerate(files): img cv2.imread(os.path.join(folder, f)) img cv2.resize(img, (thumb, thumb)) r, c divmod(i, cols) sheet[r*thumb:(r1)*thumb, c*thumb:(c1)*thumb] img cv2.imwrite(contact_sheet.jpg, sheet) make_contact_sheet(dataset/person_01)拼图后打开contact_sheet.jpg异常样本一目了然。这一步花十分钟能省掉后面调参的两小时。3.3 数据增强要不要做期末作业级别如果每人样本超过 20 张且角度光照有变化可以不做增强。如果样本少可以做水平翻转、轻微旋转、亮度调整。但要注意人脸识别对翻转敏感左右翻转后的人脸和原图编码差异较大可能被当成两个人。所以增强只建议做亮度和小角度旋转不要做翻转。import cv2 import numpy as np def augment_brightness(img, factor1.2): hsv cv2.cvtColor(img, cv2.COLOR_BGR2HSV) hsv[:, :, 2] np.clip(hsv[:, :, 2] * factor, 0, 255) return cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR) def augment_rotate(img, angle10): h, w img.shape[:2] M cv2.getRotationMatrix2D((w/2, h/2), angle, 1.0) return cv2.warpAffine(img, M, (w, h))亮度因子控制在 0.81.2旋转角度控制在 ±15 度以内。超过这个范围生成的人脸就不自然了反而引入噪声。4. 训练与识别128 维编码怎么算、阈值怎么定4.1 批量编码把每张脸变成 128 个数字face_recognition 的核心是face_encodings函数它接收一张 RGB 图片返回一个 128 维的 numpy 数组。这个数组就是人脸的「数字指纹」。训练阶段就是把 dataset 下每个人的所有图片都编码然后按人分组存起来。import face_recognition import os import pickle import numpy as np dataset_dir dataset known_encodings [] known_names [] for person_name in os.listdir(dataset_dir): person_dir os.path.join(dataset_dir, person_name) if not os.path.isdir(person_dir): continue for img_name in os.listdir(person_dir): img_path os.path.join(person_dir, img_name) # face_recognition 需要 RGB 格式 image face_recognition.load_image_file(img_path) # 每张图可能检测到多张脸取第一张 encodings face_recognition.face_encodings(image) if len(encodings) 0: print(f未检测到人脸跳过{img_path}) continue known_encodings.append(encodings[0]) known_names.append(person_name) # 保存编码和标签 data {encodings: known_encodings, names: known_names} with open(encodings/face_encodings.pkl, wb) as f: pickle.dump(data, f) print(f共编码 {len(known_encodings)} 张人脸涉及 {len(set(known_names))} 个人)load_image_file读进来是 RGB而 OpenCV 读进来是 BGR两者不能混用这是新手最常见的翻车点。face_encodings默认用 HOG 模型检测速度快但小脸容易漏如果图片里人脸较小可以加参数modelcnn但需要 GPU 才快。编码结果用 pickle 存下次识别直接加载不用重新跑。4.2 识别逻辑欧氏距离和阈值 0.6 的由来识别时把摄像头拍到的人脸编码和已知编码逐一算欧氏距离。距离越小越像。face_recognition 官方建议阈值 0.6低于 0.6 认为是同一个人。这个值是 dlib 在 LFW 数据集上调出来的平衡点不是随便定的。import face_recognition import cv2 import pickle import numpy as np # 加载已知编码 with open(encodings/face_encodings.pkl, rb) as f: data pickle.load(f) cap cv2.VideoCapture(0) # 降采样比例加快处理速度 scale 0.25 while True: ret, frame cap.read() if not ret: break # 缩小图像加速检测 small_frame cv2.resize(frame, (0, 0), fxscale, fyscale) rgb_small cv2.cvtColor(small_frame, cv2.COLOR_BGR2RGB) face_locations face_recognition.face_locations(rgb_small) face_encodings face_recognition.face_encodings(rgb_small, face_locations) for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings): # 距离比对 distances face_recognition.face_distance(data[encodings], face_encoding) best_idx np.argmin(distances) name Unknown if distances[best_idx] 0.6: name data[names][best_idx] # 坐标还原到原图尺寸 top, right, bottom, left [int(v / scale) for v in (top, right, bottom, left)] cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2) cv2.putText(frame, name, (left, top - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2) cv2.imshow(Recognition, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()scale 0.25是性能关键。原图 640×480 直接检测每帧要几百毫秒画面卡顿缩小到 1/4 后检测速度提升十几倍坐标再乘回去即可。face_distance返回的是待识别编码和所有已知编码的距离数组argmin取最近的那个。阈值 0.6 可以调调到 0.5 更严格误认少但可能拒真调到 0.7 更宽松认得多但可能把别人认成你。报告里可以做一个阈值对比实验用表格展示不同阈值下的准确率和误识率。4.3 阈值调优实验怎么做拿一部分样本做测试集分别用 0.4、0.5、0.6、0.7 跑一遍统计正确识别数和错误识别数。表格大概长这样阈值正确识别误识别拒识准确率0.41801260%0.5241580%0.6282093%0.7295085%这张表放进报告比单纯说「用了 0.6」有说服力得多。数据自己跑不要编。5. 避坑与排查那些让系统跑不起来的细节5.1 摄像头打不开或黑屏现象cap.read()返回 False窗口一片黑。原因通常是摄像头被其他程序占用或者 OpenCV 后端选错。Windows 上可以换cv2.CAP_DSHOW后端cv2.VideoCapture(0, cv2.CAP_DSHOW)。Linux 上检查/dev/video0权限把当前用户加入video组。虚拟机里没有 USB 直通的话摄像头根本传不进来这种情况换物理机跑。5.2 中文路径导致图片读取失败现象load_image_file报错或返回 None。原因是 OpenCV 和 dlib 对中文路径支持不好。解决办法是用 numpy 读文件再解码或者干脆把 dataset 路径改成全英文。我一般直接要求项目路径不含中文省事。5.3 识别总是 Unknown现象明明采集了样本识别时全是 Unknown。先检查编码文件里names和encodings数量是否一致再检查采集时保存的是灰度图而识别时用的是 RGB 图——两者编码分布不同距离自然大。采集和识别必须用同一种颜色空间。另外如果采集时人脸框偏了编码质量差也会导致距离偏大。5.4 帧率低、画面卡顿现象识别窗口一卡一卡。原因是每帧都在做全图检测和编码。解决降采样前面说的 scale、跳帧处理每 3 帧检测一次中间帧沿用上次结果、或者把检测和识别放到独立线程。期末作业级别降采样加跳帧就够了。5.5 多人脸时标签错乱现象画面里两个人标签张冠李戴。原因是face_locations和face_encodings的顺序虽然对应但如果你在循环里做了排序或过滤顺序就乱了。保持两者用同一个列表推导式生成不要分开处理。6. 报告怎么写才不像流水账实验设计比代码更值分6.1 报告结构从问题到验证的闭环很多人的报告就是贴代码加截图老师一看就知道是凑的。好的报告应该是一个完整的实验叙事要解决什么问题、选了哪些方案、为什么选这个、怎么验证、结果如何、有什么局限。我一般按这个框架写引言人脸识别的应用场景和本次目标、相关工作LBPH、CNN、dlib 三种方案对比、系统设计模块图、数据流、实验设置数据集规模、硬件环境、参数配置、实验结果准确率、阈值对比、耗时、讨论失败案例分析、结论。6.2 用混淆矩阵和耗时数据撑起实验部分光说准确率 93% 太单薄。做一个混淆矩阵展示每个人被正确识别和误识别成谁的次数。再测一下单帧检测耗时、编码耗时、比对耗时用表格列出来。这些数据用脚本就能跑出来不需要额外工作但报告的专业度立刻不一样。import time import face_recognition import cv2 img face_recognition.load_image_file(dataset/person_01/1.jpg) t0 time.time() locations face_recognition.face_locations(img) t1 time.time() encodings face_recognition.face_encodings(img, locations) t2 time.time() print(f检测耗时{(t1-t0)*1000:.1f} ms) print(f编码耗时{(t2-t1)*1000:.1f} ms)把不同分辨率下的耗时都测一遍画个折线图报告里就是实打实的实验数据。6.3 失败案例比成功案例更有说服力挑几张识别错误的图放进报告分析原因是光照太暗、角度太偏、还是训练样本里没有类似姿态。然后给出改进方向比如增加对应姿态的样本、调整阈值、换用 CNN 检测模型。这种自我批判的部分恰恰是老师最看重的——说明你真的理解了系统的边界而不是跑通就完事。6.4 我踩过的那些坑最后说几个我自己的血泪教训。第一不要等到答辩前一天才跑通dlib 编译可能卡你一整晚。第二采集样本时多拍几组不同光照的别在同一个位置拍 30 张那样训练出来的编码方差极小换到答辩教室的灯光下直接失灵。第三报告里的数据一定要自己跑出来网上抄的准确率经不起追问。第四GUI 用 tkinter 就够了别上 PyQt期末作业没必要还容易打包出问题。这套方案从采集到识别认真做三天能跑通报告再花两天打磨足够应付绝大多数期末要求。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑