开发者

基于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

屏幕录制主要代码:

importnumpyasnp
fromPILimportImageGrab
importcv2

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

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

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

fromthreadingimportThread

classScreenshotVideo(Thread):

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

详细代码将在文末给出。

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

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

defvideo_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()

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

fromnumbaimportjit

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

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

使用pynput监听键盘按键

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

frompynputimportkeyboard#pipinstallpynput

defhotkey(self):
"""热键监听"""
withkeyboard.Listener(on_press=self.on_press)aslistener:
listener.join()

defon_press(self,key):
try:
ifkey.char=='t':#录屏结束,保存视频
self.flag=True
elifkey.char=='k':#录屏中止,删除文件
self.flag=True
self.kill=True
exceptExceptionase:
print(e)

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

如何保存MP4格式视频

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

OpenH264 Video Codec provided by Cisco Systems, Inc.

源码

本文实现的源码如下:

importtime
fromPILimportImageGrab
importcv2
frompathlibimportPath
importnumpyasnp
fromnumbaimportjit
frompynputimportkeyboard
fromthreadingimportThread


@jit(nopython=True)
defaverage_n(x,y):
"""Numpy计算趋近值"""
return((x+y+y)//3).astype(x.dtype)


classScreenshotVideo(Thread):

def__init__(self,width,high,path='',fps=15):
""LmqKeCjEk"初始化参数"""
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
defscreenshot():
"""静态方法,屏幕截图,并转换为np.array数组"""
returnnp.array(ImageGrab.grab())

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

definit_videowriter(self,path):
"""获取视频编码并新建视频文件"""
ifnotpath:
raiseException('视频路径未设置,请设置\nvideo=ScreenshotVideo(fps,width,high)\nvideo=video(video_path)')
path=Path(path)ifisinstance(path,str)elsepath
fourcc=cv2.VideoWriter_fourcc(*self.get编程客栈_fourcc(path.suffix))
returncv2.VideoWriter(path.as_posix(),fourcc,self.fps,(self.width,self.high))

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

defvideo_record_end(self):
"""录制结束,根据条件判断文件是否保存"""
self.video.release()
编程客栈cv2.destroyAllWindows()
ifself.save_fileandself.kill:
Path(self.save_file).unlink()

defvideo_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()

defpre_video_record(self):
"""预录制,以获取最佳fps值"""
self.video=selfwww.cppcns.com.init_videowriter('test.mp4')
start_time=time.time()
for_inrange(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()

definsert_frame_array(self,frame_list):
"""Numpy增强截图信息"""
fps_n=round(self.fps/self.best_fps)
iffps_n<=0:
returnframe_list
times=int(np.log2(fps_n))#倍率
for_inrange(times):
frame_list2=map(average_n,[frame_list[0]]+frame_list[:-1],frame_list)
frame_list=[[x,y]forx,yinzip(frame_list2,frame_list)]
frame_list=[jforiinframe_listforjini]
returnframe_list

defframe2video_run(self):
"""使用opencv将连续型截图转换为视频"""
self.video=self.init_videowriter(self.save_file)
start_time=time.time()
frame_list=[]
whileTrue:
frame_list.append(self.screenshot())
ifself.flag:
break
self.spend_time=round(time.time()-start_time,4)
ifnotself.kill:#视频录制不被终止将逐帧处理图像
frame_list=self.insert_frame_array(frame_list)
foriminframe_list:
self.video_record_doing(im)
self.video_record_end()

defhotkey(self):
"""热键监听"""
withkeyboard.Listener(on_press=self.on_press)aslistener:
listener.join()

defon_press(self,key):
try:
ifkey.char=='t':#录屏结束,保存视频
self.flag=True
elifkey.char=='k':#录屏中止,删除文件
self.flag=True
self.kill=True
exceptExceptionase:
print(e)

defrun(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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新开发

开发排行榜