スクリーンキャプチャ動画収録機能を実装する

· 563 words · 2 minute read

タイトルの通り、スクリーンキャプチャ動画収録機能を実装します。今回はスタートとストップを任意のタイミングで実行したかったのでthreading.Event()を用いています。単純にwhileでループさせればもっと簡易的にスクリーンキャプチャを撮ることができると思います。


仕組み 🔗

仕組みはシンプルです。pyautoguiでスクリーンショットを連続で撮り、その画像をcv2でくっつける、というものです。 スクリーンショットはcv2でもできるので、わざわざpyautoguiを使わなくても良いかもしれません。

コード 🔗

screen_capture.py

import numpy as np
import cv2
import pyautogui
import os
import time
import threading
import shutil


# ループ処理用デコレータ
def setInterval(interval):
    def decorator(function):
        def wrapper(*args, **kwargs):
            stopped = threading.Event()

            def loop():  # executed in another thread
                while not stopped.wait(interval):  # until stopped
                    function(*args, **kwargs)

            t = threading.Thread(target=loop)
            t.daemon = True  # stop if the program exits
            t.start()
            return stopped

        return wrapper

    return decorator


class ScreenCapture:
    NAME = 'screen_capture'
    IMAGE_EXTENSION = 'jpg'
    VIDEO_EXTENSION = 'mp4'

    def __init__(
        self,
        path: str = '.',
        fps: int = 10,
    ):
        self.img_cv_list = []
        self.path = path
        self.fps = fps
        self.dir_name = '{}_{}'.format(self.NAME, time.strftime('%Y%m%d%H%M%S'))
        self.dir_path = '{}/{}'.format(self.path, self.dir_name)
        self.__stop_flag = None

    def start(self):
        self.__print_log('started')
        os.makedirs(self.dir_path, exist_ok=True)
        self.__stop_flag = self.__screenshot()  # @setInterval の戻り値を self で状態管理

    def stop(self):
        self.__stop_flag.set()  # set() で @setInterval が止まる
        self.__print_log('stopped')

    def save(self):
        img_height, img_width, _ = np.asarray(pyautogui.screenshot()).shape

        video_filename = '{}/{}_{:010d}.{}'.format(self.dir_path, self.dir_name, 1, self.VIDEO_EXTENSION)
        fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
        video = cv2.VideoWriter(video_filename, fourcc, self.fps, (img_width, img_height))

        for i, img_cv in enumerate(self.img_cv_list):
            img_filename = '{}/{}_{:010d}.{}'.format(self.dir_path, self.dir_name, i+1, self.IMAGE_EXTENSION)
            cv2.imwrite(img_filename, img_cv)
            video.write(img_cv)

        video.release()
        self.__print_log('saved')

    def clear(self):
        shutil.rmtree(self.path)
        self.__print_log('cleared')

    def __print_log(self, message):
        print('{} {}.'.format(self.NAME, message))

    @setInterval(0.1)
    def __screenshot(self):
        img = pyautogui.screenshot()
        img_array = np.asarray(img)
        img_cv = cv2.cvtColor(img_array, cv2.COLOR_BGR2RGB)
        self.img_cv_list.append(img_cv)

使い方 🔗

main.py

from screen_capture import ScreenCapture

screen_capture = ScreenCapture()

# キャプチャのスタート
screen_capture.start()

# キャプチャのストップ
screen_capture.stop()

# キャプチャ動画の保存
screen_capture.save()

# キャプチャをクリア
screen_capture.clear()

以上ありがとうございました。