web-dev-qa-db-fra.com

Capturer des données vidéo de l'écran en Python

Existe-t-il un moyen avec Python (peut-être avec OpenCV ou PIL) de saisir en continu des images de tout ou partie de l’écran, au moins à 15 ips ou plus? Je l'ai vu faire dans d'autres langues, donc en théorie cela devrait être possible. 

Je n'ai pas besoin de sauvegarder les données d'image dans un fichier. En fait, je veux juste qu'il émette un tableau contenant les données RVB brutes (comme dans un tableau numpy ou quelque chose du genre), car je vais juste le prendre et l'envoyer à un grand écran LED (probablement après le redimensionner).

10
Adam Haile

Il existe une autre solution avec mss qui fournit un taux de trame bien meilleur (Testé sur un Macbook Pro avec MacOS Sierra)

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
16
Neabfi

Vous devrez utiliser ImageGrab from Pillow (PIL) Library et convertir la capture en tableau numpy. Lorsque vous avez le tableau, vous pouvez faire ce que vous voulez en utilisant opencv. J'ai converti la capture en couleur grise et utilisé imshow () à titre de démonstration.

Voici un code rapide pour vous aider à démarrer: 

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

vous pouvez y brancher un tableau avec la fréquence qui vous convient pour continuer à capturer des images. Après cela, il vous suffit de décoder les cadres. n'oubliez pas d'ajouter avant la boucle:

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

et dans la boucle, vous pouvez ajouter:

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

METTRE À JOUR
le résultat final ressemble à quelque chose comme ceci (Si vous voulez obtenir un flux d’images, c’est-à-dire stocker en vidéo simplement une démonstration de l’utilisation d’opencv sur l’écran capturé):

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

J'espère que cela pourra aider

9
ibininja

J'ai essayé tout ce qui précède, mais cela ne m'a pas donné la mise à jour de l'écran en temps réel… .. Vous pouvez essayer ceci. Ce code est testé et fonctionne avec succès, il vous donne également une bonne sortie en fps. Vous pouvez également en juger par chaque temps de boucle nécessaire.

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
2
Istiyak

Vous pouvez essayer ceci =>

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)
2
Sandzz

sur la base de ce post et d’autres posts, j’ai réalisé quelque chose comme ceci… .. Il prend une capture d’écran et écrit dans un fichier vidéo sans enregistrer l’image.

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(image), cv2.COLOR_RGB2BGR)
  out.write(img)
  StopIteration(0.5)
 except KeyboardInterrupt:
  break

out.release()
cv2.destroyAllWindows()
1
szanyi krisztián

Avec toutes les solutions ci-dessus, je ne pouvais pas obtenir une fréquence d'images utilisable avant d'avoir modifié mon code de la manière suivante:

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

Avec cette solution, j'obtiens facilement plus de 20 images/seconde.

Pour référence, vérifiez ce lien: https://python-mss.readthedocs.io/examples.html

0
Markoe7

J'ai essayé ImageGrab à partir de PIL et il m'a donné 20 images par seconde, ce qui est correct, mais l'utilisation des bibliothèques win32 m'a permis d'obtenir + 40 images par seconde, ce qui est incroyable!

J'ai utilisé this code de Frannecklp mais cela ne fonctionnait pas très bien, donc je devais le modifier:

-Premier pip install pywin32 en cas d'utilisation des bibliothèques

-importez les bibliothèques comme ceci à la place:

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

pour obtenir un simple écran d'image, faites:

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

et pour obtenir des cadres:

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
0
Reza Hosseini