Как сделать запись экран на 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)