【问题标题】:How to read all screen pixels into a python numpy array at 60fps+如何以 60fps+ 将所有屏幕像素读入 python numpy 数组
【发布时间】:2018-07-10 03:35:43
【问题描述】:

第一次问关于 SO 的问题。

我正在尝试寻找一种快速实时阅读屏幕的方法 (60fps+)。 numpy 的屏幕截图是一种快速方法,但与该速度不匹配。像素的这个问题有一个绝妙的答案:Most efficient/quickest way to parse pixel data with Python?

我尝试将 GetPixel 更改为这种用于 BMP 的长格式,但这会将其降低到 5fps:

t1 = time.time()
count = 0

width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)
while count < 1000:
    hwin = win32gui.GetDesktopWindow()
    hwindc = win32gui.GetWindowDC(hwin)
    srcdc = win32ui.CreateDCFromHandle(hwindc)

    memdc = srcdc.CreateCompatibleDC()

    bmp = win32ui.CreateBitmap()
    bmp.CreateCompatibleBitmap(srcdc, width, height)
    memdc.SelectObject(bmp)

    memdc.BitBlt((0, 0), (width, height), srcdc, (left, top), win32con.SRCCOPY)
    bmpinfo = bmp.GetInfo()
    bmpInt = bmp.GetBitmapBits(False)

    count +=1
t2 = time.time()
tf = t2-t1
it_per_sec = int(count/tf)
print (str(it_per_sec) + " iterations per second")

我观看了一个在 C# 上工作的人的 youtube 视频,他说 GetPixel 打开和关闭内存,这就是为什么对每个单独的像素执行 GetPixel 会有很多开销。他建议锁定整个数据字段,然后才执行getpixel。我不知道该怎么做,所以任何帮助将不胜感激。 (编辑:此链接可能指的是Unsafe Image Processing in Python like LockBits in C#

还有另一种方法可以获取位图的内存地址,但我不知道如何处理它。那里的逻辑是我应该能够从该点将内存读取到任何 numpy 数组中,但我无法做到这一点。

任何其他快速阅读屏幕的选项也将受到赞赏。

必须有一种方法,GPU 知道要在每个位置绘制哪些像素,这意味着这里必须有一个内存库或我们可以利用的数据流。

附:为什么要求高速?我正在开发已经有很多开销的工作自动化工具,我希望优化屏幕数据流以帮助项目的这一部分。

【问题讨论】:

  • 您可能需要图形硬件的合作才能在 C 中执行此操作,然后将绑定写入 Python 以允许它访问捕获的流。 NVIDIA 的 Capture SDK 可能是一个开始寻找的地方。
  • 流媒体软件如何工作?他们有某种访问权限,对吗?我会尝试检查 NVIDIA SDK,但希望它更通用,这样我也可以在我的英特尔集成笔记本电脑上试用它。
  • 驱动程序可以在数据发送到显示设备之前读取最终的帧缓冲区。

标签: python performance winapi screen frame-rate


【解决方案1】:

下面的代码使用 MSS,如果修改为显示无输出,则 1080p 可以达到 44fps。 https://python-mss.readthedocs.io/examples.html#opencv-numpy

import time

import cv2
import mss
import numpy


with mss.mss() as sct:
    # Part of the screen to capture
    monitor = {'top': 40, 'left': 0, 'width': 800, 'height': 640}

    while 'Screen capturing':
        last_time = time.time()

        # Get raw pixels from the screen, save it to a Numpy array
        img = numpy.array(sct.grab(monitor))

        # Display the picture
        #cv2.imshow('OpenCV/Numpy normal', img)

        # Display the picture in grayscale
        # cv2.imshow('OpenCV/Numpy grayscale',
        #            cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY))

        print('fps: {0}'.format(1 / (time.time()-last_time)))

        # Press "q" to quit
        if cv2.waitKey(25) & 0xFF == ord('q'):
            cv2.destroyAllWindows()
            break

仍然不完美,因为它不是 60fps+,如果可能的话,使用来自 GPU 的原始重新打包缓冲区将是一个更好的解决方案。

【讨论】:

    猜你喜欢
    • 2011-02-09
    • 1970-01-01
    • 2016-11-28
    • 2013-06-11
    • 2012-11-28
    • 2017-08-17
    • 2011-08-10
    相关资源
    最近更新 更多