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

OpenCV多进程运行多路YOLO视频目标检测冻结问题排查

问题描述

基于PyTorch与OpenCV实现YOLO算法目标检测模型,单路视频运行状态正常,但使用multiprocessing多进程同时测试多路视频时程序出现冻结,需要排查代码问题。

原始问题代码

import torch
import cv2
import time
from multiprocessing import Process

model = torch.hub.load('ultralytics/yolov5', 'custom', path='runs/best.pt', force_reload=True)

def detectObject(video,name):
    cap = cv2.VideoCapture(video)
    while cap.isOpened():
        pTime = time.time()
        ret, img = cap.read()
        cTime = time.time()
        fps = str(int(1 / (cTime - pTime)))
        if img is None:
            break
        else:
            results = model(img)
            labels = results.xyxyn[0][:, -1].cpu().numpy()
            cord = results.xyxyn[0][:, :-1].cpu().numpy()
            n = len(labels)
            x_shape, y_shape = img.shape[1], img.shape[0]
            for i in range(n):
                row = cord[i]
                # If score is less than 0.3 we avoid making a prediction.
                if row[4] < 0.3:
                    continue
                x1 = int(row[0] * x_shape)
                y1 = int(row[1] * y_shape)
                x2 = int(row[2] * x_shape)
                y2 = int(row[3] * y_shape)
                bgr = (0, 255, 0)  # color of the box
                classes = model.names  # Get the name of label index
                label_font = cv2.FONT_HERSHEY_COMPLEX  # Font for the label.
                cv2.rectangle(img, (x1, y1), (x2, y2), bgr, 2)  # Plot the boxes
                cv2.putText(img, classes[int(labels[i])], (x1, y1), label_font, 2, bgr, 2)
                cv2.putText(img, f'FPS={fps}', (8, 70), label_font, 3, (100, 255, 0), 3, cv2.LINE_AA)

        img = cv2.resize(img, (700, 700))
        cv2.imshow(name, img)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()

Videos = ['../Dataset/Test1.mp4','../Dataset/Test2.mp4']
for i in Videos:
    process = Process(target=detectObject, args=(i, str(i)))
    process.start()

运行日志

Downloading: "https://github.com/ultralytics/yolov5/archive/master.zip" to /home/com/.cache/torch/hub/master.zip
YOLOv5 🚀 2022-6-27 Python-3.9.9 torch-1.11.0+cu102 CPU

Fusing layers... 
YOLOv5s summary: 213 layers, 7023610 parameters, 0 gradients
Adding AutoShape... 
问题根因
  • 模型加载位置错误:在主进程全局作用域加载YOLO模型,Linux下默认fork模式启动子进程时,会直接复制主进程中已初始化的PyTorch上下文、模型内部锁状态,带锁的框架对象跨进程复制后会出现锁冲突,推理时直接卡死。
  • OpenCV GUI接口不支持跨进程调用:cv2.imshow、cv2.waitKey依赖HighGUI模块的全局单例状态,多进程并发调用这类接口会触发UI线程死锁。
  • 子进程未做回收:代码启动子进程后没有调用join()等待子进程运行,主进程提前退出会导致子进程状态异常,加剧冻结问题。
  • 多进程启动模式不兼容:PyTorch、OpenCV均不支持在fork出的子进程中直接使用主进程初始化的框架对象,默认启动模式存在大量隐式状态冲突。
  • 缺少多进程入口判断:没有加if __name__ == '__main__':保护,跨平台运行时会出现重复加载、递归启动进程的问题。
修复方案
  • 将模型初始化逻辑移入每个子进程的执行函数内部,保证每个进程独立加载模型、独立初始化PyTorch运行上下文,完全避免跨进程共享模型对象。
  • 所有OpenCV相关操作(视频流读取、绘制、窗口显示、按键监听)全部放在对应子进程内部执行,不跨进程传递任何OpenCV对象。
  • 主进程启动子进程后,统一调用join()等待所有子进程执行结束,避免主进程提前退出。
  • 多进程启动前设置启动模式为spawn,该模式会全新启动Python解释器进程加载资源,从根源上避免fork复制带来的状态冲突。
  • 增加多进程入口判断,保证跨平台运行正常。

修复后可运行代码

import torch
import cv2
import time
from multiprocessing import Process, set_start_method

def detectObject(video,name):
    # 每个子进程独立加载模型,不共享主进程资源
    model = torch.hub.load('ultralytics/yolov5', 'custom', path='runs/best.pt', force_reload=True)
    cap = cv2.VideoCapture(video)
    while cap.isOpened():
        pTime = time.time()
        ret, img = cap.read()
        if not ret or img is None:
            break
        cTime = time.time()
        fps = str(int(1 / (cTime - pTime)))
        results = model(img)
        labels = results.xyxyn[0][:, -1].cpu().numpy()
        cord = results.xyxyn[0][:, :-1].cpu().numpy()
        n = len(labels)
        x_shape, y_shape = img.shape[1], img.shape[0]
        for i in range(n):
            row = cord[i]
            # 置信度低于0.3跳过
            if row[4] < 0.3:
                continue
            x1 = int(row[0] * x_shape)
            y1 = int(row[1] * y_shape)
            x2 = int(row[2] * x_shape)
            y2 = int(row[3] * y_shape)
            bgr = (0, 255, 0)
            classes = model.names
            label_font = cv2.FONT_HERSHEY_COMPLEX
            cv2.rectangle(img, (x1, y1), (x2, y2), bgr, 2)
            cv2.putText(img, classes[int(labels[i])], (x1, y1), label_font, 2, bgr, 2)
        cv2.putText(img, f'FPS={fps}', (8, 70), label_font, 3, (100, 255, 0), 3, cv2.LINE_AA)
        img = cv2.resize(img, (700, 700))
        cv2.imshow(name, img)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    cap.release()
    cv2.destroyWindow(name)

if __name__ == '__main__':
    # 设置spawn启动模式,避免fork带来的上下文冲突
    set_start_method('spawn', force=True)
    Videos = ['../Dataset/Test1.mp4','../Dataset/Test2.mp4']
    process_list = []
    for video_path in Videos:
        p = Process(target=detectObject, args=(video_path, str(video_path)))
        p.start()
        process_list.append(p)
    # 等待所有子进程执行完毕
    for p in process_list:
        p.join()
    cv2.destroyAllWindows()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 08:18:33