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

多进程实现单视频流运行多个人脸检测模型的问题排查

多进程实现单一视频流的多模型人脸检测

问题描述

尝试用多进程同时运行不同人脸检测模型,通过OpenCV读取摄像头视频流,但第二个进程(dlib_hog)无法接收帧报错。核心问题是多进程直接共享cv2.VideoCapture对象导致帧被抢占,且跨进程共享该对象本身不被支持。

原代码

import cv2
import dlib
from multiprocessing import Process

def haar_cascade():
    while True:
        ret,frame=cap.read()
        cv2.imshow('input',frame)
        if not ret:
            print("Can't receive frame (stream end?). Exiting ...")
            break
        classifier = cv2.CascadeClassifier('haarcascade_frontalface2.xml')
        faces = classifier.detectMultiScale(frame)
        for result in faces:
            x, y, w, h = result
            x1, y1 = x + w, y + h
            cv2.rectangle(frame, (x, y), (x1, y1), (0, 0, 255), 2)
        if cv2.waitKey(1) == ord('q'):
            break
        cv2.imshow('harr-cascade',frame)


def dlib_hog():
    while True:
        ret,frame=cap.read()
        if not ret:
            print("Can't receive frame (stream end?). Exiting ...")
            break
        detector = dlib.get_frontal_face_detector()
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = detector(gray, 1) # result
        #to draw faces on image
        for result in faces:
            x = result.left()
            y = result.top()
            x1 = result.right()
            y1 = result.bottom()
            cv2.rectangle(frame, (x, y), (x1, y1), (0, 0, 255), 2)
        if cv2.waitKey(1) == ord('q'):
            break
        cv2.imshow('dlib-hog',frame)


if __name__ == "__main__":
    cap =cv2.VideoCapture(0)
    if not cap.isOpened():
        print("Cannot open camera")
        exit()
    harrProcess=Process(target=haar_cascade)
    harrProcess.start()
    dlibProcess=Process(target=dlib_hog)
    dlibProcess.start()

# When everything done, release the capture
harrProcess.join()
dlibProcess.join()
cap.release()
cv2.destroyAllWindows()

核心问题分析

  • cv2.VideoCapture无法跨进程共享:每个进程拥有独立内存空间,主进程创建的cap对象在子进程中并非同一实例,直接调用read()会导致资源冲突。
  • 帧抢占问题:即使共享对象可行,两个进程同时调用read()会导致帧被其中一个进程读取后,另一个进程无法获取有效帧。
  • 模型重复初始化:循环内重复加载检测模型(如cv2.CascadeClassifier、dlib.get_frontal_face_detector()),严重降低运行效率。

修正方案

采用主进程读帧+队列分发的模式,主进程负责读取视频帧,通过multiprocessing.Queue将帧发送给各个检测子进程;同时统一处理退出信号,避免子进程无法正常终止。

修改后的代码

import cv2
import dlib
from multiprocessing import Process, Queue
import numpy as np

def haar_cascade(frame_queue):
    # 初始化模型,仅执行一次
    classifier = cv2.CascadeClassifier('haarcascade_frontalface2.xml')
    while True:
        frame = frame_queue.get()
        # 收到结束信号则退出
        if frame is None:
            break
        # 人脸检测与绘制
        faces = classifier.detectMultiScale(frame)
        for x, y, w, h in faces:
            cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2)
        cv2.imshow('haar-cascade', frame)
        # 处理窗口事件,避免卡顿
        if cv2.waitKey(1) == ord('q'):
            frame_queue.put(None)
            break
    cv2.destroyWindow('haar-cascade')

def dlib_hog(frame_queue):
    # 初始化模型,仅执行一次
    detector = dlib.get_frontal_face_detector()
    while True:
        frame = frame_queue.get()
        # 收到结束信号则退出
        if frame is None:
            break
        # 人脸检测与绘制
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = detector(gray, 1)
        for face in faces:
            x, y = face.left(), face.top()
            x1, y1 = face.right(), face.bottom()
            cv2.rectangle(frame, (x, y), (x1, y1), (0, 255, 0), 2)
        cv2.imshow('dlib-hog', frame)
        # 处理窗口事件,避免卡顿
        if cv2.waitKey(1) == ord('q'):
            frame_queue.put(None)
            break
    cv2.destroyWindow('dlib-hog')

if __name__ == "__main__":
    cap = cv2.VideoCapture(0)
    if not cap.isOpened():
        print("Cannot open camera")
        exit()
    
    # 创建队列用于传递帧,设置最大缓存避免内存溢出
    frame_queue = Queue(maxsize=10)
    
    # 启动子进程
    harr_process = Process(target=haar_cascade, args=(frame_queue,))
    dlib_process = Process(target=dlib_hog, args=(frame_queue,))
    harr_process.start()
    dlib_process.start()
    
    try:
        while True:
            ret, frame = cap.read()
            if not ret:
                print("Can't receive frame (stream end?). Exiting ...")
                break
            # 显示原始帧
            cv2.imshow('input', frame)
            # 发送帧的副本到队列,避免子进程修改原帧影响其他进程
            if not frame_queue.full():
                frame_queue.put(frame.copy())
            # 监听退出键
            if cv2.waitKey(1) == ord('q'):
                break
    finally:
        # 发送结束信号给子进程
        frame_queue.put(None)
        # 等待子进程退出
        harr_process.join()
        dlib_process.join()
        # 释放资源
        cap.release()
        cv2.destroyAllWindows()

关键优化点

  • 队列分发帧:主进程统一读取帧,通过队列将帧的副本发送给每个子进程,确保所有进程拿到相同的帧。
  • 模型预初始化:将检测模型的初始化放在循环外,避免重复加载,提升运行效率。
  • 统一退出机制:主进程捕获q键后,向队列发送None作为结束信号,确保子进程能正常退出并释放资源。
  • 帧副本传递:发送frame.copy()避免子进程修改原帧导致其他进程的帧被篡改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 18:35:16