作为一个测试,在跑游戏的时候偶然间遇到一些 BUG,都需要提交表单并附上重现操作,但有时候,我们也不记得之前进行了什么操作,所以在跑功能的时候,开启录屏就是一个好习惯了,遇到问题,可以通过回看视频,重复之前的操作步骤来尝试定位问题。常用的录屏软件也就那几个,游戏录屏的话可以使用 windows 自带的录屏软件(win+G),其他的市面上也有不少好用的录屏软件,但是这些录屏软件基本都不支持分段循环录制,每个视频录制下来都很大,不利于保存和传播,小伙伴们都想要一个能够像行车记录仪一样的视频录制软件,循环录制,单个视频时长 1 分钟,可以定义存储上限,不会无限保存视频,翻阅了网上的资料,决定自己试着写个。
  python 实现录屏主要用到了 PIL 和 cv2 库,然后还有 numpy 和 pygetwindow 等,首先声明这些库

import time
from datetime import datetime
from PIL import ImageGrab, ImageDraw
import numpy as np
import cv2
import pygetwindow as gw
import pyautogui as pag

  接下来是实现录像功能的方法:

def recode(window_title):
    """
    录制指定窗口的视频
    :param window_title: 窗口名称
    :return: 
    """
    # 1.首先根据窗口名称获取到对应的窗口
    window = gw.getWindowsWithTitle(window_title)[0]
    # 2.激活并将对应的窗口显示到最顶层
    window.restore()
    window.activate()
    # 3.根据当前时间生成录像文件的名字
    file_name = datetime.now().strftime('%Y-%m-%d %H-%M-%S')
    # 4.获取窗口的位置和大小
    left, top, width, height = window.left, window.top, window.width, window.height
    # 5.设置VideoWriter_fourcc录制类型
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    # 6.设置文件名,大小,帧率等, VIDEO_FILE_PATH是我设置的一个全局参数,是录像的保存目录,如VIDEO_FILE_PATH = 'E:\\record_files'
    #   FPS我也参数化了,FPS=15,这个帧率可能会影响录像的播放速度,可以根据自己的情况自行调整
    video = cv2.VideoWriter(f'{VIDEO_FILE_PATH}\\{file_name}.avi', fourcc, FPS, (width, height))
    # 7.记录开始录制视频的时间
    start_time = time.time()
    # 8.当录制时间不足1分钟时,循环写入到录像文件中
    while time.time() - start_time < 60:
        # 这里我每次写入都重新获取了窗口的顶点位置和大小,这样的用处是在你拖动对应的窗口后,录像的区域会跟随你的拖动重新选定,不会傻傻的还在录原来的位置
        left, top, width, height = window.left, window.top, window.width, window.height
        # 根据窗口区域截取对应的图像
        capture_image = ImageGrab.grab((left, top, left+width, top+height))
        # 生成图像帧
        frame = cv2.cvtColor(np.array(capture_image), cv2.COLOR_RGB2BGR)
        # 将图像帧写入到文件中
        video.write(frame)
    video.release()

  然后写一个简单的主函数,循环调用进行录制

def main():
    while True:
        recode('锚点降临')

  这样就可以将录制的视频文件循环保存到指定的文件夹中了。第一步成功!

  在使用过程中,我们发现录制的视频是没有包含鼠标的,也就是说我们只能看到视频,无法确定我们的鼠标怎么移动,点了哪里,然后又查阅资料,写了一个绘制鼠标轨迹的方法,这个方法是将窗口截图传入,根据当时鼠标的位置,在传入的截图中指定位置自己绘制一个鼠标(真正的鼠标图案有点复杂,我是以圆点代替的)

def record_mouse(img, mouse_x, mouse_y):
    """
    在图片上绘制鼠标位置
    :param img: 需要绘制的图片
    :param mouse_x: 鼠标在图片上的相对x坐标
    :param mouse_y: 鼠标在图片上的相对y坐标
    :return:
    """
    # 1.首先获取图片大小
    w, h = img.size
    # 2.加载图像
    draw = ImageDraw.Draw(img)
    # 判断鼠标位置,如果当时鼠标坐标在图片范围之内,则绘制鼠标
    if 0 < mouse_x < w and 0 < mouse_y < h:
        # 绘制一个圆点,以红色填充
        draw.ellipse((mouse_x-2, mouse_y-2, mouse_x+2, mouse_y+2), fill=250)
    # 返回添加了鼠标的截图图像
    return img

  然后修改一下原来的方法,在截图的时候绘制上鼠标位置

# # 根据窗口区域截取对应的图像
# capture_image = ImageGrab.grab((left, top, left + width, top + height))

# 将上面的方法修改为:

# 获取鼠标坐标,利用到了pyautogui库
mouse_x, mouse_y = pag.position()
# 将截图的图像传入record_mouse方法,获得绘制了鼠标位置之后的截图
capture_image = record_mouse(ImageGrab.grab((left, top, left+width, top+height)), mouse_x - left, mouse_y-top)

  这样,录制的视频就可以显示鼠标轨迹了。

  最后,就只剩定时删文件,以确保不会占用太多的硬盘空间。

def del_files():
    """
    判断文件数量是否超过设定值,如果超过,则删除一定数量的文件
    :return:
    """
    # 根据目录获取文件列表
    files = os.listdir(VIDEO_FILE_PATH)
    # 判断文件数量,如果超过了设定的最大值MAX_FILES_COUNT(自行定义),则删除最前面的几个文件
    if len(files) > MAX_FILES_COUNT:
        for i in files[:len(files)-MAX_FILES_COUNT]:
            os.remove(f'{VIDEO_FILE_PATH}\\{i}')

  然后再修改一下 main 函数:

def main():
    while True:
        del_files()
        recode('锚点降临')

  这样,一个模拟行车记录仪的视频录制软件就完成了,试了一下效果好像还可以?

  为了将其打包成一个工具,方便给组里的其他小伙伴使用,我用 PYQT5 给他添加了一个图形界面:

  点击开始录制按钮,倒计时 321 开始循环录制,按钮变成停止录制,可以点击停止录制按钮自行停止录制,当找不到对应名称的窗口时,也会 tips 提醒,以上就是这个录屏软件的全部功能,有兴趣的小伙伴欢迎探讨~


↙↙↙阅读原文可查看相关链接,并与作者交流