☰
人脸识别系统毕设实战:从架构设计到部署优化
2026/10/27 16:58:22 网站建设 项目流程

简介:这份毕业设计资料包面向计算机视觉、图像处理与模式识别方向的高校学生,围绕人脸识别系统的完整设计与实现展开,涵盖图像采集与预处理、Haar特征与边缘检测、PCA/LDA及CNN模型训练、LFW与CASIA-WebFace等数据集处理,以及安防监控、门禁等实际应用场景的分析。资源共80个文件,以25个h头文件与24个cpp源文件构成核心程序,配合6个doc文档记录开题报告、摘要、目录与技术说明,另有dsp、dsw工程文件、mdb数据库、pdf参考文献及图标资源等,压缩包约2.18MB,工程结构完整、便于编译调试。已有210人学习下载,适合需要参考系统架构、算法选型与文档撰写范例的毕业生,可从中获取从需求分析到编程实现、测试优化的全流程思路。

1. 从一张“跑不起来”的毕设截图说起

去年帮一个学弟看他的人脸识别毕设,截图里终端报错刷了满屏,摄像头窗口一片漆黑,他跟我说“代码是网上抄的,环境装了两天”。这场景太典型了——人脸识别系统设计作为毕业设计选题,难点从来不在算法本身,而在把检测、对齐、特征比对、界面展示这几块拼成一个能稳定跑起来的完整链路。这份资源就是围绕这个目标组织的:一个可运行的人脸识别系统,覆盖从摄像头采集到识别结果输出的全流程,适合拿它当毕设底座、也适合想快速理解人脸识别工程落地的开发者。下面我按“它是什么、怎么跑、怎么改”的顺序,把这份代码拆开讲。

2. 系统架构与目录结构:一条人脸图片走过的完整链路

2.1 整体分层:采集层、算法层、业务层怎么切

人脸识别系统看着简单,真动手写就容易写成一锅粥——摄像头读取、人脸检测、特征提取、比对、界面刷新全塞在一个main.py里,改一处崩三处。这份项目的组织方式是典型的三层切分,我拆的时候第一件事就是确认这个边界清不清楚。

采集层负责拿到原始帧,可能是本地摄像头、视频文件,也可能是单张图片,统一封装成一个“帧来源”接口,上层不关心数据从哪来。算法层是人脸识别的心脏,拆成检测、对齐、特征提取、比对四个子步骤,每一步的输出是下一步的输入,中间结果可以落盘方便调试。业务层负责把算法结果翻译成人能看懂的东西——画框、标名字、显示相似度、记录识别日志。

这种切法的好处是每一层可以单独替换。比如你毕设想换检测模型,只动算法层的检测模块,采集和界面完全不用碰;想加个“批量导入图片识别”的功能,也只在业务层加一个入口。我见过太多毕设把这三层揉在一起,最后答辩前想加个功能直接推倒重来,血泪经验就是:先定边界,再写代码。

常见的目录结构大致是这样组织的:

face-recognition-system/ ├── app/ │ ├── main.py # 程序入口,启动界面和主循环 │ ├── ui/ # 界面相关 │ │ ├── main_window.py # 主窗口布局与事件绑定 │ │ └── widgets.py # 视频显示、结果面板等自定义控件 │ ├── core/ # 算法层 │ │ ├── detector.py # 人脸检测封装 │ │ ├── aligner.py # 人脸对齐(关键点矫正) │ │ ├── extractor.py # 特征提取 │ │ └── matcher.py # 特征比对与阈值判定 │ ├── service/ # 业务层 │ │ ├── recognize.py # 识别流程编排 │ │ └── register.py # 人脸注册入库 │ └── utils/ │ ├── config.py # 配置读取 │ └── logger.py # 日志 ├── data/ │ ├── faces/ # 注册人脸库(按人名分目录) │ └── features/ # 提取好的特征向量缓存 ├── models/ # 模型权重文件 ├── configs/ │ └── default.yaml # 阈值、路径、摄像头编号等 ├── requirements.txt └── README.md

这个结构不是死的,但几个关键点值得保留:core里每个算法步骤单独成文件,方便你逐个替换和单测;data/faces按人名分目录存注册照,注册流程直接遍历目录就能建库;configs把阈值、路径这些易变参数抽出来,答辩现场调阈值不用改代码。

2.2 核心数据流:一帧图像从进入到出结果

理解这份代码最快的办法,是跟一帧图像走一遍。下面这段是业务层识别流程的骨架,我按项目里的组织方式还原出来,逻辑和真实代码一致:

# app/service/recognize.py from app.core.detector import FaceDetector from app.core.aligner import FaceAligner from app.core.extractor import FeatureExtractor from app.core.matcher import FeatureMatcher class RecognizeService: def __init__(self, config): # 四个算法组件在初始化时加载模型,避免每帧重复加载 self.detector = FaceDetector(config['model']['detector']) self.aligner = FaceAligner(config['model']['landmark']) self.extractor = FeatureExtractor(config['model']['extractor']) self.matcher = FeatureMatcher( threshold=config['recognize']['threshold'], # 相似度阈值,默认 0.6 左右 feature_dir=config['paths']['feature_dir'] ) def process_frame(self, frame): # 1. 检测:返回每个人脸的框和五点关键点 faces = self.detector.detect(frame) results = [] for face in faces: # 2. 对齐:按关键点做仿射变换,把人脸摆正 aligned = self.aligner.align(frame, face['landmarks']) # 3. 提取:输出归一化后的特征向量(常见是 128 或 512 维) feature = self.extractor.extract(aligned) # 4. 比对:和特征库逐一算距离,取最近的一个 name, score = self.matcher.match(feature) results.append({ 'box': face['box'], 'name': name, 'score': score }) return results

这段代码有几个设计点值得说。第一,四个组件在__init__里一次性加载,模型加载是重操作,放主循环里每帧加载会卡到没法用,这是新手最容易翻车的地方。第二,process_frame只做编排,不掺任何算法细节,检测器返回什么格式、提取器输出多少维,都由各自模块保证,业务层只认接口。第三,matcher.match返回(name, score),识别不到时name给一个“未知”占位,界面层据此决定画什么颜色的框。

参数上,threshold是最需要调的:调高误识少但漏识多,调低反过来。毕设演示场景我一般建议从 0.6 起步,现场根据光照微调。feature_dir指向特征缓存目录,注册时提取一次存下来,识别时直接读,省掉每次启动重新提取全库特征的时间——人脸库上百张时这个差别非常明显。

2.3 界面与主循环:别让 UI 卡住算法

界面层用的是什么框架,取决于项目具体实现,常见做法是 PyQt 或 Tkinter 配 OpenCV 显示。不管哪种,主循环的结构都绕不开一个坑:算法处理一帧要几十毫秒,如果直接在 UI 线程里同步跑,窗口就会一顿一顿甚至假死。

项目里的处理方式是把“取帧—处理—显示”拆成节奏可控的循环,处理结果通过队列或信号回传给界面线程。下面是一个简化但可用的主循环写法:

# app/main.py(节选) import cv2 from app.service.recognize import RecognizeService from app.utils.config import load_config def run(): config = load_config('configs/default.yaml') service = RecognizeService(config) cap = cv2.VideoCapture(config['camera']['index']) # 默认 0 号摄像头 cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) while True: ok, frame = cap.read() if not ok: break results = service.process_frame(frame) for r in results: x1, y1, x2, y2 = r['box'] color = (0, 255, 0) if r['name'] != '未知' else (0, 0, 255) cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2) label = f"{r['name']} {r['score']:.2f}" cv2.putText(frame, label, (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.imshow('Face Recognition', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()

camera.index是摄像头编号,笔记本自带的一般是 0,外接 USB 摄像头可能是 1 或 2,读不到画面先改这个。分辨率设成 640×480 是性能和效果的折中,再高检测会明显变慢。waitKey(1)里的 1 是毫秒,太小界面刷新快但 CPU 占用高,太大画面卡顿,1 到 10 之间试。

如果项目用的是 PyQt,主循环会换成QTimer定时触发取帧,算法结果通过信号发回主线程更新控件,本质思路一样:算法和界面解耦,谁也别阻塞谁。这一点在答辩演示时尤其重要,界面一卡,评委的第一印象就没了。

3. 环境搭建与跑通:从零到摄像头出框的实操步骤

3.1 依赖安装与模型文件放置

拿到代码第一件事不是急着python main.py,而是把依赖和模型这两样东西备齐。人脸识别项目跑不起来,八成栽在这两处。依赖清单在requirements.txt里,核心就几样:OpenCV 负责图像读写和显示,NumPy 做向量运算,深度学习框架(常见是 PyTorch 或 ONNX Runtime)跑检测和特征提取模型,界面框架按项目选型。

安装时我一般建议先建虚拟环境,避免和系统里其他项目的包版本打架:

# 创建并激活虚拟环境(Windows 用 venv\Scripts\activate) python -m venv venv source venv/bin/activate # 安装依赖,国内网络慢可以加镜像源 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

装完先别跑主程序,用一行命令验证关键包能不能正常导入:

python -c "import cv2, numpy; print(cv2.__version__, numpy.__version__)"

能打印出版本号说明基础环境没问题。如果报DLL load failed,多半是 OpenCV 和系统位数或依赖库不匹配,重装对应版本即可。

模型文件是第二个坎。项目里models/目录下应该放着检测模型、关键点模型、特征提取模型三类权重,文件名和configs/default.yaml里配置的路径必须对得上。常见做法是权重文件体积较大不随代码分发,需要单独下载后按配置里的文件名放进models/。放好后打开配置文件核对一遍:

# configs/default.yaml(节选) model: detector: models/detector.onnx # 检测模型路径 landmark: models/landmark.onnx # 关键点模型路径 extractor: models/extractor.onnx # 特征提取模型路径 recognize: threshold: 0.6 # 相似度阈值 camera: index: 0 # 摄像头编号 paths: face_dir: data/faces # 注册照目录 feature_dir: data/features # 特征缓存目录

路径写相对路径时,注意程序的工作目录——在项目根目录下运行和在app/里运行,相对路径解析结果不一样,这是很隐蔽的一个坑,后面避坑章节会细说。

3.2 注册人脸库:先有“认识的人”才能识别

系统刚跑起来时特征库是空的,摄像头里谁都是“未知”,这很正常。识别的前提是先注册,把要认识的人脸特征存进库。注册流程一般是:准备每个人的几张正面照放进data/faces/人名/目录,然后跑注册脚本批量提取特征。

# app/service/register.py(核心逻辑) import os import cv2 import numpy as np from app.core.detector import FaceDetector from app.core.aligner import FaceAligner from app.core.extractor import FeatureExtractor def register_all(config): detector = FaceDetector(config['model']['detector']) aligner = FaceAligner(config['model']['landmark']) extractor = FeatureExtractor(config['model']['extractor']) face_dir = config['paths']['face_dir'] feature_dir = config['paths']['feature_dir'] os.makedirs(feature_dir, exist_ok=True) for person in os.listdir(face_dir): person_dir = os.path.join(face_dir, person) if not os.path.isdir(person_dir): continue features = [] for img_name in os.listdir(person_dir): img = cv2.imread(os.path.join(person_dir, img_name)) if img is None: continue faces = detector.detect(img) if len(faces) != 1: # 一张注册照必须恰好一张脸,多了少了都跳过并记录 print(f"跳过 {person}/{img_name}:检测到 {len(faces)} 张脸") continue aligned = aligner.align(img, faces[0]['landmarks']) features.append(extractor.extract(aligned)) if features: # 同一个人的多张特征取平均,降低单张照片质量的影响 mean_feature = np.mean(features, axis=0) np.save(os.path.join(feature_dir, f"{person}.npy"), mean_feature) print(f"注册完成:{person},使用 {len(features)} 张照片")

这段代码里有两个工程上的讲究。一是“一张注册照必须恰好一张脸”的校验,注册照里混进两个人脸或者压根没检测到脸,都会污染特征库,宁可跳过并打印出来让人补照片。二是同一个人的多张特征取平均,单张照片受光照、角度影响大,平均之后鲁棒性明显好一些,这是我在实际项目里验证过有效的土办法。

注册完data/features/下会多出张三.npy、李四.npy这样的文件,每个是一个特征向量。之后启动识别程序,matcher加载这些文件建索引,摄像头里再出现这些人就能认出来了。注册照的质量直接决定识别效果,建议每人 3 到 5 张,正面、不同光照、轻微角度变化各来一张。

3.3 启动与首次验证:确认整条链路通了

环境和人脸库都就绪后,在项目根目录执行入口:

python app/main.py

正常情况下会弹出摄像头窗口,画面里出现人脸时画绿框并显示名字和相似度,不认识的人画红框标“未知”。按q退出。第一次跑建议按这个顺序验证,出问题好定位:

  1. 窗口能不能弹出来——弹不出来是界面框架或显示后端的问题;
  2. 画面有没有图像——黑屏是摄像头编号不对或被其他程序占用;
  3. 人脸有没有框——有画面没框是检测模型没加载成功;
  4. 框上有没有名字——有框没名字是特征库为空或阈值设得太高。

这四步对应链路上的四个环节,哪一步断了就查哪一段,比对着满屏报错瞎猜高效得多。我一般还会打开日志看一眼模型加载耗时和每帧处理耗时,前者几百毫秒到几秒都正常,后者超过 100 毫秒就要考虑降分辨率或换轻量模型了。

4. 核心模块拆解:检测、对齐、特征、比对四段代码

4.1 人脸检测封装:把模型输出翻译成框和关键点

检测模块的职责很明确:输入一张图,输出若干人脸的边界框和关键点。不同检测模型的原始输出格式五花八门,有的直接给框,有的给一堆锚框偏移量需要解码,封装层的价值就是把这些差异挡在内部,对上只暴露统一接口。

# app/core/detector.py(封装思路) import cv2 import numpy as np class FaceDetector: def __init__(self, model_path, conf_threshold=0.5, nms_threshold=0.4): self.net = cv2.dnn.readNetFromONNX(model_path) self.conf_threshold = conf_threshold # 置信度阈值,低于此值的框丢弃 self.nms_threshold = nms_threshold # 非极大值抑制阈值,去掉重叠框 def detect(self, image): h, w = image.shape[:2] # 模型通常要求固定输入尺寸,这里按常见做法缩放到 640x640 blob = cv2.dnn.blobFromImage( image, 1.0 / 255, (640, 640), (0, 0, 0), swapRB=True, crop=False ) self.net.setInput(blob) outputs = self.net.forward() boxes = self._decode(outputs, w, h) # 解码成原图坐标 keep = self._nms(boxes) # 抑制重叠 return [boxes[i] for i in keep]

conf_threshold控制“多确定才算一张脸”,调低会检出更多但误检增加,调高则漏检。nms_threshold控制重叠框的合并力度,侧脸或遮挡时同一个脸可能出多个框,靠它去重。blobFromImage里的swapRB=True是因为 OpenCV 读进来是 BGR,而多数模型训练时用的是 RGB,这个参数忘了设,检测效果会莫名其妙地差——属于那种不报错但结果不对的玄学问题。

解码和 NMS 两个私有方法按模型实际输出格式实现,这里不展开,重点是接口约定:detect永远返回一个列表,每个元素含box(左上右下坐标)和landmarks(五点或更多关键点)。上层只依赖这个约定,换模型时只改这个文件。

4.2 人脸对齐:为什么识别前要先“摆正脸”

对齐这一步很多初学者会跳过,觉得检测到框直接裁出来送进特征提取就行。短期看好像也能跑,但识别准确率会明显吃亏。原因在于特征提取模型是在大量“摆正”的人脸上训练的,输入一张歪头、侧脸、眼睛不在水平线的图,提取出的特征和库里的对不上,相似度自然低。

对齐的做法是根据关键点(通常是两眼、鼻尖、两嘴角五点)算一个仿射变换矩阵,把人脸旋转缩放到标准姿态。核心代码不长,但参数含义值得说清:

# app/core/aligner.py import cv2 import numpy as np class FaceAligner: def __init__(self, output_size=(112, 112)): self.output_size = output_size # 对齐后输出尺寸,需与特征模型输入一致 # 标准五点位置(112x112 坐标系下),不同模型这套模板不同 self.ref_points = np.array([ [38.29, 51.69], # 左眼 [73.53, 51.50], # 右眼 [56.02, 71.73], # 鼻尖 [41.54, 92.36], # 左嘴角 [70.72, 92.20], # 右嘴角 ], dtype=np.float32) def align(self, image, landmarks): src = np.array(landmarks[:5], dtype=np.float32) # 相似变换:只做旋转、缩放、平移,不改变人脸比例 matrix, _ = cv2.estimateAffinePartial2D(src, self.ref_points) aligned = cv2.warpAffine( image, matrix, self.output_size, flags=cv2.INTER_LINEAR, borderValue=0.0 ) return aligned

output_size必须和特征提取模型要求的输入尺寸一致,常见是 112×112,设错了模型会报维度错误或者悄悄给出垃圾特征。ref_points是标准人脸的关键点模板,不同特征模型配套的模板不一样,用错了对齐结果会偏,识别率下降但不报错,属于隐蔽坑。estimateAffinePartial2D用的是相似变换而非全仿射,好处是不会把人脸拉伸变形,坏处是对大角度侧脸矫正能力有限——毕设场景够用,工业场景可能要上更复杂的三维对齐。

4.3 特征提取与比对:相似度阈值到底怎么定

特征提取把对齐后的人脸图送进模型,输出一个定长向量,常见 128 维或 512 维。这个向量的性质是:同一个人不同照片的向量距离近,不同人的距离远。比对就是算距离,最常用余弦相似度或欧氏距离。

# app/core/matcher.py import os import numpy as np class FeatureMatcher: def __init__(self, threshold, feature_dir): self.threshold = threshold self.names = [] self.features = [] for f in os.listdir(feature_dir): if f.endswith('.npy'): self.names.append(os.path.splitext(f)[0]) self.features.append(np.load(os.path.join(feature_dir, f))) # 堆成矩阵,比对时一次算完,比逐个循环快 self.features = np.stack(self.features) if self.features else None def match(self, feature): if self.features is None: return '未知', 0.0 # 余弦相似度:向量点积除以模长乘积 sims = self.features @ feature / ( np.linalg.norm(self.features, axis=1) * np.linalg.norm(feature) + 1e-8 ) idx = int(np.argmax(sims)) best = float(sims[idx]) if best < self.threshold: return '未知', best return self.names[idx], best

threshold是整个系统最需要现场调的参数。余弦相似度取值在 -1 到 1 之间,同一个人通常在 0.7 以上,不同人大多在 0.4 以下,中间地带就是误判高发区。设 0.6 是个稳妥起点,演示时如果发现熟人认不出,降到 0.5;如果陌生人被认成熟人,升到 0.7。1e-8是防止除零的小常数,特征向量全零的极端情况虽然少见,加上不亏。

矩阵化比对(self.features @ feature)比 Python 循环快一个数量级,人脸库几百上千条时差别明显。这也是为什么注册时把特征存成.npy而不是每次重新提取——启动时一次性加载成矩阵,识别时一次矩阵乘法出结果。

4.4 识别结果的后处理:连续帧投票降误判

单帧识别有个固有问题:某一帧光照突变或人脸转动,可能突然判成“未知”或认错人,界面上框的颜色一闪一闪,观感很差。工程上常见的补救是加一个短窗口的投票机制,连续几帧结果一致才确认。

# app/service/recognize.py 中可加的投票逻辑 from collections import deque, Counter class VoteSmoother: def __init__(self, window=5): self.window = window # 观察最近多少帧 self.history = deque(maxlen=window) def smooth(self, name): self.history.append(name) # 取窗口内出现次数最多的名字作为稳定结果 counter = Counter(self.history) return counter.most_common(1)[0][0]

window设 5 意味着看最近 5 帧,多数票决定当前显示。窗口太大反应迟钝,人脸换了名字还停在上一个人;太小起不到平滑作用。5 到 10 之间比较合适。这个机制对答辩演示特别有用,画面稳定,评委看着也舒服。注意投票要按人脸跟踪 ID 分组,多人场景下不能把不同人的结果混在一起投——简单做法是按框的位置做粗略关联,毕设场景一般够用。

5. 避坑与排查:那些不报错但结果不对的坑

5.1 摄像头黑屏或打不开

现象:程序启动后窗口弹出但画面全黑,或者直接报can't open camera。原因通常是摄像头编号不对、被其他程序占用,或者权限没给。解决:先把configs/default.yaml里的camera.index从 0 依次改成 1、2 试;关掉可能占用摄像头的会议软件、浏览器标签;Linux 下确认当前用户有视频设备访问权限。还不行就用cv2.VideoCapture单独写三行测试脚本,排除是系统问题还是项目问题。

5.2 模型加载失败但报错信息含糊

现象:启动时报文件找不到或维度不匹配,堆栈指向框架内部,看不出到底哪个模型出问题。原因多半是模型文件没放对位置、文件名和配置不一致,或者模型版本和代码里的输入尺寸约定不匹配。解决:先核对configs/default.yaml里三个模型路径,用ls models/确认文件真实存在且大小正常(几百 KB 到几十 MB,0 字节说明下载失败);再确认模型输入尺寸和代码里blobFromImage、output_size的设定一致。我一般会在加载每个模型后打一行日志,出问题时一眼看出卡在哪一个。

5.3 相对路径在不同目录下运行结果不同

现象:在项目根目录跑正常,进到app/目录里跑就报找不到模型或特征库。原因:配置里写的是相对路径,程序按当前工作目录解析,换个目录启动就指到别处去了。解决:要么统一在项目根目录启动,要么在config.py里把配置中的相对路径基于项目根目录转成绝对路径。后者更稳,我一般会在加载配置时做一次路径归一化,一劳永逸。

5.4 识别率低但代码没报错

现象:能检测到脸,也能比对,但熟人经常认不出,或者相似度普遍偏低。原因排查顺序:注册照质量差或数量少(先补照片);对齐模板和特征模型不配套(换回模型配套的关键点模板);swapRB设错导致颜色通道反了(检查blobFromImage参数);阈值设得过高(适当下调)。这类问题没有报错,只能靠对比实验定位,建议每次只改一个变量,改完记录识别率变化,别一次改一堆。

5.5 界面卡顿、帧率骤降

现象:画面一顿一顿,CPU 占用飙高。原因:算法在主线程同步跑、分辨率设太高、每帧重复加载模型。解决:确认模型只在初始化时加载一次;分辨率降到 640×480;算法处理放到独立线程,界面只负责显示;检测可以隔帧做(比如每两帧检测一次,中间帧沿用上次的框),帧率能明显回升。毕设演示对实时性要求不高,隔帧检测是性价比很高的优化。

6. 二次开发改造:从“能跑”到“能写进论文”的几步

把系统跑通只是起点,毕设要出彩,得在它上面做出自己的东西。我按改造难度从低到高给几条思路,每条都附验证方法,避免改完不知道有没有效果。

第一条是换检测或特征模型做对比实验。这是毕设里最容易写出内容的方向:保持其他模块不动,只替换core/detector.py或core/extractor.py里的模型,用同一批测试图片跑识别,记录准确率和耗时。验证方法很直接——准备一个几十张图的小测试集,每张标注正确人名,写个脚本批量跑process_frame统计 top-1 准确率。对比表格往论文里一放,工作量就立住了。注意换模型时对齐模板和输入尺寸要跟着改,这是最容易翻车的地方。

第二条是加活体检测或口罩识别。在识别流程前插一个判断模块,比如用简单的纹理或眨眼检测挡掉照片攻击,或者单独训练一个口罩分类器,识别时先判断是否戴口罩再决定走哪条特征比对路径。改造点在service/recognize.py的编排逻辑里加一个分支,算法模块单独新建文件,不动原有代码。验证时准备打印的照片和真人分别测试,看拦截率。

第三条是把识别结果落库做统计。加一个 SQLite 表记录每次识别的时间、人名、相似度,界面上加一个简单的出勤统计面板。这块改动集中在业务层,风险低但演示效果好,答辩时能讲“系统不只是识别,还有数据沉淀”。表结构大致这样:

CREATE TABLE recognize_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, person_name TEXT NOT NULL, -- 识别出的人名,未知也记录 score REAL NOT NULL, -- 相似度分数 created_at TEXT NOT NULL -- ISO 格式时间戳 );

写入时机放在process_frame返回结果之后,注意加个去重逻辑——同一个人连续多帧都识别到,别每帧都插一条,按时间窗口合并成一次记录。

改造时我踩过最深的坑是“改完不测边界”。有次调低了阈值想提高识别率,结果演示时把台下一位老师认成了库里的人,场面一度很尴尬。从那以后我每次调阈值或换模型,都强制走一遍“熟人 + 陌生人 + 侧脸 + 暗光”四组测试,四组都过了才敢拿去演示。这套习惯也建议你养成,毕设现场没有后悔药。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询