有没有办法用Python(可能使用OpenCV或PIL)连续抓取全部或部分屏幕的帧,至少15 fps或更高?我已经看到它用其他语言完成,所以理论上它应该是可能的。
我不需要将图像数据保存到文件中。我实际上只是希望它输出一个包含原始RGB数据的数组(比如在一个numpy数组或其他什么),因为我只是把它拿到并发送到一个大的LED显示器(可能在重新调整它之后)
答案 0 :(得分:19)
还有一个mss的解决方案可以提供更好的帧速率。 (使用MacOS Sierra在Macbook Pro上测试)
import numpy as np
import cv2
from mss import mss
from PIL import Image
mon = {'top': 160, 'left': 160, 'width': 200, 'height': 200}
sct = mss()
while 1:
sct.get_pixels(mon)
img = Image.frombytes('RGB', (sct.width, sct.height), sct.image)
cv2.imshow('test', np.array(img))
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
答案 1 :(得分:9)
您需要使用Pillow(PIL)库中的ImageGrab并将捕获转换为numpy数组。当你有阵列时,你可以使用opencv随心所欲。我将捕获转换为灰色,并使用imshow()作为演示。
这是一个快速入门的代码:
from PIL import ImageGrab
import numpy as np
import cv2
img = ImageGrab.grab(bbox=(100,10,400,780)) #bbox specifies specific region (bbox= x,y,width,height *starts top-left)
img_np = np.array(img) #this is the array obtained from conversion
frame = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)
cv2.imshow("test", frame)
cv2.waitKey(0)
cv2.destroyAllWindows()
你可以用你想要的频率在那里插入一个阵列来保持捕捉帧。之后,您只需解码帧。不要忘记在循环之前添加:
fourcc = cv2.VideoWriter_fourcc(*'XVID')
vid = cv2.VideoWriter('output.avi', fourcc, 6, (640,480))
并在循环内添加:
vid.write(frame) #the edited frame or the original img_np as you please
<强>更新强>
最终结果看起来像这样(如果你想实现一个帧流。存储为视频只是在捕获的屏幕上使用opencv的演示):
from PIL import ImageGrab
import numpy as np
import cv2
while(True):
img = ImageGrab.grab(bbox=(100,10,400,780)) #bbox specifies specific region (bbox= x,y,width,height)
img_np = np.array(img)
frame = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)
cv2.imshow("test", frame)
cv2.waitKey(0)
cv2.destroyAllWindows()
希望有所帮助
答案 2 :(得分:3)
我尝试了以上所有方法,但没有提供实时屏幕更新。 你可以试试看此代码已经过测试和成功运行,还为您提供了良好的fps输出。您还可以根据需要在每个循环时间对此进行判断。
import numpy as np
import cv2
from PIL import ImageGrab as ig
import time
last_time = time.time()
while(True):
screen = ig.grab(bbox=(50,50,800,640))
print('Loop took {} seconds',format(time.time()-last_time))
cv2.imshow("test", np.array(screen))
last_time = time.time()
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
答案 3 :(得分:2)
你可以尝试这个=&gt;
import mss
import numpy
with mss.mss() as sct:
monitor = {'top': 40, 'left': 0, 'width': 800, 'height': 640}
img = numpy.array(sct.grab(monitor))
print(img)
答案 4 :(得分:2)
根据这篇文章和其他文章,我做了这样的事情。 它无需保存img即可截取屏幕截图并将其写入视频文件。
import cv2
import numpy as np
import os
import pyautogui
output = "video.avi"
img = pyautogui.screenshot()
img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
#get info from img
height, width, channels = img.shape
# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output, fourcc, 20.0, (width, height))
while(True):
try:
img = pyautogui.screenshot()
image = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
out.write(image)
StopIteration(0.5)
except KeyboardInterrupt:
break
out.release()
cv2.destroyAllWindows()
答案 5 :(得分:1)
使用上述所有解决方案,直到我以以下方式修改代码后,我才能获得可用的帧速率:
import numpy as np
import cv2
from mss import mss
from PIL import Image
bbox = {'top': 100, 'left': 0, 'width': 400, 'height': 300}
sct = mss()
while 1:
sct_img = sct.grab(bbox)
cv2.imshow('screen', np.array(sct_img))
if cv2.waitKey(1) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
使用这种解决方案,我可以轻松获得每秒20帧以上的帧。
作为参考,请检查以下链接:https://python-mss.readthedocs.io/examples.html
答案 6 :(得分:1)
您可以尝试一下。此代码对我有用。我测试了Linux
import numpy as np
import cv2
from mss import mss
from PIL import Image
sct = mss()
while 1:
w, h = 800, 640
monitor = {'top': 0, 'left': 0, 'width': w, 'height': h}
img = Image.frombytes('RGB', (w,h), sct.grab(monitor).rgb)
cv2.imshow('test', np.array(img))
if cv2.waitKey(25) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
确保已安装以下软件包
枕头,opencv-python,numpy,mss
答案 7 :(得分:1)
如果有人想通过mss
库来寻找一种更容易,更快捷的屏幕抓取方法,请尝试从我的高性能视频处理ScreenGear
库中获取vidgear类。只需在任意计算机(已在所有平台上进行过测试,包括Windows 10,MacOS Serra,Linux Mint进行测试)上编写以下几行python代码,即可享受线程化的屏幕广播。
# import required libraries
from vidgear.gears import ScreenGear
import cv2
# define dimensions of screen w.r.t to given monitor to be captured
options = {'top': 40, 'left': 0, 'width': 100, 'height': 100}
# open video stream with defined parameters
stream = ScreenGear(monitor=1, logging=True, **options).start()
# loop over
while True:
# read frames from stream
frame = stream.read()
# check for frame if Nonetype
if frame is None:
break
# {do something with the frame here}
# Show output window
cv2.imshow("Output Frame", frame)
# check for 'q' key if pressed
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
# close output window
cv2.destroyAllWindows()
# safely close video stream
stream.stop()
VidGear库文档: https://abhitronix.github.io/vidgear
ScreenGear API: https://abhitronix.github.io/vidgear/gears/screengear/overview/
更多示例: https://abhitronix.github.io/vidgear/gears/screengear/usage/
答案 8 :(得分:0)
我尝试过ImageGrab
中的PIL
,它给了我20fps的感觉,但是使用win32库给了我+ 40fps的感觉!
我使用了Frannecklp的this代码,但是它不能很好地工作,所以我需要对其进行修改:
-首先使用pip install pywin32
,以防使用库
-改为这样导入库:
import cv2
import numpy as np
from win32 import win32gui
from pythonwin import win32ui
from win32.lib import win32con
from win32 import win32api
要获得简单的图像屏幕,请执行以下操作:
from grab_screen import grab_screen
import cv2
img = grab_screen()
cv2.imshow('frame',img)
并获取框架:
while(True):
#frame = grab_screen((0,0,100,100))
frame = grab_screen()
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q') or x>150:
break
答案 9 :(得分:0)
对于opencv来说,此任务非常简单,我们只是循环捕获屏幕截图,并将其转换为帧。我创建了用于录制屏幕的计时器,开始时,您必须输入要录制的秒数:)这是代码。
import cv2
import numpy as np
import pyautogui
from win32api import GetSystemMetrics
import time
#Take resolution from system automatically
w = GetSystemMetrics(0)
h = GetSystemMetrics(1)
SCREEN_SIZE = (w,h)
fourcc = cv2.VideoWriter_fourcc(*"XVID")
out = cv2.VideoWriter("recording.mp4", fourcc, 20.0, (SCREEN_SIZE))
tim = time.time()
tp = int(input('How many times you want to record screen?->(Define value in Seconds): '))
tp = tp+tp
f = tim+tp
while True:
img = pyautogui.screenshot()
frame = np.array(img)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
out.write(frame)
tu = time.time()
if tu>f:
break
cv2.destroyAllWindows()
out.release()
这就是您可以在屏幕录像中使用时间的方式,您无需使用imshow(),因为它可以在屏幕上无限显示屏幕录像,因此输出视频看起来很奇怪。