简介:基于Python、OpenCV、Django与人脸识别库实现的人脸识别系统课程设计源码包,面向高校计算机相关专业学生,适用于毕业设计、课程大作业或人脸识别项目入门。项目已获导师指导并取得97分高分,代码完整且可直接运行,覆盖人脸图像采集、特征提取、模型训练、实时识别与人脸库管理的完整流程。资源共130个文件,包含19个Python源码、41个pyc编译文件、65张jpeg/png人脸样本图片、sqlite3数据库,以及用于模型存储的pb和data、index等TensorFlow文件,压缩包整体22.62MB,目录层级清晰,便于按模块阅读与复用;系统中内置训练好的模型,加载后即可进行识别测试,sqlite3库可保存人员信息与特征数据,方便管理多个注册人脸。目前已有883人学习下载。通过该项目可掌握Django Web框架与OpenCV、人脸识别库的整合方法,理解从图像输入到特征匹配的技术实现,还可在已有模型基础上扩展自己的识别场景,是快速上手实战项目的优质参考。
1. 课程设计里的"人脸识别系统",到底在做什么?
先说说这类课程设计最常见的尴尬:算法原理写了一大堆,却拿不出一套能当场演示的系统。而"基于Python+OpenCV+Django+人脸识别库实现的人脸识别系统"这个标题,正是把"能演示"当成了最高优先级——用OpenCV负责图像采集和处理,用人脸识别库给出特征向量,用Django把识别能力包成一个Web页面。你不用自己去训练卷积神经网络,也不需要了解太多人脸识别底层理论,只要把几个成熟组件串起来,就能做出一个"打开浏览器、上传照片、返回姓名"的闭环。
这篇文章写给正在做人脸识别课程设计、毕业设计,或者刚入门想知道这几个组件怎么串起来的人。全文按"选型→采集→特征→集成→排错→调优"推进,每一步都有可复现的命令和参数说明,你可以照着改,也可以把它当成答辩前的检查清单。
2. 技术栈拆解:为什么是 OpenCV + Django + 人脸识别库,而不是全端深度学习?
很多课程设计的题目只写了"人脸识别",但到底用什么算法、什么库,完全由你自己定。这里的核心权衡是:老师要看到的是一个能打开的Web系统,不是一个训练日志。所以选型的第一原则是"成熟、能跑、好调试"。
2.1 人脸识别库的选择:face_recognition 还是 dlib 还是 OpenCV 自带识别器
"人脸识别库"这几个字在不同源码里指代的东西不一样。常见的有三个:OpenCV自带的LBPH人脸识别器、dlib的人脸检测与特征提取、face_recognition——它是dlib的Python封装,把检测、特征提取、距离比对都收拢成了几行API。
我建议课程设计直接选face_recognition。一是API足够简单,face_recognition.face_encodings(image)直接返回128维特征向量,比对用face_distance就能拿到距离,新生不需要从头理解ResNet原理。二是识别效果稳定,它底层用的是dlib的ResNet模型,在教室、宿舍这类场景里比LBPH可靠得多。三是它能一次性检测多张脸,张合影里可以返回多组特征,课程设计答辩时这是个加分项。
不是说LBPH不能用。如果你做的是"静态人脸的简单识别",LBPH也能跑,但它本质上是在灰度直方图上做统计,遇到光照变化、表情变化,准确率掉得很快。我见过同学答辩现场戴个眼镜,LBPH就认不出来了,这种翻车不止一次。
| 方案 | 检测方式 | 特征维度 | 上手难度 | 课程设计推荐度 |
|---|---|---|---|---|
| OpenCV LBPH | Haar+直方图 | 可变 | 低 | 一般 |
| dlib 原生 | HOG/CNN | 128 | 中 | 一般 |
| face_recognition | dlib封装 | 128 | 低 | 推荐 |
你可能会问,为什么不直接用深度学习框架自己训练一个分类器?因为课程设计的时间成本不划算。自己训练CNN需要标注数据、调整超参、设计网络,最后效果还不一定比预训练模型好。更实际的做法是:人脸检测用dlib或OpenCV,特征提取用预训练模型,距离判断用欧氏距离,这套组合已经覆盖了"人脸识别"的完整链路。
2.2 Django 在系统里的职责边界:只做 Web 外壳,不做算法计算
第二个常见错误,是认为"Django人脸识别系统"需要把算法写进Django模型里。实际上Django只负责Web层:接收HTTP请求、解析上传文件、调用识别逻辑、返回JSON。识别计算是独立的Python函数,不属于Django的ORM、模板或管理后台。
为什么必须分开?因为人脸特征提取和比对是CPU密集操作,如果放在Django视图里同步执行,一个请求进来,服务器就会卡住,其它访问全部排队。课程设计演示时,浏览器一直转圈,老师会觉得系统很卡。
我常用的结构是:Django项目里建一个recognition应用,应用下放两个模块,views.py处理请求,service.py封装识别函数。views.py不直接import face_recognition,而是调用service.recognize。这样以后想换成TensorFlow或ONNX模型,只需要改service.py。
数据流是这样的:前端上传图片 -> urls.py路由到views.recognize_upload -> request.FILES取文件 -> service.recognize(image_bytes) -> 返回人脸位置、名字、距离 -> JsonResponse。整个过程不碰数据库,因为人脸特征库是pickle文件,识别是内存操作,不需要持久化。
课程设计里要不要建数据库?这取决于题目要求。如果老师要求"用户注册""考勤记录",那就需要Django自带的sqlite加一张表存日志。如果只是认人,用文件特征库就够了,还能避免ORM序列化向量这种麻烦事。
2.3 最小环境安装:从 python 安装到 opencv 安装,一次跑通
环境是第一个大坑。很多同学照着网上的python安装教程装完Python,转头import cv2报错,或者装face_recognition时dlib编译失败。我一般建议用Python 3.8到3.11之间的版本,别追最新,因为有些预编译轮子还没跟上。安装时记得勾选"Add Python to PATH",否则后面pip都不认。
然后创建虚拟环境。Windows下是python -m venv venv,激活后命令行前面会出现(venv)。这一步很重要,避免把包装到系统Python里造成版本冲突。
python -m venv venv # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate pip install --upgrade pip pip install django opencv-python face_recognition numpy参数说明:opencv-python是最常用的发行包,它包含cv2模块,安装体积较大。不要再装opencv-contrib-python,两个包一起装容易出现二进制冲突,这也是我踩过的坑。face_recognition在Windows上安装时,如果报"CMake is required"或"Microsoft Visual C++ 14.0 is required",需要先安装CMake和Visual Studio Build Tools,因为dlib要从源码编译。
如果你不想折腾编译,可以换一条路:用Anaconda环境,conda install -c conda-forge dlib python-face-recognition,conda会直接提供编译好的包。但在时间紧张时,我建议直接装face_recognition,通常一条pip命令就能好。装完之后,用一行命令验证环境:
python -c "import cv2, django, face_recognition; print(cv2.__version__, django.get_version())"如果输出版本号,说明基础环境已经通了。后面所有翻车都从这之后开始。
3. 数据准备:用 OpenCV 采集人脸样本,预处理成识别库要的格式
识别系统的地基是数据。很多课程设计失败在于只给每个人拍了一张正脸照,然后抱怨识别不准。我的习惯是每人采集20到50张样本,覆盖正面、左右偏转、抬头低头、室内光、靠窗光。这样特征库里有足够变化,阈值才有意义。
3.1 人脸采集脚本:摄像头连续抓帧、自动检测并裁剪对齐
采集阶段不需要face_recognition,直接用OpenCV就够了。采集只要求"能检测到人脸并保存",OpenCV的Haar级联检测器在CPU上跑得很快,不依赖外部模型,不容易翻车。以下是一个完整的小脚本。
import cv2 import os person_name = "zhangsan" # 建议用英文/拼音,避开中文路径 save_dir = os.path.join("dataset", person_name) os.makedirs(save_dir, exist_ok=True) cap = cv2.VideoCapture(0) if not cap.isOpened(): raise IOError("无法打开摄像头,请检查驱动或换 index") # 用 OpenCV 自带的 Haar 人脸检测器 face_cascade = cv2.CascadeClassifier( cv2.data.haarcascades + "haarcascade_frontalface_default.xml" ) count = 0 max_samples = 30 while count < max_samples: ret, frame = cap.read() if not ret: continue gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale( gray, scaleFactor=1.1, minNeighbors=5, minSize=(120, 120) ) for (x, y, w, h) in faces: # 检测框向外扩 20%,避免只截到脸中部 x0 = max(0, x - int(0.2 * w)) y0 = max(0, y - int(0.2 * h)) x1 = min(frame.shape[1], x + int(1.2 * w)) y1 = min(frame.shape[0], y + int(1.2 * h)) face = frame[y0:y1, x0:x1] # 统一缩放到 160x160,保证后续特征提取输入稳定 face = cv2.resize(face, (160, 160)) cv2.imwrite(os.path.join(save_dir, f"{count:03d}.jpg"), face) count += 1 cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) cv2.imshow("capture", frame) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows() print(f"已保存 {count} 张样本到 {save_dir}")逻辑说明:detectMultiScale直接返回人脸矩形坐标。我用max(0, ...)防止裁剪越界,用外扩比例让上额和下巴都保留下来。resize到160x160是所有样本统一尺寸,这样不管摄像头是1080P还是720P,特征提取的输入都是一致的。
参数说明:scaleFactor=1.1表示每次搜索窗口缩小10%,这个值越小检测越精确但越慢,课程设计里1.1到1.2都行;minNeighbors=5表示一个候选框被连续5次检测才算数,等于5时误检少但可能漏检,如果你发现框不住人脸,可以降到3。minSize=(120,120)过滤掉太远的、像素不足的人脸。
3.2 图像预处理:灰度、直方图均衡化、归一化的真实作用
采集脚本里我只做了灰度化和resize,没做更多预处理。为什么?因为face_recognition内部有自己的人脸对齐,它的模型期望输入是RGB图,你如果提前转成灰度反而少了一个通道的信息。这里有一个课程设计里常见的误区:把OpenCV图像处理里学的灰度化、均衡化、高斯模糊一股脑用在人脸识别前置,效果未必好。
但这不代表预处理没用。OpenCV图像处理在人脸识别里的正确用途是"图像质量修正":当光线暗、对比度低时,可以用cv2.equalizeHist对灰度图做直方图均衡化,增加暗部细节。下面这行可以放在保存前:
# 采集时把原始图和均衡化图各存一套,后面用识别率决定用哪套 gray_eq = cv2.equalizeHist(gray) # 保存均衡化后的灰度图,文件名加 _eq 后缀注意:如果用均衡化后的灰度图做特征提取,识别时也要走同样的预处理链路,否则训练识别不一致。我遇到过同学训练时用均衡化,识别时直接传原图,准确率明显下降。
归一化的作用则体现在后期。无论你用什么识别库,输入图像的像素范围最好一致。OpenCV读出来是BGR、0到255,face_recognition.load_image_file读出来是RGB、0到255,底层模型自己有归一化,所以外部不需要除以255。你只需要保证图像尺寸接近模型训练时的尺寸,这就是我统一resize到160x160的原因。
3.3 数据目录组织与样本清洗:直接决定特征库质量
采集完的数据目录要清晰,推荐结构:
dataset/ zhangsan/ 000.jpg, 001.jpg, ... lisi/ 000.jpg, 001.jpg, ...这样后面遍历时,os.listdir("dataset")拿到的人名就是标签。比把标签写在文件名里更安全,因为文件名可能含特殊字符。
样本清洗是很多人忽略的一步。采集过程中会混入模糊帧、重复帧、甚至拍到别人脸但保存到当前人目录下的坏数据。我的习惯是采集完先人工扫一遍,把模糊的、闭眼的、拍到侧脸的删掉;如果某个人样本少了,重新采集补上。实际经验是:10张高质量样本比50张低质量样本更好。
4. 特征提取与 Django 集成:从 128 维向量到 Web 注册/识别接口
采集完图片后,下一步是把每张图转成一个128维向量。这是人脸识别的核心:不是比较图片像素,而是比较向量距离。face_recognition封装了dlib的模型,一行face_encodings就能完成检测、对齐和特征提取。
4.1 用 face_recognition 批量提取特征,保存到本地特征库
写一个独立的生成特征库脚本,不要把它放Django视图里,否则每次启动都要重新提取。下面这个脚本遍历dataset目录下每个人名文件夹,提取所有样本的特征,保存成pickle文件。
import os import pickle import face_recognition dataset_dir = "dataset" known_encodings = [] known_names = [] for name in os.listdir(dataset_dir): person_dir = os.path.join(dataset_dir, 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) image = face_recognition.load_image_file(img_path) encodings = face_recognition.face_encodings(image) if len(encodings) > 0: known_encodings.append(encodings[0]) known_names.append(name) else: print(f"跳过无脸图片: {img_path}") with open("face_db.pkl", "wb") as f: pickle.dump({ "encodings": known_encodings, "names": known_names, }, f) print(f"特征库保存完毕,共 {len(known_names)} 条记录")逻辑说明:遍历dataset目录下每个人名文件夹,逐张提取特征。如果图片中检测不到人脸,face_encodings返回空列表,这一条直接跳过,避免把脏数据塞进特征库。最后用pickle把所有人和特征的对应关系存下来,下次启动秒级加载。
参数说明:known_encodings里每个元素是一个numpy数组,形状是(128,)。如果一个文件夹里有20张图,就生成20条向量,names列表里对应的name重复20次。比对时,一张待识别脸会和全部向量算欧氏距离,然后取最近的那个。
这里有个提速技巧:如果样本已经裁剪好,可以用face_recognition.face_encodings(image, known_face_locations=[(0, h, w, 0)])手动传入人脸框,跳过检测阶段。但前提是你确认每张图只有一个脸且已经对齐,否则不要用。
4.2 创建 Django 项目与应用:从项目结构到识别核心视图
Django部分是课程设计的门面。首先创建项目和app。常见做法是:项目名叫face_project,应用叫recognition。
django-admin startproject face_project cd face_project python manage.py startapp recognition这两条命令完成之后,去face_project/settings.py的INSTALLED_APPS里加上'recognition'。这是django创建app后必做的一步,漏掉的话后面很多功能会不生效。然后编辑recognition/views.py,写识别接口。为了演示方便,我用csrf_exempt装饰器关闭POST校验,但注意这只是课程设计里的简化做法,真正生产项目不能用csrf_exempt。
# recognition/views.py import pickle import numpy as np import face_recognition from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt # 模块加载时读一次特征库,避免每次请求都读文件 with open("face_db.pkl", "rb") as f: db = pickle.load(f) known_encodings = np.array(db["encodings"]) known_names = db["names"] @csrf_exempt def recognize_upload(request): if request.method != "POST": return JsonResponse({"error": "请用 POST 提交"}, status=405) upload = request.FILES.get("image") if not upload: return JsonResponse({"error": "缺少 image 字段"}, status=400) image = face_recognition.load_image_file(upload) face_locations = face_recognition.face_locations(image) face_encodings = face_recognition.face_encodings(image, face_locations) results = [] for i, encoding in enumerate(face_encodings): # 用欧氏距离找最近的人脸 distances = face_recognition.face_distance(known_encodings, encoding) best_idx = int(np.argmin(distances)) name = known_names[best_idx] distance = float(distances[best_idx]) location = face_locations[i] if i < len(face_locations) else None results.append({ "name": name, "distance": distance, "location": [int(v) for v in location] if location else None, }) return JsonResponse({"faces": results})逻辑说明:face_locations返回图中每个人脸的位置,face_encodings再根据位置提取特征。这样就支持一张照片里有多个人。每个待识别向量与所有已知特征算距离,取最小距离作为预测结果;至于这个最小距离到底算不算"同一个人",由阈值决定,后面章节细讲。
参数说明:known_encodings转成np.array后,face_distance可以批量计算,速度比Python循环快很多。如果只有一个人脸,distance小于0.45一般可以认为是本人;但如果你的数据集只有5个人,这个值可以放松到0.5,因为类间距离比较近。
4.3 路由与测试接口:用 curl 验证识别接口通不通
写完视图还要配路由。在recognition/urls.py里写:
from django.urls import path from . import views urlpatterns = [ path("recognize/", views.recognize_upload, name="recognize_upload"), ]然后在face_project/urls.py里include一下。这一步很多新手会漏,结果访问404。配置完后,先不用写前端页面,用curl或Postman测试接口更省事。下面用curl测试上传一张测试图片:
curl -X POST -F "image=@test_zhangsan.jpg" http://127.0.0.1:8000/recognize/如果识别成功,返回JSON里会有name字段;如果返回error,多半是文件字段名不对,或者特征库路径没有放在manage.py所在目录。这里有个坑:pickle文件的路径是相对于当前工作目录的,你用python manage.py runserver启动时,工作目录是项目根目录,所以face_db.pkl要放在项目根目录,否则就会报FileNotFoundError。
5. 避坑:人脸识别系统最常见的 5 个翻车现场
这部分不是理论,几乎每条都是我在实际调试里遇到过的。按"现象→原因→解决"写,方便你对着排错。
5.1 OpenCV 打不开摄像头:index=0 不是万能的
现象:cv2.VideoCapture(0)成功实例化,但read()一直返回False,窗口黑屏;或者直接报"can't open camera by index"。
原因:笔记本有多个摄像头时,系统分配的不一定是0;如果摄像头被微信、浏览器占用,也会独占设备;在虚拟机上,摄像头设备默认没被桥接进来。
解决:写一个小脚本循环尝试index=0到3,看哪个能读到帧。如果本地实在没有摄像头,就不要用实时采集,改成上传图片演示。在云服务器上做课程设计时,我一般直接用上传图片这个路线,省掉摄像头的变量。
5.2 中文路径导致 Dlib 读取图片失败
现象:数据集目录叫"张三",特征提取时dlib报错或返回的encodings为空。OpenCV的imread遇到中文路径也会返回None,但不会报错,导致后面一片混乱。
原因:dlib和部分OpenCV版本在Windows下使用C接口读取文件,系统默认编码不是UTF-8,中文路径被截断。
解决:最省事的方法是把所有目录和图片文件名都改成英文、拼音或数字,比如zhangsan_001.jpg。如果你的图片已经是中文名,可以用np.fromfile加cv2.imdecode来读,但我不建议在课程设计里额外引入这个链路,改文件名最稳。Django上传的文件名同样处理,否则会存成乱码。
5.3 face_recognition 安装时 dlib 编译失败:CMake 和 VS Build Tools 才是根源
现象:pip install face_recognition时,终端滚动一大段后报错"Failed building wheel for dlib"、"CMake is required"或"Microsoft Visual C++ 14.0 is required"。
原因:dlib没有对应你Python版本的预编译wheel,需要本地编译。编译依赖C++编译器、CMake和Python开发头文件,缺一个就失败。
解决:先安装Visual Studio Build Tools,安装时勾选"使用C++的桌面开发";再安装CMake,安装时勾选"Add CMake to system PATH";然后重试pip install face_recognition。如果你用的是Anaconda,更省事的方式是conda install -c conda-forge dlib python-face-recognition,由conda直接提供编译好的包。这个细节能救很多人。
5.4 Django debug 模式下的内存泄漏与特征库重新加载
现象:识别接口第一次调用正常,第二次开始越来越慢,内存占用缓慢上涨,最后服务器卡死。
原因:把特征库加载写在了视图函数里,每个请求都重新读取pickle、重新创建dlib对象,旧对象没有被及时释放。Django开发服务器又是多线程,累积起来就拖垮了进程。
解决:把特征库加载放到模块顶层,即views.py的import之后、视图函数之外。模块在进程启动时加载一次,所有请求共享同一个列表。还要注意,如果特征是numpy数组,加载后尽量用np.array包一层,避免列表转数组的隐式转换重复发生。课程设计用runserver演示没问题,但别拿runserver当生产服务器,它默认是单进程、不适合并发。
5.5 识别率忽高忽低:光线、角度、模糊才是幕后黑手
现象:同一个人在白天能识别,傍晚识别失败;正脸能识别,侧脸30度就失败;照片稍微模糊就认错。
原因:人脸识别模型虽然由CNN训练出来的,但它对图像质量非常敏感。录入的照片如果是顺光、正面,识别时一旦换个光照,特征分布就会偏移。模糊图像经过dlib检测后,人脸特征提取出的向量也可能偏离正常范围。
解决:采集样本时要覆盖场景变化。比如白天窗边拍10张,晚上开灯拍10张,戴不戴眼镜各拍几张。识别端可以加一个清晰度判断,用cv2.Laplacian计算方差,方差小于某个阈值就返回"图片模糊,请重拍"。这是一个很实用的OpenCV图像处理技巧,能挡住一大半误识别。
6. 把课程设计做成"能演示"的系统:阈值调优与性能进阶
6.1 tolerance 阈值怎么调:查表法找最优
face_recognition的compare_faces默认threshold=0.6,这个值偏宽松,可能把两个不同的人判成同一个人。课程设计演示时,如果只是"上传张三返回张三",0.6没问题;但如果还要"上传李四不能识别成张三",就必须收紧阈值。
我一般准备10张确实匹配的图和10张不匹配的图,算距离后遍历0.3到0.7之间的阈值,选误报最少、漏报最少的点。这个流程不需要机器学习框架,用Python算术就能跑。
import numpy as np # 假设 test_distances 是真实匹配的距离,false_distances 是不匹配的距离 best_t = 0.5 best_score = 0.0 for t in np.arange(0.3, 0.7, 0.01): true_pos = np.mean([d <= t for d in test_distances]) false_pos = np.mean([d <= t for d in false_distances]) score = true_pos - false_pos if score > best_score: best_score = score best_t = t print("最优阈值:", best_t)这段代码的逻辑是:把两个距离数组分别比较,选一个让"该认出的都认出、不该认出的都不认"的t。课程设计不要求严谨ROC,只要这个分数最大就能用。
参数说明:t的扫描范围0.3到0.7是人脸识别常见的经验区间。小于0.3太严,容易漏检;大于0.7太松,几乎来谁都是熟人。如果你的特征库只有一个人,threshold可以设到0.5以内。
6.2 实时视频识别 vs 上传图片识别:两种演示场景的取舍
答辩时老师可能要看实时摄像头,也可能只看上传图片。我建议主演示用上传图片,因为可控。实时视频一旦现场光线不好或人离镜头远,很容易翻车。
实时识别的性能参数是隔帧处理和缩放。face_recognition做一次特征提取在CPU上要几十到一百毫秒,全帧处理会卡。常见做法是每3帧取一帧,并把画面缩小一半,速度能提升4倍。
# 实时识别主循环中的关键片段 frame_idx = 0 while True: ret, frame = cap.read() if not ret: break frame_idx += 1 if frame_idx % 3 != 0: # 每隔2帧才处理一帧 continue small = cv2.resize(frame, (0, 0), fx=0.5, fy=0.5) rgb = cv2.cvtColor(small, cv2.COLOR_BGR2RGB) locs = face_recognition.face_locations(rgb) encs = face_recognition.face_encodings(rgb, locs) # 下面再遍历 encs 和 known_encodings 做比对这里把frame缩到一半,处理像素变成原来的四分之一,dlib检测时间会大幅下降。但代价是人脸区域变小,如果人脸本身在画面里只有100像素,缩小后就不到50像素,可能检测不到。所以实时演示时要保证人脸贴近镜头,或者不要缩得太狠,fx=0.75也可以。
6.3 性能进阶:特征库常驻内存与更快的加载方式
最后一个能明显提升体验的技巧是让特征库真正"常驻内存"。前面views.py里已经放在模块顶层了,但Django的runserver默认使用自动重载,每次修改代码都会重启整个进程,特征库也会重新加载。这本身不是问题,问题是你可能没意识到"重启一次要等好几秒"。
更稳的方案是写一个独立的service模块,初始化一次,之后不管怎么改视图代码都不会重建。另外,pickle加载速度很快,但如果特征库非常大,比如几千条,加载耗时也会增加。这时可以把已知特征转成numpy数组,用np.load/np.save存成.npy格式,加载更快。
# 保存时也可以用 np.savez 同时存向量和名字 np.savez("face_db.npz", encodings=np.array(known_encodings), names=known_names) # 加载时只需一行 data = np.load("face_db.npz")这个npz格式比pickle略小一点,课程设计里不值得大书特书,但能给老师一种"你考虑了性能"的印象。
我做这套系统时最深的教训是:不要一开始就追求准确率,先把"拍脸→存特征→上传→比对→显示"这条链路跑通,再回头调阈值和性能。人脸识别本身不难,难的是数据质量和环境一致性。希望帮到你。
本文还有配套的精品资源,点击获取