You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 16:03:02