尝试使用 Python 截屏并录屏
( 本文的完整版地址在 https://www.ccgxk.com/?post=494 )
我在去年,曾经尝试过一个大胆的东西,就是使用 Python 写了个程序来录屏,以此给自己一种“期待感”,当时有没有效果我忘了,但是现在我又将这个项目捡了起来。
界面是长上面那个样子,集成了项目名设置、开始录制、结束录制、转换视频的功能,看起来没有那么潦草了,这个是一种录屏软件,当然,之后我估计还会把删除截的图片那一功能给搞一下,因为转换成视频后,那一大堆临时图片确实也没有什么必要存在了。
当然,这篇文章并不是 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 cv2
global_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 变成 rgb
screenshot_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 = 200
height = 170
screenwidth = 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_unixtime
itemProjName = itemNameInput.get()
if not itemProjName:
messagebox.showerror('error', '项目名称不能为空!')
return 0
if 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 + 1
label.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 = picdir
save_video_dir = './video_output/'
if not os.path.exists(save_video_dir):
os.makedirs(save_video_dir)
fps = myfps
frames = 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 = outputname
video_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://www.cnblogs.com/duyuanshang/p/18272320