python - 如何以 60fps+ 将所有屏幕像素读入 python numpy 数组
问题描述
第一次问关于SO的问题。
我正在尝试找到一种快速实时阅读屏幕的方法(60fps+)。numpy 的屏幕截图是一种快速方法,但与该速度不匹配。像素的这个问题有一个绝妙的答案:使用 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。我不知道该怎么做,所以任何帮助将不胜感激。(编辑:此链接可能指的是Python 中的不安全图像处理,如 C# 中的 LockBits)
还有另一种方法可以获取位图的内存地址,但我不知道如何处理它。那里的逻辑是我应该能够从该点将内存读取到任何 numpy 数组中,但我无法做到这一点。
任何其他快速阅读屏幕的选项也将受到赞赏。
必须有一种方法,GPU 知道在每个位置绘制哪些像素,这意味着这里必须有一个内存库或我们可以利用的数据流。
PS为什么要求高速?我正在研究已经有很多开销的工作自动化工具,我希望优化屏幕数据流以帮助项目的这一部分。
解决方案
下面的代码使用 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 的原始重新打包缓冲区将是一个更好的解决方案。
推荐阅读
- dataframe - 将组特定函数应用于 Julia 数据帧
- vercel - 如何将节点服务器部署到 Vercel?
- asp.net-core - 基于 UI 的角色管理 asp.net core 5.0 razor pages
- mysql - 每次我构建容器时 docker-compose 清除数据库
- python - 使用 python 在应用程序中执行重复性任务
- prolog - 域声明中的 CLPFD "OR" 条件
- function - 不能在方案编程中定义这样的功能
- android-activity - 对活动生命周期感到困惑
- vb.net - 继承属性与设置 BindableAttribute
- c - 将局部变量名称与 c 中的参数名称相同是一种不好的做法吗?