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
相关产品推荐
相关产品推荐

