Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
用Python从屏幕捕获视频数据_Python_Opencv_Numpy_Screenshot - Fatal编程技术网

用Python从屏幕捕获视频数据

用Python从屏幕捕获视频数据,python,opencv,numpy,screenshot,Python,Opencv,Numpy,Screenshot,Python(可能是OpenCV或PIL)有没有办法连续抓取屏幕的全部或部分帧,至少15 fps或更多?我在其他语言中看到过,所以理论上应该是可能的 我不需要将图像数据保存到文件中。实际上,我只想让它输出一个包含原始RGB数据的数组(比如numpy数组或其他东西),因为我只想将它发送到一个大的LED显示屏上(可能在重新调整大小之后)。您需要使用Pillow(PIL)库中的ImageGrab并将捕获转换为numpy数组。当您拥有阵列时,您可以使用opencv随心所欲地使用它。我将捕获转换为灰色,并

Python(可能是OpenCV或PIL)有没有办法连续抓取屏幕的全部或部分帧,至少15 fps或更多?我在其他语言中看到过,所以理论上应该是可能的


我不需要将图像数据保存到文件中。实际上,我只想让它输出一个包含原始RGB数据的数组(比如numpy数组或其他东西),因为我只想将它发送到一个大的LED显示屏上(可能在重新调整大小之后)。

您需要使用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):


希望这会有所帮助

还有一种解决方案可以提供更好的帧速率。(使用MacOS Sierra在Macbook Pro上测试)

你可以试试这个=>

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)

我尝试了以上所有方法,但没有给我实时的屏幕更新。 你可以试试这个。这段代码已经过测试并成功运行,同时也为您提供了良好的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

我从
PIL
尝试了
ImageGrab
,它给了我20fps的速度,这还可以,但是使用win32库给了我+40fps的速度,这真是太棒了

我使用了Frannecklp的代码,但它工作不太好,所以我需要修改它:

-首先
pip在使用库的情况下安装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

基于这篇文章和其他文章,我做了这样的事情。 它是在不保存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()

使用上述所有解决方案,我无法获得可用的帧速率,直到我以以下方式修改代码:

import numpy as np
import cv2
from mss import mss
from PIL import Image

bounding_box = {'top': 100, 'left': 0, 'width': 400, 'height': 300}

sct = mss()

while True:
    sct_img = sct.grab(bounding_box)
    cv2.imshow('screen', np.array(sct_img))

    if (cv2.waitKey(1) & 0xFF) == ord('q'):
        cv2.destroyAllWindows()
        break
使用此解决方案,我可以轻松获得每秒20多帧


请查看此链接以供参考:

您可以尝试此代码,因为它对我有用。我已经在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', cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR))
    if cv2.waitKey(25) & 0xFF == ord('q'):
        cv2.destroyAllWindows()
        break
确保已安装以下软件包:


枕头、opencv python、numpy、mss

使用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(),因为它在屏幕上无限显示我们的屏幕录制,所以输出视频看起来很奇怪。

如果有人想用
mss
库更简单、更快地抓取屏幕,那么请尝试我的高性能视频处理库中的类。只要在任何机器上编写这几行python代码(在所有平台上测试,包括Windows10、MacOSSerra、LinuxMint),就可以享受线程屏幕转换

# 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库文档:

ScreenGear API:



更多示例:

不确定您所说的“您可以按自己喜欢的频率插入阵列以继续捕获帧”是什么意思。。。阵列在哪里?我根本不需要做视频输出。。。有没有一种方法可以指定屏幕上的抓取位置?我的意思是说添加一个whilelook来获取屏幕截图流。我现在就编辑代码。对于指定特定区域,请使用bbox参数。一分钟后,我将进行更新。我做了进一步的更改。希望有帮助这基本上使用了
ImageGrab.grab()
,根据我的经验,它非常慢(在我的MacBookPro 2015上大约2 fps)。按照OP的要求,此解决方案的捕获速度不能超过15fps。我还尝试了
mss
库,它速度快得多,但我无法保证图像之间有稳定的fps或定期间隔。ImageGrab仅适用于macOS和Windows。我获得的值错误:使用图像时图像数据不足。FromBytes使用i7 2600k,我在录制1440p监视器时仅获得8fps。截至2019年7月,此代码将触发此错误:“AttributeError:'MSS'对象没有属性'get_pixels'。@YakovK若要避免此问题,请安装MSS的旧版本:
pip卸载MSS
pip安装MSS==2.0.22
另一种解决方法是使用
MSS().grab(窗口)
代码看起来与此类似:
screenshot=mss.mss().grab(窗口)
img=Image.frombytes(“RGB”)、(screenshot.width、screenshot.height)、screenshot.RGB)
在使用Python 3.6的Windows上尝试了这一点,在我的i7 6700k CPU上获得了大约10 fps。循环耗时{}秒。这是我的FPS吗?不,这是两帧处理之间的时间差。。。差别越小越好。你可以做另一个计算,比如分析每60秒处理多少帧的差异…MacMini上每秒2.5帧,而Markoe7的方法渲染速度大于65帧谢谢你。第18行有两个输入错误,你应该传递img not image,第19行你应该传递image not img。谢谢,没有注意到,只是想把它放在一起:D(很快就会修好)Mac Mini上的65fps-太棒了!保存为.npy文件很容易,我每10-15ms会得到一帧。结果是100FPS-67FPS。我想SSD在这方面也起到了重要的作用。很好的方法,使用这种方法平均可以获得90 fps。这种方法很有效,但速度真的不快,至少在依赖外部工具的linux上是如此e> scrot来实际拍摄屏幕截图。我的3个月几乎需要半秒钟
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()
# 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()