基于Python+OpenCV制作屏幕录制工具

目录
  • 应用平台
  • 屏幕录制部分
  • 计算视频最优fps及使用numpy计算中间帧数组
  • 使用pynput监听键盘按键
  • 如何保存MP4格式视频
  • 源码
  • 总结

最近有在使用屏幕录制软件录制桌面,在用的过程中突发奇想,使用python能不能做屏幕录制工具,也锻炼下自己的动手能力。接下准备写使用python如何做屏幕录制工具的系列文章:

录制屏幕制作视频

录制音频

合成视频,音频

基于pyqt5制作可视化窗口

大概上述四个部分,希望自己能够尽快完善,接下来开始使用python制作屏幕录制部分。

应用平台

  • windows 10
  • python 3.7

屏幕录制部分

屏幕录制可以简单地理解为将屏幕快照以动图的形式播放,这里我选用PIL下的ImageGrab来截取屏幕画面,首先

pip install Pillow

之后需要将截取到的快照数组合成为视频,使用cv2模块

pip install opencv-python

ImageGrab类不能直接存储为视频,使用numpy模块进行数组化,再通过cv2.COLOR_BGR2RGB转换为cv2色彩通道。

pip install numpy

屏幕录制主要代码:

import numpy as np
from PIL import ImageGrab
import cv2

im = ImageGrab.grab()
width, high = im.size  # 获取屏幕的宽和高
fourcc = cv2.VideoWriter_fourcc(*'I420')  # 设置视频编码格式
fps = 15  # 设置帧率
video = cv2.VideoWriter('test.avi', fourcc, fps, (width, high))
while True:  # 开始录制
    im = ImageGrab.grab()
    im_cv = cv2.cvtColor(np.array(im), cv2.COLOR_BGR2RGB)
    # 图像写入
    video.write(im_cv)
    if xx:  # 当某某条件满足中断循环
        break
video.release()  # 释放缓存,持久化视频

测试运行可以保存屏幕快照为视频,但操作起来不优雅,也不利于后续的操作。

封装成类,继承线程父类,方便使用键盘来控制视频录制的结束。

from threading import Thread

class ScreenshotVideo(Thread):

    def __init__(self):
     """初始化参数"""
        super().__init__()

详细代码将在文末给出。

计算视频最优fps及使用numpy计算中间帧数组

实际操作中视频录制在不同电脑中会出现不一样的帧率,导致视频播放或快或慢,需要根据不同的电脑计算出相应的最优fps值。

def video_best_fps(self, path):
    """获取电脑录制视频的最优帧率"""
    video = cv2.VideoCapture(path)  # 读取视频
    fps = video.get(cv2.CAP_PROP_FPS)  # 获取当前视频的帧率
    count = video.get(cv2.CAP_PROP_FRAME_COUNT)  # 获取视频帧数,即该视频有多少幅画面
    self.best_fps = int(fps * ((int(count) / fps) / self.spend_time))   # 计算播放时间与录制时间对比得到最优帧率
    video.release()

再调整帧率参数进行录制视频就减弱了视频播放太快或者太慢。也可以给视频增加帧数从而延长播放时间,这里我采用一种很简单的方法增加视频帧,仅供参考。

from numba import jit

# 使用numpy计算相邻两帧图像且更接近于后一帧的图像
# 调用jit方法加速数组计算
@jit(nopython=True)
def average_n(x, y):
    """Numpy计算趋近值"""
    return ((x + y + y) // 3).astype(x.dtype)

该方法仅针对于设置的fps比最优fps要高时,处理后的视频观感,视频还是较为急促,但是细节帧增多,所以播放时长会比未处理前的要长,略有残影。

使用pynput监听键盘按键

在视频录制中,并不知道视频何时结束,所以用while循环包裹录制代码,但也不可能让代码无休止的运行下去,在此使用监听键盘模块来中断录制代码的运行。

from pynput import keyboard  # pip install pynput

def hotkey(self):
    """热键监听"""
    with keyboard.Listener(on_press=self.on_press) as listener:
        listener.join()

def on_press(self, key):
    try:
        if key.char == 't':  # 录屏结束,保存视频
            self.flag = True
        elif key.char == 'k':  # 录屏中止,删除文件
            self.flag = True
            self.kill = True
    except Exception as e:
        print(e)

按下键盘“T”键时,结束录制,保存视频。“K”键则是停止录制,删除缓存文件。

如何保存MP4格式视频

视频编码格式应该为('a', 'v', 'c', '1'),文件后缀为'.mp4',在录制前先去https://github.com/cisco/openh264/releases下下载对应平台的dll.bz2文件,将压缩包解压放在项目文件夹下。再运行代码,成功会出现一行编码说明:

OpenH264 Video Codec provided by Cisco Systems, Inc.

源码

本文实现的源码如下:

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计算趋近值"""
    return ((x + y + y) // 3).astype(x.dtype)

class ScreenshotVideo(Thread):

    def __init__(self, width, high, path='', fps=15):
        """初始化参数"""
        super().__init__()
        self.save_file = path
        self.best_fps = fps
        self.fps = fps
        self.width = width
        self.high = high
        self.spend_time = 1
        self.flag = False
        self.kill = False
        self.video = None

    def __call__(self, path):
        """重载视频路径,便于类的二次调用"""
        self.save_file = Path(path)
        self.video = self.init_videowriter(self.save_file)

    @staticmethod
    def screenshot():
        """静态方法,屏幕截图,并转换为np.array数组"""
        return np.array(ImageGrab.grab())

    @staticmethod
    def get_fourcc(name):
        """视频编码字典"""
        fourcc_maps = {'.avi': 'I420',
                       '.m4v': 'mp4v',
                       '.mp4': 'avc1',
                       '.ogv': 'THEO',
                       '.flv': 'FLV1',
                       }
        return fourcc_maps.get(name)

    def init_videowriter(self, path):
        """获取视频编码并新建视频文件"""
        if not path:
            raise Exception('视频路径未设置,请设置\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(path.suffix))
        return cv2.VideoWriter(path.as_posix(), fourcc, self.fps, (self.width, self.high))

    def video_record_doing(self, img):
        """将BGR数组转换为RGB数组"""
        im_cv = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        self.video.write(im_cv)

    def video_record_end(self):
        """录制结束,根据条件判断文件是否保存"""
        self.video.release()
        cv2.destroyAllWindows()
        if self.save_file and self.kill:
            Path(self.save_file).unlink()

    def video_best_fps(self, path):
        """获取电脑录制视频的最优帧率"""
        video = cv2.VideoCapture(path)
        fps = video.get(cv2.CAP_PROP_FPS)
        count = video.get(cv2.CAP_PROP_FRAME_COUNT)
        self.best_fps = int(fps * ((int(count) / fps) / self.spend_time))
        video.release()

    def pre_video_record(self):
        """预录制,以获取最佳fps值"""
        self.video = self.init_videowriter('test.mp4')
        start_time = time.time()
        for _ in range(10):
            im = self.screenshot()
            self.video_record_doing(im)
        self.spend_time = round(time.time() - start_time, 4)
        self.video_record_end()
        time.sleep(2)
        self.video_best_fps('test.mp4')
        Path('test.mp4').unlink()

    def insert_frame_array(self, frame_list):
        """Numpy增强截图信息"""
        fps_n = round(self.fps / self.best_fps)
        if fps_n <= 0:
            return frame_list
        times = int(np.log2(fps_n))  # 倍率
        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):
        """使用opencv将连续型截图转换为视频"""
        self.video = self.init_videowriter(self.save_file)
        start_time = time.time()
        frame_list = []
        while True:
            frame_list.append(self.screenshot())
            if self.flag:
                break
        self.spend_time = round(time.time() - start_time, 4)
        if not self.kill:  # 视频录制不被终止将逐帧处理图像
            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):
        """热键监听"""
        with keyboard.Listener(on_press=self.on_press) as listener:
            listener.join()

    def on_press(self, key):
        try:
            if key.char == 't':  # 录屏结束,保存视频
                self.flag = True
            elif key.char == 'k':  # 录屏中止,删除文件
                self.flag = True
                self.kill = True
        except Exception as e:
            print(e)

    def run(self):
        # 运行函数
        # 设置守护线程
        Thread(target=self.hotkey, daemon=True).start()
        # 运行截图函数
        self.frame2video_run()

screen = ImageGrab.grab()
width, high = screen.size
video = ScreenshotVideo(width, high, fps=60)
video.pre_video_record()  # 预录制获取最优fps
video('test1.mp4')
video.run()

总结

本文目前使用了opencv和相关模块对屏幕进行录制并转换为视频保存,学习将多个函数封装为类,方便后续功能开发。学习的道路是无止境的,大胆的迈步走吧!

以上就是基于Python+OpenCV制作屏幕录制工具的详细内容,更多关于Python OpenCV屏幕录制的资料请关注我们其它相关文章!

(0)

相关推荐

  • python利用ffmpeg进行录制屏幕的方法

    前几天下载了几个视频,但是有两集是一个视频的,偶尔找到了ffmpeg处理视频的方法,它的功能非常强大.因此,分享一下,一起学习. import subprocess,sys,os import re class CutSplicingVdeio(object): def __init__(self): pass #dercription CutSplicingVdeio this class function def instructions(self): dercription="vdeio

  • Python+opencv+pyaudio实现带声音屏幕录制

    基于个人的爱好和现实的需求,决定用Python做一个屏幕录制的脚本.因为要看一些加密的视频,每次都要登录,特别麻烦,遂决定用自己写的脚本,将加密视频的播放过程全程录制下来,这样以后看自己的录播就好了.结合近期自己学习的内容,正好用Python来练练手,巩固自己的学习效果. 经过多番搜索,决定采用Python+opencv+pyaudio来实现屏幕录制.网上搜索到的录屏,基本都是不带声音的,而我要实现的是带声音的屏幕录制.下面就开始一步一步的实现吧. 声音录制 import pyaudio imp

  • python 实现屏幕录制示例

    PIL 即pollow 的安装命令如下: pip install pillow 其中cv2的安装是下面这条命令 pip install opencv-python 代码实现: # coding: utf-8 from PIL import ImageGrab import numpy as np import cv2 fps = 20 start = 3 # 延时录制 end = 15 # 自动结束时间 curScreen = ImageGrab.grab() # 获取屏幕对象 height,

  • Python实现屏幕录制功能的代码

    前段时间做视频时需要演示电脑端的操作,因此要用到屏幕录制,下载了个迅捷屏幕录制,但是没有vip录制的视频有水印且只能录制二分钟,于是鄙人想了下能不能通过万能的python来实现呢?经过一晚上的尝试发现这条路是可以走的通的.分享一下自己的想法,整体思路是PIL模块中的ImageGrab不停的获得当前屏幕,利用opencv写入视频流话不多说,直接上代码,有什么更好的建议,欢迎大家交流! """python + opencv 实现屏幕录制_by-_Zjh_""&

  • 使用Python来做一个屏幕录制工具的操作代码

    一.写在前面 作为一名测试,有时候经常会遇到需要录屏记录自己操作,方便后续开发同学定位.以前都是用ScreenToGif来录屏制作成动态图,偶尔的机会看到python也能实现.那就赶紧学习下. 二.效果展示 三.知识串讲 这次要讲的东西可能比较多了,涉及到pyqt5 GUI软件的制作.QThread多线程的使用.Sikuli库的图形操作.win32库的模拟键盘操作.cv2库的写视频文件等.下面我们一点点来蚕食我这次写的代码. 1.GUI界面制作 这次我用的是现成的Pyqt5界面布局类,QVBox

  • 只用20行Python代码实现屏幕录制功能

    一.模块安装 首先,我们需要用到两个python的两个模块,win32gui和PyQt5 1.pip install win32gui 2.pip install PyQt5 1.pip install win32gui PS C:\Users\lex\Desktop> pip install win32gui Looking in indexes: http://mirrors.aliyun.com/pypi/simple Requirement already satisfied: win3

  • 基于Python+OpenCV制作屏幕录制工具

    目录 应用平台 屏幕录制部分 计算视频最优fps及使用numpy计算中间帧数组 使用pynput监听键盘按键 如何保存MP4格式视频 源码 总结 最近有在使用屏幕录制软件录制桌面,在用的过程中突发奇想,使用python能不能做屏幕录制工具,也锻炼下自己的动手能力.接下准备写使用python如何做屏幕录制工具的系列文章: 录制屏幕制作视频 录制音频 合成视频,音频 基于pyqt5制作可视化窗口 大概上述四个部分,希望自己能够尽快完善,接下来开始使用python制作屏幕录制部分. 应用平台 wind

  • 使用Pyqt5制作屏幕录制界面功能

    目录 应用平台 窗口设置 主体窗口代码 划选窗口代码 总结 最近有在使用屏幕录制软件录制桌面,在用的过程中突发奇想,使用python能不能做屏幕录制工具,也锻炼下自己的动手能力.接下准备写使用python如何做屏幕录制工具的系列文章: 录制屏幕制作视频 录制音频 合成视频,音频 基于pyqt5制作可视化窗口 大概上述四个部分,希望自己能够尽快完善,前两篇文章分享了利用opencv制作了屏幕录制部分,利用PyAudio录制音频,本篇文章分享如何使用ffmpeg将同时录制的屏幕录像和音频合成为有声音

  • Python做屏幕录制工具的实现示例

    目录 思路 实现 录制 监听键盘事件 主体控制 视频信息 女朋友是一个软件测试人员,在工作中经常会遇到需要录屏记录自己操作,方便后续开发同学定位.因为录屏软件动不动就开始收费,所以她经常更换录屏软件.闲暇之余,我就觉得手痒,感觉可以用万能的 Python 来解决她的烦恼. 思路 我上网搜寻了一下相关知识,录制视频基本上都用的图像处理库 PIL 的 ImageGrab 模块.这个模块可以用于将当前屏幕的内容或者剪贴板上的内容拷贝到 PIL 图像内存.既然这个模块可以获取当前屏幕上的内容,那么我一直

  • Python+OpenCv制作证件图片生成器的操作方法

    本项目使用Python和OpenCv实现身份证图片生成工具,填入信息,选择一张头像图片(即可生成黑白和彩色身份证图片).可以选择是否自动抠图,自动抠图目前仅支持蓝色背景,对自动抠图效果不满意可以手动抠图. 在线抠图地址: https://burner.bonanza.com/ https://www.gaoding.com/koutu 参照标准: 正面 "姓名"."性别"."民族"."出生年月日"."住址"

  • 基于Python实现千图成像工具的示例代码

    目录 前置 GUI制作 GUI界面设计 逻辑设计 图片处理 修改底图大小 修改组图大小 计算图片填充次数 组图合成 图片合成 GUI打包 千图成像也就是用N张图片组成一张图片的效果.制作方法有很多的,最常见的如用ps.懒人图云.foto-mosaik-edda这些制作. 千图成像的效果我大致分为两类:一为直接用N张图片根据底图的像素颜色.大小,一张张的组成底图,如foto-mosaik-edda:二为用N张图片根据底图的像素大小,组成一张与底图大小相仿的图片,再把二者合成,经调整透明度而成的图片

  • 基于Python实现视频去重小工具

    同级目录下新建dup_video import json import os import shutil import cv2 import imagehash from PIL import Image from loguru import logger from PySimpleGUI import popup_get_folder class VideoDuplicate(object): ''' 返回整个视频的图片指纹列表 从1秒开始,每3秒抽帧,计算一张图像指纹 ''' def __i

  • 基于Python OpenCV和 dlib实现眨眼检测

    目录 了解"眼睛纵横比"(EAR) 使用面部标志和 OpenCV 检测眨眼 眨眼检测结果 总结 今天,我们使用面部标记和 OpenCV 检测视频流中的眨眼次数. 为了构建我们的眨眼检测器,我们将计算一个称为眼睛纵横比 (EAR) 的指标,该指标由 Soukupová 和 Čech 在他们 2016 年的论文<使用面部标记的实时眨眼检测>中介绍. 与计算眨眼的传统图像处理方法不同,传统的图像处理方法通常涉及以下某些组合: 眼睛定位. 阈值以找到眼白. 确定眼睛的"白

  • 基于python opencv单目相机标定的示例代码

    相机固定不动,通过标定版改动不同方位的位姿进行抓拍 import cv2 camera=cv2.VideoCapture(1) i = 0 while 1: (grabbed, img) = camera.read() cv2.imshow('img',img) if cv2.waitKey(1) & 0xFF == ord('j'): # 按j保存一张图片 i += 1 u = str(i) firename=str('./img'+u+'.jpg') cv2.imwrite(firename

随机推荐