Как сделать запись экран на Python

Свет, камера, мотор! Добро пожаловать в урок Simple Screen Recording, где мы превратим экран вашего компьютера в блокбастер! Возьмите попкорн и приготовьтесь отправиться в эпическое путешествие, чтобы запечатлеть и поделиться своими цифровыми приключениями.

Для тех, кто не знает, запись экрана – это захват последовательности изображений с экрана компьютера и их компиляция в видеоролик, который можно воспроизвести.

Как мы будем это делать?
Очень просто. Мы будем использовать mss – библиотеку, специально предназначенную для создания скриншотов экрана. Хотя существуют и другие библиотеки, mss отличается своей эффективностью и скоростью работы.

pip install mss

Создать графический интерфейс для этого будет сложно, поэтому мы будем использовать горячие клавиши. И снова есть еще один замечательный модуль под названием pynput.

pip install pynput

Наконец, нам также понадобится OpenCV для записи наших кадров в файл с видеоформатом.

Я объясню, как использовать необходимые библиотеки, не останавливаясь подробно на функциях, которые не будут использоваться.

Как использовать MSS?
Прежде всего, нам необходимо определить область, которую мы хотим захватить. Мы можем легко определить необходимый словарь, как показано ниже. Это позволит захватить весь экран.

{
  "left": 0,
  "top": 0,
  "width": 1366,
  "height": 768
}

Однако библиотека mss упрощает этот процесс, предоставляя встроенные настройки области для каждого монитора. Это означает, что мы можем легко захватить весь экран, не указывая вручную размеры каждого монитора.

import mss

monitor_index = 0 # Change to what ever monitor you would like to record.

sct = mss.mss()
region = sct.monitors[monitor_index]
print(sct.monitors[monitor_index])

"""
Output:
{
  "left": 0,
  "top": 0,
  "width": 1366,
  "height": 768
}
"""

При желании можно изменить область переменных. Чтобы сделать снимок экрана, просто выполните команду:

sct_img = sct.grab(region)

В результате получается изображение Pillow. Нам необходимо преобразовать его в кадр OpenCV. Мы сделаем это, вызвав команду:

from PIL import Image
import cv2

import numpy as np

def convert(frame):
    frame = Image.frombytes("RGB", frame.size, frame.bgra, "raw", "BGRX")
             
    frame = np.array(frame)
    return cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

Как использовать pynput?
Наша задача заключается в определении двух функций и назначении глобальной горячей клавиши для каждой из них. Если назначить каждой функции определенную комбинацию клавиш, то при нажатии соответствующей горячей клавиши будет вызываться и выполняться соответствующая функция. Для этого мы можем использовать словари для сопоставления функций соответствующим строкам. Ниже приведен пример нашего кода.

from pynput import keyboard

#Start/Stop recording
def on_toggle():
    print('Print Key Press')

#End program
def on_end():
    print('Ending...')

key_func_map = {
    '<ctrl>+s': on_toggle,
    '<ctrl>+<alt>+e': on_end
}
with keyboard.GlobalHotKeys(key_func_map) as h:
    h.join()

Обратите внимание, что h.join() выполняется в главном потоке, поэтому скрипт не будет продвигаться вперед, пока не будет остановлен. Мы будем использовать h.start(). Это запустит поток слушателя.

Как записать видео?
По мере захвата кадров мы можем либо сохранять их и записывать позже, либо сразу записывать. Оба варианта имеют свои преимущества и недостатки. В данной статье мы будем записывать их сразу.

import cv2

resolution = # (width, height).
fps        = # The fps of the outputed file.
filename   = # The name of the output file.
cv_format  = # The codec of the video.
frames     = # The captured frames.

codec = cv2.VideoWriter_fourcc(*cv_format)
out = cv2.VideoWriter(filename, codec, fps, resolution)

for frame in frames:
    out.write(frame)

out.release()
cv2.destroyAllWindows()

Мы будем выводить наш файл в формате mp4. Для этого мы определим:

cv_format  = "MP4V"
filename   = "output.mp4"
resolution = (region["width"], region["height"])

У нас есть проблема. VideoWriter должен знать среднее количество кадров в секунду. Если это значение будет больше или меньше, то видео будет выглядеть ускоренным или замедленным. Стратегия заключается в том, чтобы задать целевое значение fps и при захвате задерживать программу на вычисленную величину, чтобы уложиться в это значение.

Давайте объединим все это.

Пример

pip install mss, pynput, pillow
# Imports required to run the program
import mss
import numpy as np

from pynput import keyboard

from PIL import Image
import cv2

import time

recording = False  # Flag that defines if we are adding frames to the video
running   = True  # Keeps the program from ending and loops in the frame.

sct           = mss.mss()
monitor_index = 0  # Change to whatever monitor you would like to record.
region        = sct.monitors[monitor_index]

# Capture parameters
cv_format  = "MP4V"
filename   = "output.mp4"
resolution = (region["width"], region["height"])
fps        = 48

"""
The FPS will suffer due:
1. Converting the frames
2. We are writing immediately after receiving the frame

We need to accommodate for this issues
"""

def convert(frame):
    # Convert frame to PIL Image format
    frame = Image.frombytes("RGB", frame.size, frame.bgra, "raw", "BGRX")

    # Convert PIL Image to numpy array
    frame = np.array(frame)

    # Convert RGB to BGR (OpenCV uses BGR format)
    return cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

# Start/Stop recording
def on_toggle():
    global recording
    recording = not recording

    print("Recording" if recording else "Recording stopped")

# End program
def on_end():
    global recording, running

    print('Ending...')
    recording = False
    running = False

key_func_map = {
    '<ctrl>+s': on_toggle,
    '<ctrl>+<alt>+e': on_end
}
listener = keyboard.GlobalHotKeys(key_func_map)
listener.start()

codec = cv2.VideoWriter_fourcc(*cv_format)
out = cv2.VideoWriter(filename, codec, fps, resolution)

print("Running...")

while running:
    if recording:
        init_time = time.time()

        # Capture screen region
        sct_img = sct.grab(region)

        # Convert and write frame to video file
        out.write(convert(sct_img))

        elapsed_time = time.time() - init_time
        delay = 1 / fps - elapsed_time

        if delay > 0:
            time.sleep(delay)

out.release()
cv2.destroyAllWindows()

listener.stop()
print(f"Saved as {filename}")

Для бенчмарка:

pip install mss autopy pyautogui pyscreenshot
sudo apt-get install scrot # If you are on linux
import time
import mss
import autopy
import pyautogui
import pyscreenshot

def benchmark_library(library_name, capture_func, num_iterations):
    fps_list = []
    for _ in range(num_iterations):
        start_time = time.time()
        frame_count = 0
        while time.time() - start_time < 1:  # Measure FPS for 1 second
            capture_func()
            frame_count += 1
        end_time = time.time()
        elapsed_time = end_time - start_time
        fps = frame_count / elapsed_time
        fps_list.append(fps)
    mean_fps = sum(fps_list) / num_iterations
    print(f"{library_name} - Mean FPS: {mean_fps:.2f}")

def capture_with_mss():
    with mss.mss() as sct:
        monitor = sct.monitors[0]
        sct.grab(monitor)

def capture_with_autopy():
    autopy.bitmap.capture_screen()

def capture_with_pyautogui():
    pyautogui.screenshot()

def capture_with_pyscreenshot():
    pyscreenshot.grab()

# Set the number of iterations
num_iterations = 10

# Benchmark each library
benchmark_library("python-mss", capture_with_mss, num_iterations)
benchmark_library("autopy", capture_with_autopy, num_iterations)
benchmark_library("pyautogui", capture_with_pyautogui, num_iterations)
benchmark_library("pyscreenshot", capture_with_pyscreenshot, num_iterations)
+1
0
+1
0
+1
0
+1
0
+1
0

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *