如何用Python进行屏幕录制?

news/2025/2/13 3:38:04/

文章目录

    • 引言
    • gpt3.5给出的代码
    • 更换截图函数——ImageGrab.grab
    • 禁用imshow解决递归现象
    • 摄像头录制代码
    • 后期需求

引言

关于屏幕录制这个功能需求,之前用过基于ffmpeg的Capture录屏软件,但是fps拉高以后会变得很卡,声音也同样出现卡顿。也自己尝试过在python中调用ffmpeg的库函数,效果也不尽人意。网络上下载了几款录屏软件,不是要收费就是下载到捆绑软件或广告很是心累,因此想借此机会重新研究一下屏幕录制软件的工作原理,同时当作一个小项目练手。

gpt3.5给出的代码

当我还在犹豫是否要精心翻阅一下ffmpeg的说明书时,没想到gpt已果断给出了参考答案,可以使用Python的PyAutoGUI库来实现录屏功能。以下是一个简单的示例代码:

import pyautogui
import cv2
import numpy as np# 获取屏幕分辨率
screen_size = (1920, 1080)# 设置视频编码器
fourcc = cv2.VideoWriter_fourcc(*"XVID")# 创建视频写入对象
out = cv2.VideoWriter("output.avi", fourcc, 20.0, screen_size)# 开始录屏
while True:# 获取屏幕截图img = pyautogui.screenshot()# 将截图转换为OpenCV格式frame = np.array(img)frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)# 写入视频out.write(frame)# 按下q键退出录屏if cv2.waitKey(1) == ord("q"):break# 释放资源
out.release()
cv2.destroyAllWindows()

从给出的代码看来,屏幕录制的工作原理就是以一定的帧率不断地截图,然后将截取的图片以相同的帧率合成一个视频
放在安装了pyautogui的python环境里运行后,果然不出意外的话就要出意外了。gpt3.5给出的代码卡在运行中的界面纹丝不动,按’q’回车也并未退出循环,再问gpt也死活给不出修改方案。

查阅资料后发现要先imshow()之后,在ui窗口区域内按键才能有效终止循环:

import numpy as np
import pyautogui
import cv2# 设置录制参数
SCREEN_SIZE = (1920, 1080)
FILENAME = 'recorded_video.avi'
FPS = 30.0# 开始录制
fourcc = cv2.VideoWriter_fourcc(*"XVID")
out = cv2.VideoWriter(FILENAME, fourcc, FPS, SCREEN_SIZE)while True:# 获取屏幕截图img = pyautogui.screenshot()# 转换为OpenCV格式frame = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)# 写入视频文件out.write(frame)cv2.imshow('Frame', frame)cv2.resizeWindow('Frame', 1920, 1080)# 检测按键if cv2.waitKey(1) == ord('q'):break# 停止录制
out.release()
cv2.destroyAllWindows()

程序是能运行了,但是效果依旧不好,窗口一直有递归的效果,而且导出的视频其实是无法播放的。
在这里插入图片描述

更换截图函数——ImageGrab.grab

pyautogui虽然能实现截图,并在imshow里展示出来,但是导出的视频却无法播放,考虑肯能涉及到具体视频编解码参数问题,有懂的朋友请在评论区分享。这里采用更换PIL库中的截图函数ImageGrab.grab,可以实现截图并导出视频了,接下来最大的问题就是解决递归现象。

import numpy as np
from PIL import ImageGrab
import cv2# 设置录制参数
SCREEN_SIZE = (1920, 1080)
FILENAME = 'recorded_video.avi'
FPS = 30.0# 开始录制
fourcc = cv2.VideoWriter_fourcc(*"XVID")
out = cv2.VideoWriter(FILENAME, fourcc, FPS, SCREEN_SIZE)while True:# 获取屏幕截图# img = pyautogui.screenshot()img = ImageGrab.grab(bbox=(0, 0, 1920, 1080))print('recordin..')# 转换为OpenCV格式frame = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)# 写入视频文件out.write(frame)cv2.imshow('Frame', frame)cv2.resizeWindow('Frame', 1920, 1080)# 检测按键if cv2.waitKey(1) == ord('q'):break# 停止录制
out.release()
cv2.destroyAllWindows()

在这里插入图片描述

禁用imshow解决递归现象

视频处理时的递归现象其实非常常见,除了物理中的镜面效应(观察两个平行放置的镜子会出现递归的现象),

将摄像头对准显示器,显示器上的画面也会观察到递归的现象:
在这里插入图片描述
经尝试,将imshow()禁用后,改为帧计数的方式自定义终止循环就不会出现递归的问题了:

import numpy as np
from PIL import ImageGrab
import cv2# 设置录制参数
SCREEN_SIZE = (1920, 1080)
FILENAME = 'recorded_video.avi'
FPS = 30.0# 开始录制
fourcc = cv2.VideoWriter_fourcc(*"XVID")
out = cv2.VideoWriter(FILENAME, fourcc, FPS, SCREEN_SIZE)cnt = 0
while True:# 获取屏幕截图# img = pyautogui.screenshot()img = ImageGrab.grab(bbox=(0, 0, 1920, 1080))print('recordin..')# 转换为OpenCV格式frame = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)# 写入视频文件out.write(frame)# cv2.imshow('Frame', frame)# cv2.resizeWindow('Frame', 1920, 1080)# # 检测按键# if cv2.waitKey(1) == ord('q'):#     breakcnt = cnt + 1if cnt == 100:  #满100帧后终止循环break# 停止录制
out.release()
cv2.destroyAllWindows()

在这里插入图片描述
通过修改img = ImageGrab.grab(bbox=(0, 0, 2560, 1600))中的参数可以自定义录屏区域,x,y,w,h分别代表左上角坐标(起始坐标)和图片宽度、高度。比如我的屏幕分辨率是2560*1600,那么设置为0, 0, 2560, 1600就是录制全屏:
在这里插入图片描述
这样,我们就可以基本实现用Python进行屏幕录制的功能了。动态图预览看上去分辨率不高是因为用的格式工厂把录制的视频转了gif,压缩前录制的视频其实蛮清楚的。

通过修改fps的值,我们还可以自行录制一些高刷新率的电影、游戏画面,fps越高,画面越流畅哦。

摄像头录制代码

类似的,也可以用python实现相机录像的功能:

import cv2
import cv2 as cv# 打开摄像头
cap = cv2.VideoCapture(0)fourcc = cv.VideoWriter_fourcc(*'XVID')
file_name = 'output'
output = cv.VideoWriter((file_name + '.avi'), fourcc, 24.0, (640, 480))  #设置文件名,fps,分辨率while cap.isOpened():res, frame = cap.read()if not res:print("Frame Cannot Be Received")break# Flipping the frame horizontally to get correct orientationframe = cv2.flip(frame, 90)# Displaying the current frameoutput.write(frame)cv2.imshow('Frame', frame)# If no input is received for 1ms, or if the key 'x' is pressed, interpreter goes outside of the loopif cv2.waitKey(1) == ord('x'):break# Releasing everything after coming out of loop
cap.release()
output.release()
cv2.destroyAllWindows()

后期需求

现在屏幕录制的问题基本解决了,要想做一个实用的屏幕录制软件,还需要加上音频录制,并设计一个便捷的UI界面。

参考文档:
[1] python视频操作——python实现读取和保存视频
[2] 择一柳 python 怎样实现屏幕视频录制?


http://www.ppmy.cn/news/76648.html

相关文章

【Dubbo核心 详解四】Dubbo服务提供者的详解

✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: Dubbo核心详解(附代码示例) 文章目录 引言一、服务提供者1.1 服务提供者介绍Dubbo 服务提供者启…

c++相关知识点(持续更新中~)

添加随机数种子: //通过利用当前时间生成随机数,防止每次随机数一样 srand((unsigned int)time(0)); int numrand()%1001;//生成1-100的值 //例如:如果需要生成30-200的值 那么% 171之后是0-170 之后再1 为1-171范围 再29 为30-200 //以此…

掌握RDD分区

零、本讲学习目标 学会如何指定分区数量会定义与使用自定义分区器 一、RRD分区 (一)RDD分区概念 RDD是一个大的数据集合,该集合被划分成多个子集合分布到了不同的节点上,而每一个子集合就称为分区(Partition&#…

【Netty】Netty 概述(一)

文章目录 前言一、Java原生API之痛二、Netty的优势2.1 非阻塞 I/O2.2 丰富的协议2.3 异步和事件驱动2.4 精心设计的API2.5 丰富的缓冲实现2.6 高效的网络传输 三、Netty 核心概念3.1 核心组件3.1.1 事件模型3.1.2 字节缓冲区3.1.3 通信API 3.2 传输服务3.2.1 NIO3.2.2 epoll3.2…

2023年湖北建筑架子工报名流程?报名需要什么资料?考试一次过?

2023年湖北建筑架子工报名流程?报名需要什么资料?考试一次过? 建筑架子工证是建筑行业必备的证书之一,它是证明持有人可以在建筑工地上从事搭建脚手架、模板等施工工作的重要证明。启程别告诉你架子工的报名流程和资料。 百度搜一…

Azkaban从入门到精通以及案例实操系列

1、Azkaban概论 1.1、Azkaban简介 Azkaban 是一个开源的基于 Web 的工作流调度系统,由 LinkedIn 公司开发并维护。它可以帮助用户在大规模数据处理中来管理和调度作业,提供了简单易用、高效可靠的工作流设计和调度功能。 Azkaban 的主要特点包括&…

服了呀,被现在的00后卷麻了....

现在的小年轻真的卷得过分了。前段时间我们公司来了个00年的,工作没两年,跳槽到我们公司起薪18K,都快接近我了。后来才知道人家是个卷王,从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天,原来这位小老弟家里条…

凹函数和凸函数

凹函数英文concave,凸函数英文concave。 在有些参考资料中,凸函数又称为下凹(concave down)函数,凹函数称为上凹(concave up)函数。 凹函数和凸函数根据判定方法的不同,分为以下两类: 一元函…