SoFunction
Updated on 2024-12-12

Making a screen recording tool based on Python+OpenCV

Recently have been using screen recording software to record the desktop, in the process of using a whim, using python can do screen recording tools, but also exercise their hands. Next ready to write a series of articles using python how to do screen recording tool:

Record Screen Production Video

Record Audio

Composite video, audio

Making visualization windows based on pyqt5

Roughly the above four parts, hopefully I will be able to perfect it soon, next start using python to create the screen recording part.

application platform (computing)

  • windows 10
  • python 3.7

Screen recording section

Screen recording can be simply understood as a snapshot of the screen to play in the form of moving pictures, here I choose to use PIL under the ImageGrab to intercept the screen, first of all, the

pip install Pillow

After that you need to combine the number of intercepted snapshots into a video, using the cv2 module

pip install opencv-python

ImageGrab class can not be stored directly as a video, using numpy module for arraying, and then converted to cv2 color channel by cv2.COLOR_BGR2RGB.

pip install numpy

Screen recording main code:

import numpy as np
from PIL import ImageGrab
import cv2

im = ()
width, high =   # Get the width and height of the screen
fourcc = cv2.VideoWriter_fourcc(*'I420')  # Set the video encoding format
fps = 15  # Setting the frame rate
video = ('', fourcc, fps, (width, high))
while True:  # Start recording
    im = ()
    im_cv = ((im), cv2.COLOR_BGR2RGB)
    # Image Write
    (im_cv)
    if xx:  # Interrupt the loop when a certain condition is met
        break
()  # Releasing the cache,Persistent Video

A test run can save a screen snapshot as a video, but the operation is not elegant or conducive to subsequent operations.

Encapsulated into a class that inherits from the thread parent to facilitate the use of the keyboard to control the end of the video recording.

from threading import Thread

class ScreenshotVideo(Thread):

    def __init__(self):
     """Initialization parameters"""
        super().__init__()

Detailed code will be given at the end of the article.

Calculating the optimal fps for a video and using numpy to calculate the intermediate frame array

In practice, video recording will have different frame rates in different computers, resulting in either fast or slow video playback, and you need to calculate the corresponding optimal fps values according to different computers.

def video_best_fps(self, path):
    """Getting the optimal frame rate for a computer-recorded video."""
    video = (path)  # Read the video
    fps = (cv2.CAP_PROP_FPS)  # Get the frame rate of the current video
    count = (cv2.CAP_PROP_FRAME_COUNT)  # Get the number of frames in the video, i.e. how many frames are in the video
    self.best_fps = int(fps * ((int(count) / fps) / self.spend_time))   # Calculate playback time vs. recording time to get the optimal frame rate
    ()

Then adjust the frame rate parameter to record the video will weaken the video playback too fast or too slow. You can also add frames to the video to extend the playback time, here I use a very simple method to increase the video frame, just for reference.

from numba import jit

# Use numpy to compute two images that are two frames adjacent and closer to the later frame
# Call the jit method to speed up array calculations
@jit(nopython=True)
def average_n(x, y):
    """Numpy computes convergence values."""
    return ((x + y + y) // 3).astype()

This method is only for the set fps is higher than the optimal fps, after the processing of the video view, the video is still more rapid, but the details of the frame increased, so the playback time will be longer than before processing, slightly residual shadow.

Listening to keyboard keys with pynput

In video recording, it is not known when the video ends, so the recording code is wrapped in a while loop, but it is not possible to let the code run endlessly, and here we use the Listen to Keyboard module to interrupt the running of the recording code.

from pynput import keyboard  # pip install pynput

def hotkey(self):
    """Hot Key Listening"""
    with (on_press=self.on_press) as listener:
        ()

def on_press(self, key):
    try:
        if  == 't':  # End of screen recording, save video
             = True
        elif  == 'k':  # Recording screen aborts, deletes files
             = True
             = True
    except Exception as e:
        print(e)

Press "T" key to end the recording and save the video. The "K" key stops recording and deletes the cache file.

How to save MP4 format video

The video encoding format should be ('a', 'v', 'c', '1') with a file extension of '.mp4', before recording go to the/cisco/openh264/releasesDownload the dll.bz2 file for the corresponding platform under and unzip the zip package in the project folder. Run the code again and a line of coding instructions will appear for success:

OpenH264 Video Codec provided by Cisco Systems, Inc.

source code (computing)

The source code implemented in this article is as follows:

import time
from PIL import ImageGrab
import cv2
from pathlib import Path
import numpy as np
from numba import jit
from pynput import keyboard
from threading import Thread


@jit(nopython=True)
def average_n(x, y):
    """Numpy computes convergence values."""
    return ((x + y + y) // 3).astype()


class ScreenshotVideo(Thread):

    def __init__(self, width, high, path='', fps=15):
        """Initialization parameters"""
        super().__init__()
        self.save_file = path
        self.best_fps = fps
         = fps
         = width
         = high
        self.spend_time = 1
         = False
         = False
         = None

    def __call__(self, path):
        """Overloading video paths for easy secondary calls to classes"""
        self.save_file = Path(path)
         = self.init_videowriter(self.save_file)

    @staticmethod
    def screenshot():
        """Static method, screenshot, and convert to array"""
        return (())

    @staticmethod
    def get_fourcc(name):
        """Video Coding Dictionary"""
        fourcc_maps = {'.avi': 'I420',
                       '.m4v': 'mp4v',
                       '.mp4': 'avc1',
                       '.ogv': 'THEO',
                       '.flv': 'FLV1',
                       }
        return fourcc_maps.get(name)

    def init_videowriter(self, path):
        """Get video encoding and create new video file"""
        if not path:
            raise Exception('Video path not set,Please set\nvideo = ScreenshotVideo(fps,width,high)\nvideo = video(video_path)')
        path = Path(path) if isinstance(path, str) else path
        fourcc = cv2.VideoWriter_fourcc(*self.get_fourcc())
        return (path.as_posix(), fourcc, , (, ))

    def video_record_doing(self, img):
        """Converting BGR arrays to RGB arrays"""
        im_cv = (img, cv2.COLOR_BGR2RGB)
        (im_cv)

    def video_record_end(self):
        """End of recording, determine if the file is saved based on the conditions"""
        ()
        ()
        if self.save_file and :
            Path(self.save_file).unlink()

    def video_best_fps(self, path):
        """Getting the optimal frame rate for a computer-recorded video."""
        video = (path)
        fps = (cv2.CAP_PROP_FPS)
        count = (cv2.CAP_PROP_FRAME_COUNT)
        self.best_fps = int(fps * ((int(count) / fps) / self.spend_time))
        ()

    def pre_video_record(self):
        """Pre-recording for optimal fps."""
         = self.init_videowriter('test.mp4')
        start_time = ()
        for _ in range(10):
            im = ()
            self.video_record_doing(im)
        self.spend_time = round(() - start_time, 4)
        self.video_record_end()
        (2)
        self.video_best_fps('test.mp4')
        Path('test.mp4').unlink()

    def insert_frame_array(self, frame_list):
        """Numpy Enhanced Screenshot Information."""
        fps_n = round( / self.best_fps)
        if fps_n <= 0:
            return frame_list
        times = int(np.log2(fps_n))  # Multiplier
        for _ in range(times):
            frame_list2 = map(average_n, [frame_list[0]] + frame_list[:-1], frame_list)
            frame_list = [[x, y] for x, y in zip(frame_list2, frame_list)]
            frame_list = [j for i in frame_list for j in i]
        return frame_list

    def frame2video_run(self):
        """Converting continuous type screenshots to video using opencv"""
         = self.init_videowriter(self.save_file)
        start_time = ()
        frame_list = []
        while True:
            frame_list.append(())
            if :
                break
        self.spend_time = round(() - start_time, 4)
        if not :  # Video recording is not terminated will process the image frame by frame
            frame_list = self.insert_frame_array(frame_list)
            for im in frame_list:
                self.video_record_doing(im)
        self.video_record_end()

    def hotkey(self):
        """Hot Key Listening"""
        with (on_press=self.on_press) as listener:
            ()

    def on_press(self, key):
        try:
            if  == 't':  # End of screen recording, save video
                 = True
            elif  == 'k':  # Recording screen aborts, deletes files
                 = True
                 = True
        except Exception as e:
            print(e)

    def run(self):
        # Run the function
        # Set up daemon threads
        Thread(target=, daemon=True).start()
        # Run the screenshot function
        self.frame2video_run()


screen = ()
width, high = 
video = ScreenshotVideo(width, high, fps=60)
video.pre_video_record()  # Pre-record for optimal fps
video('test1.mp4')
()

summarize

In this paper, the current use of opencv and related modules to record the screen and convert it to video to save, learn to encapsulate multiple functions into classes to facilitate the subsequent development of the function. The road to learning is endless, bold steps to go!

The above is based on Python + OpenCV to create screen recording tools in detail, more information about Python OpenCV screen recording please pay attention to my other related articles!