尝试使用 Python 截屏并录屏

news/2024/7/2 15:25:06/文章来源:https://www.cnblogs.com/duyuanshang/p/18272320

( 本文的完整版地址在 https://www.ccgxk.com/?post=494 )

我在去年,曾经尝试过一个大胆的东西,就是使用 Python 写了个程序来录屏,以此给自己一种“期待感”,当时有没有效果我忘了,但是现在我又将这个项目捡了起来。

img

界面是长上面那个样子,集成了项目名设置、开始录制、结束录制、转换视频的功能,看起来没有那么潦草了,这个是一种录屏软件,当然,之后我估计还会把删除截的图片那一功能给搞一下,因为转换成视频后,那一大堆临时图片确实也没有什么必要存在了。


当然,这篇文章并不是 2022 年写的,而是 2024年06月27日 写的,之所以这样搞,是因为我不想通过 RSS 来惊扰人,毕竟我曾经搞过太多让自己牛逼的想法了,但无一例外以失败告终。如果这个尝试如之前一大堆被喧闹地宣布过的尝试一样,那肯定又是一个打击了。

哈哈,回想过去的几个月的落魄操作,我似乎感觉,如果我不是选择去进工厂来个日夜生死 10 小时的两班倒,或者找个工作,那么整个世界都在我的脑门上深深的蒙上一层令人窒息的惩罚。

没事,还有丘吉尔,丘吉尔的 Never give up 一直在鼓励我,甚至和丘吉尔和谈这种事情也不同意,就是一条路走到黑,赢得地铁上百余人的热心支持和整个礼堂百千人,整个国家千万人的异口同声,那种感觉实在是妙极了!!! 终有一天,我会一天就把这些我欠下的帐一并偿还!从此人生结束那数十年载的废物状态,迎接心里期望已久的大理石、花园、雕塑、果冻那种梦幻成功人士之生活!

厄,跑题有点远了哈。

然后,当时是认为,我一直是只有在感到自己在被监视的情况下、或者更准确一点,我认为我不是孤单一人,我是对某物有责任感时,我就会搞起更多的注意力来行我的事情。

举个例子,我经常使用摄像头来录“日志”,以便于我能持续的说话。为什么?因为如果我是对着一片空气,或者说是对着一面白墙来说话的话,那么我肯定是马上跑神,两分钟我都觉得悬,这也是我为什么在搞很多正业,尤其是学生时代搞作业和其他学习活动的时候不断的跑神。这些事情的原因是一样的,没有责任感,也没有另一种学者口中所述的互动感的话,那么我将没有任何的执行力。

当然,即便我现在是多么相信这个方法可以带给我比较强的执行力,但我的历史告诉我,执行力没有这么容易被解决,再过几日,这个方法和过去千千万万方法一样,会被扫入脑海里的垃圾堆里,以及给我自信上再划上一道不忍直视的裂痕。

但是,使用摄像头又有点过于麻烦,所以,我还是想起使用 Python 来一张一张的截图,最后再通过 OpenCV 合成一个视频。听起来很牛逼!

那么今天下午搞了一下午,终于把东西搞出来了,一个初步能使用的家伙,不知道会不会有效呢?现在我把代码给粘贴到下面,然后这种东西,也上传到 github 上吧,好久没有往我的 github 上搞过任何东西了。

代码如下,Python :

from PIL import ImageGrab, Image
import os
import time
import tkinter as tk
from tkinter import messagebox 
from datetime import datetime
import cv2global_folder = 'myscreen'  # 文件夹
global_pic_name_i = 100000000  # 截屏图像名称序列
global_pic_time = 5000  # 截屏的时间差(单位为秒,但似乎并不准确)
global_afterid = None  # after id
global_unixtime = None  # unix 时间戳# 截屏并保存的函数
def takeScrPic(folder, picName):screenshot_folder = folder  # 文件夹screenshot_name = picName  # 截屏图像名称new_width = 1080  # 新的宽度pic_quality = 45 # 截图的图片质量(1~95)if not os.path.exists(screenshot_folder):  # 文件夹不存在就建立一个os.makedirs(screenshot_folder)screenshot = ImageGrab.grab()  # 截屏命令 width, height = screenshot.size  # 宽高计算new_height = int(height * (new_width / width))   resized_screenshot = screenshot.resize((new_width, new_height))  # 根据新宽高来转换图片 resized_screenshot = resized_screenshot.convert('RGB')  # rgba 变成 rgbscreenshot_path = os.path.join(screenshot_folder, screenshot_name)   resized_screenshot.save(screenshot_path, 'JPEG', quality=pic_quality)  # 保存到目录print(f'The resized screenshot is {new_width} wide x {new_height} tall and saved as {screenshot_path}')  # 打印结果# 程序的界面
def makeUI():root = tk.Tk()root.title('screenRec')root.attributes('-topmost', True) # 将窗口置顶width = 200height = 170screenwidth = root.winfo_screenwidth()screenheight = root.winfo_screenheight()size_geo = '%dx%d+%d+%d' % (width, height, (screenwidth-width)/2, (screenheight-height)/2 - 70)root.geometry(size_geo)# root.resizable(False, False) label = tk.Label(root, text='输入项目名称,点击开始录制')  label.pack()itemNameInput = tk.Entry(root)  itemNameInput.pack(pady=10)  startButton = tk.Button(root, text='开始录制', command=clickDef)startButton.pack()endButton = tk.Button(root, text='停止录制', command=stopAfter, state='disabled')endButton.pack()convertButton = tk.Button(root, text='转换成视频', command=item2video, state='disabled')convertButton.pack()return root, label, itemNameInput, startButton, endButton, convertButton# 开始录制的点击事件
def clickDef():global global_pic_name_i, global_afterid, global_unixtimeitemProjName = itemNameInput.get()if not itemProjName:messagebox.showerror('error', '项目名称不能为空!')return 0if not global_unixtime:global_unixtime = int(time.time())takeScrPic(itemProjName, itemProjName + str(global_pic_name_i) + '.jpg')global_pic_name_i = global_pic_name_i + 1label.config(text='已截 ' + str(global_pic_name_i - 100000000) + ' 张,' + '已录制' + toGoodTime( int(time.time()) - global_unixtime ))global_afterid = root.after(global_pic_time, clickDef)endButton.config(state='normal')startButton.config(state='disabled')# 将秒转化为分秒格式
def toGoodTime(sec):minutes = str(sec // 60)remaining_seconds = str(sec % 60)return str(' ' + minutes+' 分 '+ remaining_seconds +' 秒')# 停止录制
def stopAfter():root.after_cancel(global_afterid)endButton.config(state='disabled')convertButton.config(state='normal')# 点击 转化成视频 按钮
def item2video():label.config(text = '转化中,请稍后...')itemProjName = itemNameInput.get()convertButton.config(state='disabled')convert2Video(itemProjName, itemProjName + '.mp4')# 将序列转化为视频
def convert2Video(picdir, outputname, myfps=25):im_dir = picdirsave_video_dir = './video_output/'if not os.path.exists(save_video_dir):os.makedirs(save_video_dir)fps = myfpsframes = sorted(os.listdir(im_dir))  # 提取序列img = cv2.imread(os.path.join(im_dir, frames[0]))img_size = (img.shape[1], img.shape[0])seq_name = outputnamevideo_dir = os.path.join(save_video_dir, seq_name)# fourcc = cv2.VideoWriter_fourcc('M', 'P', '4', 'V')fourcc = cv2.VideoWriter_fourcc(*'avc1')videowriter = cv2.VideoWriter(video_dir, fourcc, fps, img_size)for frame in frames:f_path = os.path.join(im_dir, frame)image = cv2.imread(f_path)videowriter.write(image)print(frame + ' has been written!')videowriter.release()label.config(text = '转化完成')# ↑↑↑↑↑ convert2Video('myscreen', 'out.mp4') 本函数的示例用法 ↑↑↑↑↑root, label, itemNameInput, startButton, endButton, convertButton = makeUI()
root.mainloop()

平时不怎么用 Python,语法也不是很懂,在 AI 语言大模型的帮助下,现学现卖把东西搞了出来。

至于需要安装的第三方库,也就一个 cv2 我感觉。

pip3 install opencv-python
或
pip install opencv-python

也就那样吧。其实这个程序特别适合使用 命令行 来搞,但上一次我确实是使用的命令行,可惜可能因为会显得这玩意儿很无聊,所以当时有放弃了,这次我把写项目名称、录制、停止、转换成视频都集成到一个界面里了,这样应该也不会有什么奇怪的理由来拒绝了吧?我也不知道。

简单说一下程序吧。

其实也没什么可说的,截图程序是 文心一言 给我写的,我那按钮点点变成可用还是不可用的逻辑也是很明了的写在那里。

文件名使用的是 100000000 去加,是因为我不知道怎么写一个能自动 01、02、.... 11、12 这样前面自动补零的算法,所以偷了个懒,直接使用一个大数相加了,为什么要前面补零呢?如果不补零的话,后期它无法识别这个序列的顺序,它会从1、10、11、....、19、2、20、21.... 这种迷之排序。

root, label, itemNameInput, startButton, endButton, convertButton = makeUI()  

这一行的 Python 独家操作,我当时还是震撼了好久。这一行,makeUI() 这个程序最后,把这些元素给 return 出来了,然后在外面接受一下,就整个程序可访问了。

另外我也发现,Python 也没那么智能,在 JavaScript 里我直接把数字和字符串相加,就能直接连接到一起,而在 Python 里,必须用 str() 来字符串化一下数字才能用。其实我觉得 JavaScript 已经证明了这样的无必要性,Python 到底是在图啥???

另外还有一点想要吐槽的是:

fourcc = cv2.VideoWriter_fourcc(*'avc1')
videowriter = cv2.VideoWriter(video_dir, fourcc, fps, img_size)

我乒乒乓乓搞了一大堆对于最后输出视频的视频配置,最后告诉我不能设置比特率和压缩质量。OpenCV 了呀,最后生成的视频,体积还是那么大。不过没事,到时候我再搞个 ffmpeg 搞里头,让它转义一下,把已经没用的图片文件、大视频删除了即可。

别的就没有了。我把它也上传到我的 github 里吧。

https://github.com/kohunglee/rec_screen_py

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/732469.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Compose 延迟列表踩过的坑

问题 在使用 Jetpack Compose 延迟列表时遇到一个坑,简单记录一下。直接上代码:这个代码看起来也没有什么问题,滑动正常,点击滑动到顶部也正常。 但是极端操作:在一边滑动列表一边点击按钮,就出问题了。这样再点击按钮,就不生效了。从日志来看,点击时协程发射值没有问题…

代码随想录算法训练营第22天 | 77.组合 216.组合总和 17.电话号码的字母组合

77.组合 给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。 解题 只能取比它大的,所以有个参数startindex 参数:一维数组单个组合path,二维数组结果集result,总数n,组合大小k,搜索结果的开始索引startindex 终止条件:path.size=k点击查看代码 class Solut…

(四)详解RLHF

一直都特别好奇大模型的强化学习微调是怎么做的,网上虽然相关文章不少,但找到的文章都是浅尝辄止说到用PPO训练,再细致深入的就没有讲了。。。只能自己看一看代码,以前搞过一点用PPO做游戏,感觉和语言模型PPO的用法不太一样。在游戏场景,每个step给环境一个action之后,a…

模拟集成电路设计系列博客——8.1.1 锁相环基本介绍

8.1.1 锁相环基本介绍 几乎所有的数字,射频电路以及大部分的模拟电路。不幸的是,集成电路振荡器本身并不适合用于高性能电路中的频率/时间参考源。一个主要的问题是它们的震荡频率并不能精确知道。更进一步的,集成电路振荡器的时钟抖动(可以被认为是频率上的随机波动)对于…

(三)使用 PPO 算法进行 RLHF 的 N 步实现细节

使用 PPO 算法进行 RLHF 的 N 步实现细节 当下,RLHF/ChatGPT 已经变成了一个非常流行的话题。我们正在致力于更多有关 RLHF 的研究,这篇博客尝试复现 OpenAI 在 2019 年开源的原始 RLHF 代码库,其仓库位置位于 openai/lm-human-preferences。尽管它具有 “tensorflow-1.x” …

JMeter安装目录简单说明

一 前言 环境: window 10 JMeter5.3 JMeter安装目录的文件通常容易被忽略,注意力全放在JMeter本身的各个功能的使用上。 但在前面的学习中我们发现了熟悉安装目录的必要性。 如jmeter.properties这个文件,之前的文章中就经常查看或者修改,还有一些日志文件也在安装目录中 二…

G61【模板】线性基 P3812 线性基

视频链接: G23 线性方程组 高斯消元法 - 董晓 - 博客园 (cnblogs.com) P3812 【模板】线性基 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)// 线性基 O(63*n) #include <iostream> #include <cstring> #include <algorithm> using namespace std;typede…

寿司

寿司 题目描述解析 合法的结果只有两种情况:\(B\) 都在两边、\(R\) 都在两边,至于是最左边还是最右边或者都有,无所谓,因为是环。 而每个 \(B\) 移到最左边的代价就是它左边 \(R\) 的个数,移到最右边就是它右边 \(R\) 的个数。 按环形 dp 的套路,我们可以把串复制二倍,然…

(一)ChatGPT 背后的“功臣”——RLHF 技术详解

ChatGPT 背后的“功臣”——RLHF 技术详解 OpenAI 推出的 ChatGPT 对话模型掀起了新的 AI 热潮,它面对多种多样的问题对答如流,似乎已经打破了机器和人的边界。这一工作的背后是大型语言模型 (Large Language Model,LLM) 生成领域的新训练范式:RLHF (Reinforcement Learnin…

Jetpack Compose(8)——嵌套滚动

目录前言一、Jetpack Compose 中处理嵌套滚动的思想二、Modifier.nestedScroll2.1 NestedScrollConnection2.2 NestedScrollDispatcher三、实操讲解3.1 父组件消费子组件给过来的事件——NestedScrollConnection3.2 子组件对事件进行分发——NestedScrollDispatcher3.2 按照分发…

Unity Address Asset System:Assembly-CSharp - 可用Assembly-CSharp.Player - 不可用

在使用Unity的Addressables插件进行游戏资源分包管理的时候,报了这个错误: 反编译查看发现是unity与.net版本不匹配导致的问题 解决方案: 在Unity中打开Edit->Project Settings->Player,更改.Net版本 微软官方文档: 在 Unity 中使用 .NET 4 和更高版本 | Microsoft …

CC2分析与利用

CC2分析与利用 环境配置 一、 CC2 需要使用commons-collections-4.0版本,因为3.1-3.2.1版本中TransformingComparator没有实现Serializable接口,不能被序列化,所以CC2不用3.x版本。还需要 javassist 依赖,利用链2需要。 pom.xml 添加:<dependency><groupId>or…

【计算机网络】TCP连接三次握手和四次挥手

三次握手建立连接 TCP(传输控制协议)的三次握手机制是一种用于在两个 TCP 主机之间建立一个可靠的连接的过程。这个机制确保了两端的通信是同步的,并且在数据传输开始前,双方都准备好了进行通信。①、第一次握手:SYN(最开始都是 CLOSE,之后服务器进入 LISTEN)发起连接:…

原型设计

原型设计的重要性 网页原型显示了网页的骨架结构,因此可以更好地了解用户将去哪里以及如何导航,通过视觉方式表达产品的要求。 网页原型还有助于交流想法和规划网页,提高团队沟通的效率和质量,进行高效协作。 设计团队与客户沟通变得容易,能够有效地减少了返工和误解,降低…

weblogic 漏洞复现

1.环境地址信息http://192.168.116.112:7001/console/ 2.使用漏洞检测工具,检测对应漏洞 选中对应漏洞检查,发现存在对应漏洞 3.漏洞利用 命令执行 内存马上传使用冰蝎连接 连接成功

详细解析ORB-SLAM3的源码

随着计算机视觉和机器人技术的发展,SLAM(同步定位与地图构建)技术在自动导航、机器人和无人机等领域中起着至关重要的作用。作为当前最先进的SLAM系统之一,ORB-SLAM3因其卓越的性能和开源特性,备受关注。本文将详细解析ORB-SLAM3的源码 ,帮助读者更好地理解其内部机制。 …

H3C之IRF典型配置举例(BFD MAD检测方式)

IRF典型配置举例(BFD MAD检测方式) 1、组网需求由于网络规模迅速扩大,当前中心设备(Device A)安全业务处理能力已经不能满足需求,现在需要另增一台设备Device B,将这两台设备组成一个IRF(如图所示),并配置BFD MAD进行分裂检测。2、组网图 IRF典型配置组网图(BFD MAD…

【攻防技术系列+反溯源】入侵痕迹清理

#溯源 #入侵痕迹清理 #攻防演练 在授权攻防演练中,攻击结束后,如何不留痕迹的清除日志和操作记录,以掩盖入侵踪迹,这其实是一个细致的技术活。 在蓝队的溯源中,攻击者的攻击路径都将记录在日志中,所遗留的工具也会被蓝队进行分析,在工具中可以查找特征,红队自研工具更容…

ProfibusDP主站转Modbus模块连接综合保护装置配置案例

常见的协议有Modbus协议,ModbusTCP协议,Profinet协议,Profibus协议,Profibus DP协议,EtherCAT协议,EtherNET协议等。本案例描述了如何使用ProfibusDP主站转Modbus模块(XD-MDPBM20)来连接综合保护装置(综保),实现数据交换和远程控制。通过配置ProfibusDP主站和Modbus…