ARTICLE DETAIL

资讯详情

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

OpenCV人脸识别课设实战:从LBPH原理到答辩避坑指南

OpenCV人脸识别课设实战:从LBPH原理到答辩避坑指南 简介一份研一图像处理期末大作业基于 OpenCV 实现人脸识别全流程面向需要完成课程设计或入门计算机视觉的学生代码可直接运行并二次开发。项目按数据处理、检测、训练、识别划分模块包含图像预处理、数据集采集脚本、Haar 级联人脸检测、特征提取与模型训练最后通过训练好的模型对新人脸进行身份判别。压缩包共 9 个文件3 个 Python 脚本分别负责建库、训练与识别2 个 XML 文件提供人脸检测所需的级联配置YML 文件保存已训练的模型参数另有 SQLite 数据库与简明 README整体仅 1.03MB轻量易读。目前已有 1652 人学习浏览。参考价值在于能快速理解 Eigenfaces、LBPH 等经典算法的工程实现也可作为期末汇报、项目复现或简历作品的实用素材无论用于课程复现还是系统设计都有直接帮助。1. 期末大作业的“人脸识别”到底在考什么OpenCV 那条最稳的落地路线研一刚开学就被图像处理课设砸中题目是“基于OpenCV的人脸识别”这大概是每个视觉方向研究生都绕不过的一关。如果你以为拿个预训练的深度学习模型跑一遍就能交差大概率会在答辩时被问得下不来台——这门课考的是你能不能把图像处理的基本功灰度化、直方图均衡化、降噪、特征提取嵌进一个完整的人脸识别链路里。OpenCV 的好处在于主干逻辑清晰检测、预处理、特征提取、分类决策全都能用几十行代码打通适合一周内出活也适合写进报告里讲明白。这篇笔记会按“选型→代码→答辩→避坑”一路捋下来新手可以照抄熟手可以跳着看边界条件。2. 从需求拆解到方案选型为什么 OpenCV 比深度学习模型更适合交作业2.1 作业题目拆解先分清“人脸检测”和“人脸识别”“基于OpenCV的人脸识别”这个题目很多人一上来就把“人脸检测”和“人脸识别”混在一起答辩时被一问就穿帮。检测只回答“图里有没有人脸、脸在哪”用的是Haar特征或LBP特征分类器识别回答的是“这张脸是谁”需要先检测到人脸再提取特征和数据库里的标签比对。大作业的重点通常放在后者——检测用的是OpenCV自带的级联分类器haarcascade_frontalface_default.xml这部分不需要你自己训练识别部分才需要你写训练、加载、预测的代码也是报告里能展开讲的核心。我一般会先跟同学确认作业要求是只需要静态图片识别还是必须摄像头实时识别校内常见的评分标准是“功能完整度 代码可读性 答辩表现 报告深度”。如果只要求静态图片识别链路可以简化但为了演示效果多数人会做摄像头版本这就会牵扯到实时性问题。另一个容易被忽略的点是很多人拿“人脸识别门禁机”来对标课设以为要用到多复杂的模型实际上门禁设备的部署环境受控用的也往往是轻量特征和OpenCV的LBPH思路一脉相承课设里把这一条讲清楚反而是加分项。2.2 三种 OpenCV 识别方案的选型对比EigenFaces / FisherFaces / LBPHOpenCV 的face模块一共给了三套经典识别器对应三种完全不同的图像处理思路。选型之前先花十分钟把原理捋一遍能让你少踩很多坑。方案核心原理对光照/角度敏感度训练数据要求推荐场景EigenFacesPCA降维把人脸映射到特征脸空间高对光照敏感每类样本要够且人脸必须对齐实验室标准数据集FisherFacesLDA降维最大化类间散度/最小化类内散度中等每类样本多身份类别数有限制受控环境LBPH局部二值模式直方图分块统计纹理较低抗光照变化样本数要求低单张也能启动训练摄像头实时/期末大作业EigenFaces 和 FisherFaces 在面对未对齐、光照不均的随手拍照片时很容易翻车LBPH 对灰度变化更钝感是期末大作业最常用的选择。我自己带人做这类课设时默认选 LBPH理由只有一个它能让“普通摄像头 普通宿舍灯光”下也跑出稳定结果把分数押在能演示的功能上而不是押在玄学上。三套方案的代码接口很相似但 EigenFaces 和 FisherFaces 在数据规模很小时协方差矩阵容易奇异导致训练直接报错LBPH 则基本不会这也是选型时一个很硬的约束。为什么不建议直接换深度学习模型核心原因是课设的数据量撑不起来。每个人二三十张照片从头训一个 CNN 必过拟合用迁移学习确实能跑但答辩老师一半会顺着问你模型参数量、损失函数、训练策略问题越答越多不如把 LBPH 的原理吃透。OpenCV 这套经典方案在《数字图像处理》教科书里都有对应章节报告好写代码量还小遇到问题网上随便一搜就是一大把现成案例。2.3 环境搭建与数据集准备安装 opencv、目录规范与照片采集脚本环境这块最常见的坑是pip install opencv-python装完发现cv2.face根本不存在。原因很简单——识别人脸的face模块放在opencv-contrib-python里只装主包没有这个子模块。我的习惯是直接装全pip install opencv-python opencv-contrib-python numpy版本上OpenCV 4.x 和 3.x 的接口差异不大LBPHFaceRecognizer_create()在 3.4.1 之后被放进cv2.face4.x 依然保留。如果你是在 Linux 下自己用 cmake 编译 OpenCV 做图像处理项目记得编译时加上 contrib 模块否则同样找不到cv2.face。用 anaconda prompt 装完却没有 opencv多半是源太老或者装到了不同环境里把 conda 源切到国内镜像、确认当前 activate 的是同一个环境就行。数据集准备是整个项目里最容易被忽视、也最决定成败的一步。常见做法是建这样的目录结构face_dataset/ person_01/ 001.jpg 002.jpg ... person_02/ ...每人至少准备二十到三十张照片采集时让摄像头慢慢平移覆盖正脸、左右轻微转头、抬头低头但角度不要超过正负三十度也不要戴口罩和墨镜。照片统一先转灰度、缩放到固定尺寸最后做一次直方图均衡化把光照差异压下去。文件名和路径都不要用中文OpenCV 的imread对中文路径的处理在不同系统上并不可靠我见过太多人因为“人脸识别.zip”解压路径里带中文训练时图片一读一个空。采集照片这一步很多人是在宿舍里拿着手机自拍再传到电脑上但课设答辩时老师最认的还是“摄像头实时采集”这条链路。写一个小脚本按字母键存图就能解决import cv2 import os cap cv2.VideoCapture(0) if not cap.isOpened(): print(camera open failed) exit() person_dir face_dataset/person_01 os.makedirs(person_dir, exist_okTrue) face_cascade cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) count 0 while True: ok, frame cap.read() if not ok: print(frame read failed) break gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces face_cascade.detectMultiScale(gray, 1.1, 5, minSize(120, 120)) for (x, y, w, h) in faces: cv2.rectangle(frame, (x, y), (x w, y h), (0, 255, 0), 2) if cv2.waitKey(1) 0xFF ord(s): face gray[y:y h, x:x w] face cv2.resize(face, (200, 200)) cv2.imwrite(f{person_dir}/{count:03d}.jpg, face) count 1 print(saved, count) cv2.imshow(capture, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这段脚本的逻辑是循环读帧检测到人脸后按s键把当前人脸区域裁出来统一缩放成 200x200 的灰度图再存盘按q退出。注意cv2.data.haarcascades是 OpenCV 自带的级联文件路径避免你手动找 xml 文件。minSize(120, 120)的作用是过滤掉太小的候选框防止把背景噪声当成人脸存进数据集。存图时建议每存一个人就换一个person_dir别把不同人的照片混在同一个文件夹里否则后面训练时的标签就全乱了。3. 用 Python 把 OpenCV 人脸识别跑通训练、预测与参数调优3.1 训练脚本从照片目录读取样本、生成标签与模型文件数据集准备好之后训练脚本的核心任务就是遍历目录给每个身份分配数字标签把图片和标签喂给识别器。整个过程大概四五十行代码但有几个细节处理不好就很容易翻车import cv2 import os import numpy as np base_dir face_dataset images [] labels [] label_map {} next_label 0 for person_name in sorted(os.listdir(base_dir)): person_dir os.path.join(base_dir, person_name) if not os.path.isdir(person_dir): continue if person_name not in label_map: label_map[person_name] next_label next_label 1 for file in os.listdir(person_dir): img_path os.path.join(person_dir, file) img cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) if img is None: print(skip:, img_path) continue img cv2.resize(img, (200, 200)) img cv2.equalizeHist(img) images.append(img) labels.append(label_map[person_name]) recognizer cv2.face.LBPHFaceRecognizer_create() recognizer.train(images, np.array(labels)) recognizer.write(face_model.yml) print(trained samples:, len(images)) print(label_map:, label_map)先解释逻辑第一层for遍历数据集里的一级子目录每个子目录名当作一个身份名label_map负责把身份名映射成从 0 开始的连续整数。第二层for读取这个身份下的所有图片imread失败返回None就跳过避免个别损坏的图片让整个训练崩溃。每张图在进入训练前都做了resize和equalizeHist这一步保证训练时的输入是统一尺寸、统一光照分布否则 LBPH 提取出的直方图会天差地别。参数上需要注意两点第一200x200不是唯一选择但必须保证训练和识别两个脚本用同一尺寸LBPH 的直方图维度是由图像尺寸和分块数共同决定的尺寸不一致训练时不会报错预测时却会得到完全没意义的 confidence第二标签必须从 0 开始连续递增LBPHFaceRecognizer内部对标签有隐式假设跳号或从 1 开始虽然能跑但保存模型后再加载预测返回的标签可能对不上你的label_map。recognizer.write保存出来的.yml文件就是你的模型文件答辩前可以单独备份一份。3.2 识别脚本静态图片与摄像头实时识别训练完模型识别脚本就是把刚才所有步骤反过来走一遍读图、检测人脸、裁脸、预处理、预测、画框。摄像头版本的典型代码是import cv2 recognizer cv2.face.LBPHFaceRecognizer_create() recognizer.read(face_model.yml) name_map {0: person_01, 1: person_02} unknown_label unknown face_cascade cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) cap cv2.VideoCapture(0) if not cap.isOpened(): print(camera open failed) exit() while True: ok, frame cap.read() if not ok: 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: face gray[y:y h, x:x w] face cv2.resize(face, (200, 200)) face cv2.equalizeHist(face) label, confidence recognizer.predict(face) name name_map.get(label, unknown_label) color (0, 255, 0) if confidence 80 else (0, 0, 255) cv2.rectangle(frame, (x, y), (x w, y h), color, 2) cv2.putText( frame, f{name} ({confidence:.0f}), (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2, ) cv2.imshow(face recognize, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这段代码的核心调用是recognizer.predict(face)它返回两个值label是预测出的身份标签confidence是距离度量越小代表和训练样本越接近。注意predict的输入必须是灰度图而且预处理顺序要和训练时完全一致——裁脸后先resize再equalizeHist任何一步不一致都会让 confidence 变大原本能识别的脸也会被判成 unknown。画框用的是检测阶段返回的原始坐标(x, y, w, h)而不是resize后的人脸子图坐标这一点特别容易写错。detectMultiScale的参数也需要解释一下scaleFactor1.1表示每层图像缩放 10%数值越接近 1 检测越慢但越不容易漏检minNeighbors5表示候选框周围至少要有 5 个重叠框才被认定为有效调高能减少误检但太高会漏检minSize(100, 100)过滤太小的框避免远处的小脸被识别成莫名其妙的标签。这几个参数对最终演示效果的影响比模型本身还大建议跑起来以后自己手调几轮感受一下。3.3 调参方向confidience 阈值与训练样本数怎么配合LBPH 的confidence没有绝对值同一个模型在光线差、镜头糊的场景下识别的距离值可能从 40 涨到 120。你不能把 80 当成铁打的阈值更不能只看一次识别成功就认为调参结束。我经常用的调参套路是先采集一组测试样本跑一遍预测把每个样本的 confidence 打印出来test_img cv2.imread(test_person_01.jpg, cv2.IMREAD_GRAYSCALE) test_img cv2.resize(test_img, (200, 200)) test_img cv2.equalizeHist(test_img) label, confidence recognizer.predict(test_img) print(label, confidence)日志打出来以后你就能看到自己人的 confidence 大概在什么范围陌生人的 confidence 又在什么范围。如果两类数字重叠得很厉害通常不是阈值的问题而是训练样本太少或者采集时光线太单一。这时优先补样本而不是硬调阈值。另一种常见情况是识别框老跳到背景或肩部区域原因往往是minNeighbors太低把纹理类似的区域误检成人脸把minNeighbors调到 6 到 7 就能压掉大部分误检。另外有个细节值得提如果你把predict的 confidence 阈值设在 100陌生人也会被随手识别成某个已知身份。课设答辩里老师通常会让一个没参与采集的同学站到摄像头前你希望这时显示 unknown而不是报一个错误的名字。所以阈值宁可刻薄一点也要保证“陌生人明显不认”这个演示效果往往比“熟人全认对”更让老师满意。4. 从“能跑”到“能答辩”交互界面、报告素材与打包成 exe 的取舍4.1 给演示加一个控制菜单按键注册、退出与人脸录入回路识别脚本跑通之后很多同学急着写报告但我建议先花半小时给程序加一个简单的交互逻辑哪怕只是在画面角落显示两行操作提示。期末答辩时一台电脑摆在教室讲台上老师会站在旁边看一个没有提示的最小 demo 会让人摸不着头脑而带快捷键的 demo 显得完整得多。常见做法是在识别脚本里加两个按键分支按r进入注册模式把当前帧里检测到的人脸存进对应的数据集目录然后重新训练模型按q退出。注册新人的逻辑其实就是前面采集脚本和训练脚本的组合不需要把训练放到循环里实时跑——存完照片调用一次训练函数模型热更新即可。你甚至可以做个最朴素的版本预先留好两个文件夹演示开始时先让现场同学各拍几张照片重新训练一次再开始识别。这个“现场注册”的动作非常讨巧它证明你的系统不是只能识别固定的人也顺便证明了训练和识别是一条完整闭环。不过条代码不要写得过于花哨。课设评分里“代码可读性”占的比重不小一个一百行内能读懂的交互脚本比一个三百行的菜单类更容易拿分。简单按键分支足够key cv2.waitKey(1) 0xFF if key ord(r): save_new_face(frame, gray_face) retrain_model() elif key ord(q): break逻辑说明放在注释里就够了r触发注册和再训练q退出循环。这样答辩时你可以说“系统的可扩展点在这里新增身份不需要改模型结构只要补数据重训”。注意retrain_model()内部要重新读取全部数据集照片多了以后这步会变慢但课设规模完全没问题。4.2 把识别结果画到画面上矩形框、名字、置信度与 FPS很多同学的代码里putText只写了识别名字这是个遗憾。在画面上同时展示 confidence 数值既能体现你对模型的理解又能让你在答辩时指着数字解释阈值逻辑。上一章的识别脚本已经画了名字和置信度这里补一个 FPS 指标import time fps 0.0 last_time time.time() frame_count 0 while True: ok, frame cap.read() if not ok: break frame_count 1 now time.time() if now - last_time 1.0: fps frame_count / (now - last_time) last_time now frame_count 0 cv2.putText(frame, fFPS: {fps:.1f}, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)FPS 的数值本身不重要重要的是它让老师知道你已经能评估系统的实时性。很多同学答不出“你的系统能跑多少帧”这个问题现场一报 FPS 就是分上来了。需要注意不要把time.time()放在每一帧循环里去算单帧耗时那样数字跳动非常厉害反而显得系统不稳定按秒统计帧数是最稳的。4.3 打包成 exe 的路径坑sys._MEIPASS 与 haarcascade 资源如果答辩现场用的是教室电脑你不可能保证那台机器装了 Python 和 OpenCV所以提前打包成 exe 是相当常见的选择。PyInstaller 是打包 OpenCV 图像处理项目最常用的工具但有坑haarcascade_frontalface_default.xml和face_model.yml这两个文件是运行时才读取的资源如果打包时不把它们带进去exe 一启动就会报找不到文件的错误。解决套路是写一个小工具函数专门处理打包后的资源路径import os import sys def resource_path(relative_path): base getattr(sys, _MEIPASS, os.path.abspath(.)) return os.path.join(base, relative_path)打包时在 spec 文件或命令行里把资源目录加进去pyinstaller -F -w --add-data haarcascade_frontalface_default.xml;. --add-data face_model.yml;. main.py这里有一个 Windows 和 Linux 的经典差异--add-data的分隔符在 Windows 下是分号在 Linux 下是冒号。用错分隔符后文件看起来加进去了运行时依然找不到。-w表示不弹出控制台窗口但它也会把打印信息全吞掉建议第一次调试时别加-w先在命令行里跑一遍看报错。4.4 报告素材怎么攒中间图导出与 MATLAB 对照期末大作业通常还要交一份实验报告很多人到最后一天才发现截图不够。与其临时补不如在写代码时就把中间过程图导出。灰度图、直方图均衡化对比、人脸裁剪区域每个环节一张图报告就立起来了import cv2 import matplotlib.pyplot as plt img cv2.imread(sample.jpg, cv2.IMREAD_GRAYSCALE) equalized cv2.equalizeHist(img) hist_orig cv2.calcHist([img], [0], None, [256], [0, 256]) hist_eq cv2.calcHist([equalized], [0], None, [256], [0, 256]) plt.figure(figsize(8, 4)) plt.plot(hist_orig, labeloriginal) plt.plot(hist_eq, labelequalized) plt.legend() plt.savefig(hist_compare.png)这段代码把原图和均衡化后的直方图画到一张图上直接可以贴进报告。这里有一个小心机很多学校的图像处理大作业同时允许用 MATLAB但如果你的方案用 OpenCV 实现报告里放一张 OpenCV 和 MATLAB 处理同一张图的直方图对比既能说明你懂原理又能在答辩时应对“为什么用 OpenCV 不用 MATLAB”这类问题。你就说OpenCV 的 I/O 和摄像头采集链路更轻团队里后续要接嵌入式或服务端Python 生态更顺。理由越朴素越可信千万别贬低 MATLAB。5. 人脸识别大作业的避坑指南5 个最容易扣分的踩坑点5.1 训练时图片读取为空跑着跑着就报“找不到指定文件”现象是训练脚本执行到一半突然报错或者跳过一堆图最后模型训练出来识别率极低。原因主要有两个一是解压后的文件路径里有中文OpenCV 的imread在 Windows 上读中文路径经常静默失败返回None你的代码里如果没做None检查就会在使用空数组训练时报错二是数据集里混入了非图片文件比如 Mac 系统自动生成的.DS_Storeimread读不出任何内容。解决方法是训练脚本里加skip逻辑同时把整个项目放到全英文路径下。我习惯在采集阶段就约定“目录名和最后的 zip 文件名都只用英文和下划线”这个习惯能帮你避开无数个深夜崩溃。另一点是最好在imread后立刻检查返回数组是否为空而不是等训练到下一行才报错。5.2 识别框画在人脸旁边或者画框位置和实际人脸错位现象是检测框明显偏移比如框在左脸边上或者人脸在画面左侧时框就偏得更厉害。问题出在坐标系搞混detectMultiScale返回的(x, y, w, h)是针对原始灰度图坐标系的而predict输入的是裁剪并缩放后的face子图。如果你拿缩放后的子图去画框坐标当然对不上。解决方法是把检测框坐标和face子图分开处理检测用原图坐标预测用子图画框和写文字时回到原始(x, y, w, h)。这是一个代码结构问题不是算法问题写注释时把“原始坐标”和“子图坐标”标清楚答辩时也经得起追问。5.3 光线一暗或者侧面一点识别结果就开始乱飘现象是白天能稳定识别到了答辩教室的筒灯下就频繁 unknown侧脸甚至直接识别成另一个人。原因是 LBPH 对光照有一定容忍度但你的训练样本如果没有覆盖识别时的光照环境再好的特征也被打回原形。侧脸则基本无解因为 LBPH 的直方图没有姿态归一化能力。解决方法是采集阶段故意在两种光照下各拍一部分比如开灯拍一轮、关大灯开台灯再拍一轮不要只在一个角度下连续拍几十张那在模型里等于一张照片的重复。后期可以在预处理里加GaussianBlur去噪但别指望它能把侧脸救回来。更稳妥的策略是让 Demo 保持正脸演示老师如果要测试侧脸大方承认这是传统方法的边界顺势话锋一转提“如果换深度学习特征提取器这里可以做得更好”——这也是一种展示理解的答辩技巧。你有没有发现这其实是个“人跟场景适配”的问题不是纯代码问题。5.4 摄像头打不开或者画面跑一阵子就冻结现象是cap cv2.VideoCapture(0)返回了对象但cap.isOpened()是False或者演示开始没问题循环跑了一两分钟后画面卡死。原因通常是摄像头被其他软件占用、OpenCV 默认的 VideoCapture 后端在 Windows 上和笔记本摄像头的兼容性差以及 USB 带宽不够导致拉流中断。解决方法是给VideoCapture指定 Windows 后端一般能解决大部分兼容问题cap cv2.VideoCapture(0, cv2.CAP_DSHOW)CAP_DSHOW是 DirectShow 后端比默认后端对 USB 摄像头更友好。拉流中断的另一个常见原因是循环里没有正确给waitKey足够时间处理窗口事件也就是每帧都调用了imshow但waitKey的事件间隔太大或太小系统事件队列堵住后画面看起来就冻住了。保持waitKey(1)一般是安全的不要用 0除非你想做单步调试。最保底的方案是在答辩前用cv2.VideoWriter录一段演示视频把VideoCapture(0)换成VideoCapture(demo.mp4)这样即使现场摄像头驱动全崩你也能继续演示识别链路。5.5 演示现场识别框乱跳置信度忽高忽低现象是同一个人的脸稍微晃一下confidence 从 45 跳到 95识别框在脸上和背景间来回切换。原因有两层检测阶段minNeighbors太低导致误检置信度较高的错误框被送进了识别器或者预处理阶段没有做时序平滑每一帧独立判断抖动自然剧烈。解决方法是先调detectMultiScale参数把误检框压下去然后在识别结果上加一个简单的滑动窗口连续 N 帧识别到同一个人才更新画面上的名字否则保持上一次的结果。代码上可以维护一个last_name和连续计数变量。这种处理方式在真实门禁系统里很常见写在报告里也算一个技术亮点。不过别做太复杂课设规模下用“3 帧连续确认”就够。6. 交作业前的最后一晚验证模型可复现的 3 个技巧答辩前的晚上先把代码里的绝对路径清干净然后做的事就是验证“这个模型到底能不能复现”。第一件必做的事是留出集测试把数据集里每个人抽三到五张照片拿到模型上去预测统计准确率。注意这几张照片必须不参与训练否则就是在开卷考试测出来的数字没有任何说服力。如果留出集准确率低于八成先别急着调识别阈值回到数据采集环节补照片问题多半出在训练样本太单一。第二件必做的事是准备一条视频演示路径。用cv2.VideoWriter录制一段大约 30 秒、包含正脸靠近、左右轻微转头、退出画面重新进入的 mp4 文件然后把你识别脚本里的VideoCapture(0)换成VideoCapture(demo.mp4)。这样万一答辩教室的摄像头驱动有问题或者设备被占用你还可以用视频继续演示。视频文件一定要和模型、haarcascade 放在同一个目录下别只拷个 exe 过去常见翻车现场是现场解压后才发现漏了资源文件。cap cv2.VideoCapture(demo.mp4)第三件必做的事是把整个项目重新压缩成一个英文路径的 zip然后解压到一个全新目录按照“安装依赖→采集或读取数据→训练→识别”的顺序完整走一遍。我自己的习惯是把这个过程当成一次彩排命令一条条敲眼睛盯着每一步的输出如果哪一步报错就现场修改改完再把这个 zip 重新打一遍。这个动作很土但每年都能拦住一大批“在宿舍能跑、到教室就挂”的翻车事故。最后补一句经验之谈不要在答辩当天临时改阈值和训练集。所有的参数都应该是前一天定好的现场唯一能动的就是 confidence 阈值——我会把它定义在脚本最顶上方便现场根据教室光线微调。文字和画框的配色也提前调好别用太细的字体教室投影仪通常不会太清晰。祝你的大作业一次通过希望帮到你。本文还有配套的精品资源点击获取
返回列表