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

树莓派2B上OpenCV-Python多进程优化FPS及用法正确性咨询

优化OpenCV-Python多进程FPS的方案(树莓派2 Model B)

嘿,Toan!我看了你在树莓派上的OpenCV多进程代码,目前的FPS表现不太理想,主要是因为你的多进程用法存在几个关键问题。咱们一步步来梳理和优化:

一、当前代码的核心问题

  • 多进程没有持续运行:你调用readThread()和resizeThread()只是启动了一次读取和resize进程,它们执行一次就结束了,主循环里还是在同步执行_update_frame()和_resize(),等于没用到多进程的异步能力。
  • 多进程共享变量不安全:直接在多进程里修改self.current_frame是错误的——多进程有独立的内存空间,修改的只是当前进程内的副本,主进程根本拿不到更新后的数据,还会导致数据竞争。
  • 没有用队列做进程间通信:进程间安全传递数据必须用multiprocessing.Queue,而不是直接共享实例变量。

二、优化后的实现思路

我们把整个流程拆成三个独立的进程,各司其职:

  1. 帧读取进程:持续从摄像头抓取原始帧,放到原始帧队列。
  2. 帧预处理进程:从原始帧队列取帧,执行resize操作,放到处理后的帧队列。
  3. 主进程:从处理后的帧队列取帧,显示并计算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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 20:14:07