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

MacOS下如何用Python(mss/pyautogui/PIL)提升截图FPS?

问题:MacBook Pro全屏截图帧率过低,如何优化至20FPS?

我正在为计算机视觉(CV)项目连续采集屏幕截图,但帧率(FPS)较低。当前使用的是2019款MacBook Pro,已尝试pyautogui、mss和PIL库,其中mss库的表现最佳,约为3FPS,截取局部屏幕时速度会快很多。这是普遍结果吗?如何进一步优化?参考相关方案后,spl的方案能达到约8FPS,但截取窗口变大时速度仍会下降。

以下是我的代码:

import PIL.ImageGrab
import cv2 as cv
import numpy as np
import os
from mss.darwin import MSS as mss
from time import time

os.chdir(os.path.dirname(os.path.abspath(__file__)))

loop_time=time()
with mss() as sct:
    # monitor = {"top": 500, "left": 500, "width": 500, "height": 500}
    while True:
        # screenshot = sct.grab(monitor)
        filename = sct.shot()
        cv_image = cv.imread(filename)  # Read the screenshot file
        cv_image = cv.cvtColor(cv_image, cv.COLOR_BGRA2BGR)  # Convert from BGRA to BGR

        cv.imshow("screen", cv_image)

        print('FPS{}'.format(1 / (time() - loop_time)))
        loop_time = time()
        if cv.waitKey(1) == ord("q"):
            break
cv.destroyAllWindows()

我希望实现全屏截图达到约20FPS的效果。


优化方案

1. 彻底消除磁盘IO开销(核心优化)

你当前代码的最大瓶颈是sct.shot()将截图写入磁盘,再用cv.imread()读取——磁盘IO的速度远慢于内存操作。直接用sct.grab()获取内存中的截图数据,跳过文件读写步骤,帧率会立刻提升。

优化后的代码:

import cv2 as cv
import numpy as np
from mss.darwin import MSS as mss
from time import time

with mss() as sct:
    # 取全屏区域(mss的monitors[0]对应整个屏幕)
    monitor = sct.monitors[0]
    loop_time = time()
    while True:
        # 直接在内存中捕获截图
        screenshot = sct.grab(monitor)
        # 转换为OpenCV兼容的numpy数组,再转BGR格式
        cv_image = np.array(screenshot)
        cv_image = cv.cvtColor(cv_image, cv.COLOR_BGRA2BGR)

        cv.imshow("screen", cv_image)

        print('FPS: {:.2f}'.format(1 / (time() - loop_time)))
        loop_time = time()
        if cv.waitKey(1) == ord("q"):
            break
cv.destroyAllWindows()

2. 降低截图分辨率/色彩深度

2019款MacBook Pro的全屏分辨率为2880×1800,像素量巨大。可以通过缩小分辨率减少计算和传输开销:

  • 捕获后直接缩放图像:在转BGR后添加cv_image = cv.resize(cv_image, (1440, 900))(缩至原尺寸一半)
  • 或者仅捕获屏幕的低分辨率镜像(macOS系统设置中开启“缩放”模式,让系统输出低分辨率画面,再捕获全屏)

如果CV项目对分辨率要求不高,这一步能让帧率接近20FPS。

3. 优化OpenCV显示环节

cv.imshow()的渲染会占用部分资源:

  • 如果不需要实时预览,直接注释掉cv.imshow()和cv.waitKey(),帧率会大幅提升(甚至超过20FPS)
  • 保留预览的话,用cv.setWindowProperty("screen", cv.WND_PROP_FULLSCREEN, cv.WINDOW_FULLSCREEN)设置全屏窗口,减少窗口装饰的渲染开销

4. 调用macOS原生API(高阶优化)

mss已经封装了原生框架,但直接调用Quartz(macOS核心图形框架)可以绕过Python库的额外开销,进一步提升帧率。

示例代码:

import cv2 as cv
import numpy as np
from Quartz import CGDisplayCreateImage, kCGDirectMainDisplay
from time import time

while True:
    loop_time = time()
    # 直接调用原生API获取主屏幕图像
    display_image = CGDisplayCreateImage(kCGDirectMainDisplay)
    # 转换为numpy数组
    width = display_image.width
    height = display_image.height
    cv_image = np.frombuffer(display_image.data, dtype=np.uint8).reshape((height, width, 4))
    cv_image = cv.cvtColor(cv_image, cv.COLOR_BGRA2BGR)

    cv.imshow("screen", cv_image)
    print('FPS: {:.2f}'.format(1 / (time() - loop_time)))
    if cv.waitKey(1) == ord("q"):
        break
cv.destroyAllWindows()

需要先安装pyobjc依赖:pip install pyobjc

5. 多线程分离任务

将截图捕获和图像处理/显示拆分为两个线程,避免捕获过程阻塞渲染线程。用队列传递截图数据,保证线程安全:

import cv2 as cv
import numpy as np
from mss.darwin import MSS as mss
from time import time
import threading
from queue import Queue

def capture_screen(sct, monitor, queue):
    while True:
        screenshot = sct.grab(monitor)
        queue.put(np.array(screenshot))

def process_and_show(queue):
    loop_time = time()
    while True:
        if not queue.empty():
            cv_image = queue.get()
            cv_image = cv.cvtColor(cv_image, cv.COLOR_BGRA2BGR)
            cv.imshow("screen", cv_image)

            print('FPS: {:.2f}'.format(1 / (time() - loop_time)))
            loop_time = time()
        if cv.waitKey(1) == ord("q"):
            break
    cv.destroyAllWindows()

if __name__ == "__main__":
    with mss() as sct:
        monitor = sct.monitors[0]
        queue = Queue(maxsize=2)  # 限制队列大小避免内存溢出
        capture_thread = threading.Thread(target=capture_screen, args=(sct, monitor, queue), daemon=True)
        capture_thread.start()
        process_and_show(queue)

关于“是否是普遍结果”

在2019款MacBook Pro上,用Python库实现全屏3-8FPS是正常情况——Python的GIL限制、macOS屏幕捕获的系统开销,都会影响帧率。但通过上述优化(尤其是消除磁盘IO+降低分辨率),达到15-20FPS完全可行。

内容的提问来源于stack exchange,提问作者Yixuan Wang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 01:31:02