基于Flask+MTCNN的人脸识别考勤系统webcam实时流开发报错求助
问题修复与需求实现方案
1 核心报错修复
你当前代码存在几个易引发报错的共性问题,直接修改即可:
- Flask debug模式会默认启动双进程重载,导致MTCNN重复初始化、摄像头被多次抢占报错,修改启动代码:
if __name__ == '__main__': # 关闭重载器,避免多进程资源冲突 app.run(debug=True, use_reloader=False)
- 不要在视频流生成器内初始化摄像头,每次请求都会重复打开设备引发冲突,将摄像头实例放到全局:
# 全局位置初始化,仅执行一次 cap = cv2.VideoCapture(0) detector = MTCNN() def generate_frame(): # 删掉函数内的cap = cv2.VideoCapture(0)代码 # 原有后续逻辑保留
- 模板文件名匹配问题:你路由中返回的是
test.html,但实际前端文件名为index.html,修改路由代码即可:
@app.route('/') def index(): return render_template('index.html')
2 点击按钮拍照功能实现
你当前代码是自动持续存图,不符合点击触发的需求,按如下修改即可:
后端代码修改
from flask import Flask, render_template, Response, jsonify from mtcnn.mtcnn import MTCNN import cv2 import os import numpy as np from datetime import datetime from src.preprocess import face_preprocess app = Flask(__name__) # 全局资源初始化 cap = cv2.VideoCapture(0) detector = MTCNN() # 拍照控制标记 save_flag = False save_dir = os.path.join('images', 'person_name') os.makedirs(save_dir, exist_ok=True) def generate_frame(): global save_flag faces = 0 frames = 0 max_faces = 50 max_bbox = np.zeros(4) # 改为永久循环,保证视频流不会中断 while True: ret, frame = cap.read() if not ret: continue frames += 1 dtString = str(datetime.now().microsecond) bboxes = detector.detect_faces(frame) if len(bboxes) != 0: max_area = 0 for bboxe in bboxes: bbox = bboxe["box"] bbox = np.array([bbox[0], bbox[1], bbox[0] + bbox[2], bbox[1] + bbox[3]]) keypoints = bboxe["keypoints"] area = (bbox[2] - bbox[0]) * (bbox[3] - bbox[1]) if area > max_area: max_bbox = bbox landmarks = keypoints max_area = area # 实时画人脸框,不管是否保存都要展示 cv2.rectangle(frame, (max_bbox[0], max_bbox[1]), (max_bbox[2], max_bbox[3]), (255, 0, 0), 2) # 仅触发拍照标记时才保存图片 if save_flag and frames % 3 == 0: landmarks = np.array([landmarks["left_eye"][0], landmarks["right_eye"][0], landmarks["nose"][0], landmarks["mouth_left"][0], landmarks["mouth_right"][0], landmarks["left_eye"][1], landmarks["right_eye"][1], landmarks["nose"][1], landmarks["mouth_left"][1], landmarks["mouth_right"][1]]) landmarks = landmarks.reshape((2, 5)).T nimg = face_preprocess.preprocess(frame, max_bbox, landmarks, image_size='112,112') cv2.imwrite(os.path.join(save_dir, "{}.jpg".format(dtString)), nimg) print("[INFO] {} Image Captured".format(faces + 1)) faces += 1 # 存满指定数量后关闭拍照标记 if faces >= max_faces: save_flag = False faces = 0 rete, buff = cv2.imencode('.jpg', frame) fr = buff.tobytes() yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + fr + b'\r\n\r\n') # 新增拍照触发路由 @app.route('/capture') def capture(): global save_flag save_flag = True return jsonify({"status":"success", "msg":"开始采集50张人脸,请正对摄像头"}) @app.route('/') def index(): return render_template('index.html') @app.route('/video') def video(): return Response(generate_frame(), mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == '__main__': app.run(debug=True, use_reloader=False)
前端代码修改(index.html)
<!DOCTYPE html> <html> <head> </head> <body> <h1>人脸考勤采集系统</h1> <img src="{{ url_for('video') }}" width="40%" height="450px"/> <br><br> <button onclick="triggerCapture()">点击采集人脸</button> <script> function triggerCapture() { fetch('/capture') .then(res => res.json()) .then(data => alert(data.msg)) } </script> </body> </html>
其他注意事项
- 确认项目目录下存在
src/preprocess.py文件,且face_preprocess.preprocess函数可正常调用,否则会报模块缺失错误 - 运行代码前确认摄像头没有被其他程序占用,且已经给Python授予了摄像头访问权限
内容的提问来源于stack exchange,提问作者Tejas
相关产品推荐
相关产品推荐

