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

Flask-SocketIO集成Yoloface:scan_face()仅首次调用有效求助

问题:Flask-SocketIO集成YOLO人脸识别仅首次请求生效

我开发的Flask服务端集成了SocketIO,Android客户端消息收发正常。但引入YOLO实现人脸识别后,scan_face()函数仅在第一次响应客户端scan_request事件时能返回正确结果;后续客户端发送scan_request时,该函数完全不执行,断点调试也被跳过,服务端仅持续监听请求。

控制台输出

flask run --host='0.0.0.0'
----- info -----
[i] Source of the camera:  0
[i] Path to output directory:  outputs/
###########################################################

==> Skipping create the outputs/ directory...
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://x.x.x.x:5000
 * Running on http://x.x.x.x:5000
Press CTRL+C to quit
x.x.x.x - - [25/Mar/2024 23:29:04] "GET /socket.io/?EIO=4&transport=polling HTTP/1.1" 200 -
Client connected to default namespace
x.x.x.x - - [25/Mar/2024 23:29:04] "POST /socket.io/?EIO=4&transport=polling&sid=iiua90AsbvoVBspJAAAA HTTP/1.1" 200 -
x.x.x.x - - [25/Mar/2024 23:29:04] "GET /socket.io/?EIO=4&transport=polling&sid=iiua90AsbvoVBspJAAAA HTTP/1.1" 200 -
x.x.x.x - - [25/Mar/2024 23:29:04] "GET /socket.io/?EIO=4&transport=polling&sid=iiua90AsbvoVBspJAAAA HTTP/1.1" 200 -
x.x.x.x - - [25/Mar/2024 23:29:04] "POST /socket.io/?EIO=4&transport=polling&sid=iiua90AsbvoVBspJAAAA HTTP/1.1" 200 -
check1
Received scan request: Scanne Person
Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.
200
227
254
[i] ==> # detected faces: 1
############################################################
value1
2gesichter
check2
person sent
2
check1
Received scan request: Scanne Person
check1
Received scan request: Scanne Person

关键代码片段

scan_request事件处理器

@socketio.on('scan_request')
def handle_scan_request(message):
    print('check1')
    print(f"Received scan request: {message}")
    scan_result = scan_face() # 仅首次调用生效
    print('check2')
    if scan_result == 1:
        get_person_by_id()
    elif scan_result == 0:
        person_not_detected()

scan_face()函数实现

import argparse
import sys
import os

from utils import *

SRC = 0
OUTPUT_DIR = 'outputs/'
MODEL_CFG = './cfg/yolov3-face.cfg'
MODEL_WEIGHTS = './model-weights/yolov3-wider_16000.weights'

print('----- info -----')
print('[i] Source of the camera: ', SRC)
print('[i] Path to output directory: ', OUTPUT_DIR)
print('###########################################################\n')

if not os.path.exists(OUTPUT_DIR):
    print('==> Creating the {} directory...'.format(OUTPUT_DIR))
    os.makedirs(OUTPUT_DIR)
else:
    print('==> Skipping create the {} directory...'.format(OUTPUT_DIR))

net = cv2.dnn.readNetFromDarknet(MODEL_CFG, MODEL_WEIGHTS)
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)


def scan_face():
    wind_name = 'face detection using YOLOv3'
    cv2.namedWindow(wind_name, cv2.WINDOW_NORMAL)

    cap = cv2.VideoCapture(SRC)

    value = None

    while True:
        has_frame, frame = cap.read()

        blob = cv2.dnn.blobFromImage(frame, 1 / 255, (IMG_WIDTH, IMG_HEIGHT),
                                     [0, 0, 0], 1, crop=False)

        net.setInput(blob)
        outs = net.forward(get_outputs_names(net))

        faces = post_process(frame, outs, CONF_THRESHOLD, NMS_THRESHOLD)
        print('[i] ==> # detected faces: {}'.format(len(faces)))
        print('#' * 60)

        info = [
            ('number of faces detected', '{}'.format(len(faces)))
        ]

        for (i, (txt, val)) in enumerate(info):
            text = '{}: {}'.format(txt, val)
            cv2.putText(frame, text, (10, (i * 20) + 20),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.7, COLOR_RED, 2)

        cv2.imshow(wind_name, frame)

        value = len(faces)
        print("value" + str(value))

        if value == 0:
            print('0gesicht')
            break
        elif value == 0: # 逻辑重复
            print('1gesicht')
            break
        else:
            print('2gesichter')
            break

    cap.release()
    cv2.destroyAllWindows()

    if value == 0:
        return 0
    else:
        return 1

问题原因与解决方案

核心问题

  1. 摄像头资源锁定:首次调用后,摄像头设备未被完全释放,后续无法重新打开,导致cap.read()失败,函数卡在循环中无法退出。
  2. 主线程阻塞:cv2.imshow()等GUI操作占用主线程资源,Flask-SocketIO单线程模式下,后续请求无法被处理。
  3. 逻辑冗余:scan_face()中判断分支重复,导致value==1的情况无法被正确识别。

修复步骤

  1. 移除GUI相关操作:服务端不需要可视化窗口,删除cv2.namedWindow()、cv2.imshow()代码,避免主线程被阻塞。
  2. 确保摄像头资源完全释放:使用try-finally块保证摄像头被释放,添加cv2.waitKey(1)强制刷新OpenCV资源:
def scan_face():
    cap = None
    try:
        cap = cv2.VideoCapture(SRC)
        if not cap.isOpened():
            print("[!] 无法打开摄像头")
            return 0
        
        has_frame, frame = cap.read()
        if not has_frame:
            print("[!] 无法读取摄像头帧")
            return 0

        blob = cv2.dnn.blobFromImage(frame, 1 / 255, (IMG_WIDTH, IMG_HEIGHT),
                                     [0, 0, 0], 1, crop=False)

        net.setInput(blob)
        outs = net.forward(get_outputs_names(net))

        faces = post_process(frame, outs, CONF_THRESHOLD, NMS_THRESHOLD)
        print('[i] ==> # detected faces: {}'.format(len(faces)))
        print('#' * 60)

        value = len(faces)
        print("value" + str(value))

    finally:
        if cap is not None:
            cap.release()
        cv2.destroyAllWindows()
        cv2.waitKey(1) # 强制释放资源

    return 0 if value ==0 else 1
  1. 用后台线程处理人脸识别:避免阻塞SocketIO事件主线程,修改事件处理器:
from threading import Thread

@socketio.on('scan_request')
def handle_scan_request(message):
    print('check1')
    print(f"Received scan request: {message}")
    # 启动后台线程执行检测
    Thread(target=process_scan).start()

def process_scan():
    scan_result = scan_face()
    print('check2')
    if scan_result == 1:
        get_person_by_id()
    elif scan_result == 0:
        person_not_detected()
  1. 修复逻辑错误:修正重复的判断分支:
if value == 0:
    print('0gesicht')
    break
elif value == 1:
    print('1gesicht')
    break
else:
    print('2gesichter')
    break
  1. 使用异步服务器:替换默认开发服务器,使用eventlet提升并发能力,修改启动方式:
if __name__ == '__main__':
    socketio.run(create_app(), host='0.0.0.0', debug=True)

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 08:52:02