繁体   English   中英

在 Python 中从屏幕捕获视频数据

[英]Capture video data from screen in Python

有没有办法使用 Python(可能使用 OpenCV 或 PIL)连续抓取整个或部分屏幕的帧,至少以 15 fps 或更高的速度抓取? 我已经看到它用其他语言完成,所以理论上应该是可能的。

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

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

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

mon = {'left': 160, 'top': 160, 'width': 200, 'height': 200}

with mss() as sct:
    while True:
        screenShot = sct.grab(mon)
        img = Image.frombytes(
            'RGB', 
            (screenShot.width, screenShot.height), 
            screenShot.rgb, 
        )
        cv2.imshow('test', np.array(img))
        if cv2.waitKey(33) & 0xFF in (
            ord('q'), 
            27, 
        ):
            break

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

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+ 帧/秒。

作为参考,请查看此链接: OpenCV/Numpy example with mss

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

希望有帮助

基于这篇文章和其他帖子,我做了这样的事情。 它截取屏幕截图并写入视频文件而不保存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 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)

你可以试试这个代码,因为它对我有用。 我已经在 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

如果有人正在寻找一种更简单、更快捷的方式来使用mss库抓取屏幕,那么请尝试ScreenGear我的高性能视频处理vidgar库中的ScreenGear类。 只需在任何机器上编写这几行 python 代码(在所有平台上测试,包括 Windows 10、MacOS Serra、Linux Mint)并享受线程屏幕投射。

# 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/latest/gears/screengear/overview/

更多示例: https : //abhitronix.github.io/vidgear/latest/gears/screengear/usage/

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

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

我已经尝试过来自PIL ImageGrab ,它给了我 20fps,这还可以,但是使用 win32 库给了我 +40fps,这太棒了!

我使用了 Frannecklp 的这段代码,但它不能正常工作,所以我需要修改它:

- 首先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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM