简体   繁体   English

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

[英]Capture video data from screen in Python

Is there a way with Python (maybe with OpenCV or PIL) to continuously grab frames of all or a portion of the screen, at least at 15 fps or more?有没有办法使用 Python(可能使用 OpenCV 或 PIL)连续抓取整个或部分屏幕的帧,至少以 15 fps 或更高的速度抓取? I've seen it done in other languages, so in theory it should be possible.我已经看到它用其他语言完成,所以理论上应该是可能的。

I do not need to save the image data to a file.我不需要将图像数据保存到文件中。 I actually just want it to output an array containing the raw RGB data (like in a numpy array or something) since I'm going to just take it and send it to a large LED display (probably after re-sizing it).我实际上只是希望它输出一个包含原始 RGB 数据的数组(比如在一个 numpy 数组或其他东西中),因为我将把它发送到一个大型 LED 显示器(可能在重新调整大小之后)。

There is an other solution with mss which provide much better frame rate.还有另一种mss解决方案可以提供更好的帧速率。 (Tested on a Macbook Pro with MacOS Sierra) (在装有 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

With all of the above solutions, I was unable to get a usable frame rate until I modified my code in the following way:使用上述所有解决方案,我无法获得可用的帧速率,直到我按以下方式修改我的代码:

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

With this solution, I easily get 20+ frames/second.使用此解决方案,我可以轻松获得 20+ 帧/秒。

For reference, check this link: OpenCV/Numpy example with mss作为参考,请查看此链接: OpenCV/Numpy example with mss

You will need to use ImageGrab from Pillow (PIL) Library and convert the capture to numpy array.您将需要使用 Pillow (PIL) 库中的 ImageGrab 并将捕获转换为 numpy 数组。 When you have the array you can do what you please with it using opencv.当您拥有数组时,您可以使用 opencv 随心所欲地使用它。 I converted capture to gray color and used imshow() as a demonstration.我将捕获转换为灰色并使用 imshow() 作为演示。

Here is a quick code to get you started:这是一个快速入门的代码:

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()

you can plug an array there with the frequency you please to keep capturing frames.您可以以您喜欢的频率在那里插入一个阵列以继续捕获帧。 After that you just decode the frames.之后,您只需解码帧。 don't forget to add before the loop:不要忘记在循环之前添加:

fourcc = cv2.VideoWriter_fourcc(*'XVID')
vid = cv2.VideoWriter('output.avi', fourcc, 6, (640,480))

and inside the loop you can add:在循环内,您可以添加:

vid.write(frame) #the edited frame or the original img_np as you please

UPDATE更新
the end result look something like this (If you want to achieve a stream of frames that is. Storing as video just a demonstration of using opencv on the screen captured):最终结果看起来像这样(如果你想实现帧流。存储为视频只是在捕获的屏幕上使用 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()

Hope that helps希望有帮助

based on this post and others posts, i made something like this .基于这篇文章和其他帖子,我做了这样的事情。 Its taking a screenshot and writing into a video file without saving the img.它截取屏幕截图并写入视频文件而不保存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()

You can try this=>你可以试试这个=>

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)

You can try this code as it is working for me.你可以试试这个代码,因为它对我有用。 I've tested it on Linux我已经在 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

Make sure that the following packages are installed:确保安装了以下软件包:

Pillow, opencv-python, numpy, mss枕头,opencv-python,numpy,mss

If anyone looking for a much easier and faster way to grab screen with mss library, then try ScreenGear class from my high-performance video-processing vidgear library.如果有人正在寻找一种更简单、更快捷的方式来使用mss库抓取屏幕,那么请尝试ScreenGear我的高性能视频处理vidgar库中的ScreenGear类。 Just write these few lines of python code on any machine (Tested on all platforms, including Windows 10, MacOS Serra, Linux Mint) and enjoy threaded screen-casting.只需在任何机器上编写这几行 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 library Docs: https://abhitronix.github.io/vidgear VidGear 库文档: https ://abhitronix.github.io/vidgear

ScreenGear API: https://abhitronix.github.io/vidgear/latest/gears/screengear/overview/ ScreenGear API: https ://abhitronix.github.io/vidgear/latest/gears/screengear/overview/

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

I tried all of the above but it did not give me the real-time screen update.我尝试了上述所有方法,但它没有给我实时屏幕更新。 You can try this.你可以试试这个。 This code is tested and worked successfully and also give you a good fps output.此代码经过测试并成功运行,并且还为您提供了良好的 fps 输出。 You can also judge this by each loop time it's needed.您还可以根据需要的每个循环时间来判断。

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

This task is very simple with opencv, we are just capturing screenshots in loop, and converting it into frames.这个任务使用 opencv 非常简单,我们只是在循环中捕获屏幕截图,并将其转换为帧。 I created timer for screenrecording, in start you have to enter how many seconds you want to record:) Here is the code.我为屏幕录制创建了计时器,开始时您必须输入要录制的秒数:) 这是代码。

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()

So that's how you can use time in screen recording, you don't need to use imshow() because it shows infinitely our screen recording on-screen so output video looks weird.所以这就是你如何在屏幕录制中使用时间,你不需要使用 imshow() 因为它在屏幕上无限显示我们的屏幕录制所以输出视频看起来很奇怪。

I've tried ImageGrab from PIL and it gave me 20fps which is ok but using win32 libraries gave me +40fps which is amazing!我已经尝试过来自PIL ImageGrab ,它给了我 20fps,这还可以,但是使用 win32 库给了我 +40fps,这太棒了!

I used this code by Frannecklp but it didn't work just fine so I needed to modify it:我使用了 Frannecklp 的这段代码,但它不能正常工作,所以我需要修改它:

-Firstly pip install pywin32 in case using the libraries - 首先pip install pywin32以防使用库

-import the libraries like this instead: - 像这样导入库:

import cv2
import numpy as np
from win32 import win32gui
from pythonwin import win32ui
from win32.lib import win32con
from win32 import win32api

for geting a simple image screen do:要获得简单的图像屏幕,请执行以下操作:

from grab_screen import grab_screen
import cv2
img = grab_screen()
cv2.imshow('frame',img)

and for getting frames:和获取帧:

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