树莓派2B上OpenCV-Python多进程优化FPS及用法正确性咨询
优化OpenCV-Python多进程FPS的方案(树莓派2 Model B)
嘿,Toan!我看了你在树莓派上的OpenCV多进程代码,目前的FPS表现不太理想,主要是因为你的多进程用法存在几个关键问题。咱们一步步来梳理和优化:
一、当前代码的核心问题
- 多进程没有持续运行:你调用
readThread()和resizeThread()只是启动了一次读取和resize进程,它们执行一次就结束了,主循环里还是在同步执行_update_frame()和_resize(),等于没用到多进程的异步能力。 - 多进程共享变量不安全:直接在多进程里修改
self.current_frame是错误的——多进程有独立的内存空间,修改的只是当前进程内的副本,主进程根本拿不到更新后的数据,还会导致数据竞争。 - 没有用队列做进程间通信:进程间安全传递数据必须用
multiprocessing.Queue,而不是直接共享实例变量。
二、优化后的实现思路
我们把整个流程拆成三个独立的进程,各司其职:
- 帧读取进程:持续从摄像头抓取原始帧,放到原始帧队列。
- 帧预处理进程:从原始帧队列取帧,执行resize操作,放到处理后的帧队列。
- 主进程:从处理后的帧队列取帧,显示并计算FPS。
这样每个任务都在独立进程里运行,充分利用树莓派的四核CPU,避免单进程阻塞带来的性能瓶颈。
三、修改后的代码
webcam.py
import cv2 from multiprocessing import Process, Queue import time class Webcam: def __init__(self): # 初始化两个队列:一个存原始帧,一个存处理后的帧(限制大小避免内存溢出) self.raw_frame_queue = Queue(maxsize=2) self.processed_frame_queue = Queue(maxsize=2) # 启动帧读取和预处理的后台进程 self.start_capture_process() self.start_preprocess_process() def _capture_frames(self): # 持续读取摄像头帧的独立进程 cap = cv2.VideoCapture('/dev/video2') # 优先设置摄像头输出分辨率,减少后续resize开销(如果摄像头支持) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) while True: ret, frame = cap.read() if not ret: print("摄像头读取失败,重试中...") time.sleep(0.1) continue # 队列未满时才放入新帧,避免阻塞读取进程 if not self.raw_frame_queue.full(): self.raw_frame_queue.put(frame) time.sleep(0.001) def _preprocess_frames(self): # 持续处理帧的独立进程(resize操作) while True: if not self.raw_frame_queue.empty(): frame = self.raw_frame_queue.get() # 若已通过摄像头设置分辨率,可省略此resize步骤 resized_frame = cv2.resize(frame, (1280, 720), cv2.INTER_AREA) if not self.processed_frame_queue.full(): self.processed_frame_queue.put(resized_frame) time.sleep(0.001) def start_capture_process(self): capture_process = Process(target=self._capture_frames, daemon=True) capture_process.start() def start_preprocess_process(self): preprocess_process = Process(target=self._preprocess_frames, daemon=True) preprocess_process.start() def get_frame(self): # 从处理后的队列取帧,队列为空时返回None if not self.processed_frame_queue.empty(): return self.processed_frame_queue.get() return None
main.py
from webcam import Webcam import cv2 import time webcam = Webcam() fps_count = 0 start_time = time.time() while True: frame = webcam.get_frame() if frame is None: # 无帧时短暂休眠,避免空循环占用过高CPU time.sleep(0.005) continue # 每秒计算一次FPS(比逐帧计算更准确) fps_count += 1 elapsed_time = time.time() - start_time if elapsed_time >= 1: fps = fps_count / elapsed_time print(f"FPS: {fps:.2f} | 帧尺寸: {frame.shape}") fps_count = 0 start_time = time.time() # 显示帧 cv2.imshow("Frame", frame) # 调整waitKey时间,降低CPU占用同时保证显示响应 if cv2.waitKey(10) & 0xFF == ord('q'): break cv2.destroyAllWindows()
四、额外优化小技巧
- 优先设置摄像头参数:如果你的摄像头支持直接输出1280x720分辨率,一定要提前设置,省去后续resize的计算开销。
- 控制队列大小:队列
maxsize设为2-3即可,既保证缓冲避免丢帧,又不会占用过多内存。 - 使用守护进程:设置
daemon=True,主进程退出时子进程会自动结束,避免遗留僵尸进程。 - 降低主进程负载:主进程只负责显示和FPS计算,所有帧处理逻辑都交给子进程。
按照这个方案修改后,你应该能看到FPS有明显提升——树莓派2B的四核CPU可以被充分利用,把帧读取、预处理和显示的任务完全解耦,避免单进程阻塞带来的性能浪费。
内容的提问来源于stack exchange,提问作者ToanVnET
相关产品推荐
相关产品推荐

