Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)

前言
前段时间,写了篇博客关于Python自制一款炫酷音乐播放器。有粉丝问我,音乐播放器为什么要用PyQt5,效果是不是比Tkinter赞?PyQt5真的可以实现这些炫酷的UI画面吗?之前没接触过PyQt5,能不能多分享一些这方面的开发案例?
今天就带大家,一起用Python的PyQt5开发一个有趣的自定义桌面动画挂件,看看实现的动画挂件效果!

下面,我们开始介绍这个自定义桌面动画挂件的制作过程。
直接跳到文末获取粉丝专属福利。
一、核心功能设计
总体来说,我们需要实现将自己喜欢的动态图gif或者视频转成一个桌面动画挂件,知识点主要包含了对GIF图/视频解析人像提取分割PyQt5窗体设置自定义挂件动画实现ico图标生成程序打包等。
拆解需求,大致可以整理出我们需要分为以下几步完成:

  1. 对gif或者视频进行逐帧解析,获取转换的图片,提取图像中人体区域,并对图片进行批量尺寸大小修改替换
  2. 初始化设置动画挂件窗体显示效果,窗体位置、大小等
  3. 桌面动画挂件功能实现,动画轮播、鼠标控制挂件位置拖动
  4. 挂件打包图标设置、打包配置
二、实现步骤
1. 解析提取,修改图片 GIF图解析:
Gif动态图资源大家可以根据自己的喜好,自己选择。博主就用之前写过的仙女蹦迪动态Gif来演示效果。

首先我们需要将Gif动态图按照每一帧进行解析 ,转换成图片格式。代码如下:
from PIL import Image# 导入PIL的Image包 import os gifFileName = "./demo.gif"# 把gif图赋值给gifFileName im = Image.open(gifFileName)# 使用Image的open函数打开test.gif图像 pngDir = gifFileName[:-4]# 倒着从gifFileName中的倒数第四个开始取字符(跳过.gif),赋值给pngDir,作为文件夹的名字 if not os.path.exists(pngDir): os.makedirs('./img')# 用图片名创建一个文件夹,用来存放每帧图片,名字为pngDir的值try: while True:# 死循环 current = im.tell()# 用tell函数保存当前帧图片,赋值给current im.save(pngDir+'/'+str(current+1)+'.png')# 调用save函数保存该帧图片 im.seek(current+1)# 调用seek函数获取下一帧图片,参数变为current帧图片+1 # 这里再次进入循环,当为最后一帧图片时,seek会抛出异常,代码执行except except EOFError: pass# 最后一帧时,seek抛出异常,进入这里,pass跳过

这样就可以把动态Gif图转换成图片了,效果如下:
Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)
文章图片

视频解析:
同理,对视频解析,也是按照每一帧进行解析,转换成图片格式。核心代码如下:
# 将视频按照每一帧转成图片png import cv2 videoFileName = "./demo.mp4"# 把视频路径赋值给videoFileName pngDir = videoFileName[:-4]# 倒着从gifFileName中的倒数第四个开始取字符(跳过.后缀),赋值给pngDir,作为文件夹的名字 if not os.path.exists(pngDir): os.makedirs(pngDir)# 用图片名创建一个文件夹,用来存放每帧图片,名字为pngDir的值 # 视频处理 分割成一帧帧图片 cap = cv2.VideoCapture(videoFileName) num = 1 while True: # 逐帧读取视频按顺序保存到本地文件夹 ret, frame = cap.read() if ret: cv2.imwrite(f"{ pngDir}/{ num}.png", frame)# 保存一帧帧的图片 num += 1 else: break cap.release()# 释放资源

效果如下:
Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)
文章图片

逐帧提取的图片已经拿到了,下面我们需要对这些图片中的人像进行分割提取。
人像分割:
我们调用的是百度开放的人体分析接口 – 百度AI开放平台链接。
Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)
文章图片

这里面我们可以创建一个人像分割的应用,其中的API Key及Secret Key后面我们调用人脸识别检测接口时会用到。
Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)
文章图片

我们可以看到官方提供的帮助文档,介绍地很详细。如何调用请求URL数据格式,向API服务地址使用POST发送请求,必须在URL中带上参数access_token,可通过后台的API Key和Secret Key生成。这里面的API Key和Secret Key就是我们上面提到的。
Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)
文章图片

那我们如何获取空背景的人像图片呢?根据API文档,可以看到里面有个type属性设置为foreground 就可以提取空背景的人像图片。
Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)
文章图片

人像分割的接口流程基本就已经清楚了,可以进行代码实现了。
# 保存图片 def save_base_image(img_str, filename): img_data = https://www.it610.com/article/base64.b64decode(img_str) with open(filename,'wb') as f: f.write(img_data)# 获取token def get_token(): host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=' + client_id + '&client_secret=' + client_secret request = urllib.request.Request(host) request.add_header('Content-Type', 'application/json; charset=UTF-8') response = urllib.request.urlopen(request) token_content = response.read() if token_content: token_info = json.loads(token_content) token_key = token_info['access_token'] return token_key# 人像分割 def body_seg_fore(filename, resultfilename): request_url = "https://aip.baidubce.com/rest/2.0/image-classify/v1/body_seg"# 二进制方式打开图片文件 f = open(filename, 'rb') img = base64.b64encode(f.read())params = dict() params['image'] = img params['type'] = 'foreground' params = urllib.parse.urlencode(params).encode("utf-8") # params = json.dumps(params).encode('utf-8')access_token = get_token() request_url = request_url + "?access_token=" + access_token request = urllib.request.Request(url=request_url, data=https://www.it610.com/article/params) request.add_header('Content-Type', 'application/x-www-form-urlencoded') response = urllib.request.urlopen(request) content = response.read() if content: # print(content) content = content.decode('utf-8') # print(content) data = https://www.it610.com/article/json.loads(content) # print(data) img_str = data['foreground'] save_base_image(img_str, resultfilename)

这样我们就可以根据图片,进行人像分割,提取出空背景的人像图。效果如下:
Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)
文章图片

Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)
文章图片

如果提取的人像图片大小不符合我们的要求,我们还可以对图片大小进行调整。
file_list = os.listdir("./image")# 读取当前文件夹所有文件 # print(file_list) n = len(file_list) for i in range(n): s = str(file_list[i]) if s[-4:] == ".png":# 检查后缀 src = https://www.it610.com/article/os.path.join(os.path.abspath('./image/'), s)# 原先的图片名字 img = Image.open(src) new_img = img.resize((128, 128), Image.BILINEAR) new_img.save(src)

我们需要的空背景图片已经拿到了,接下来我们来实现桌面挂件功能。
2. 初始化动画挂件
# 窗体初始化 def windowinit(self): self.x = 1650 self.y = 860 self.setGeometry(self.x, self.y, 300, 300) self.setWindowTitle('My Gadgets') self.img_num = 1 self.img_path = './image/{file}/{img}.png'.format(file=self.dis_file, img=str(self.img_num)) self.lab = QLabel(self) self.qpixmap = QPixmap(self.img_path) self.lab.setPixmap(self.qpixmap) self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.SubWindow) self.setAutoFillBackground(False) self.setAttribute(Qt.WA_TranslucentBackground, True) self.show()def __init__(self): super(Gadgets, self).__init__()self.dis_file = "img1" self.windowinit() self.icon_quit()self.pos_first = self.pos() self.img_count = len(os.listdir('./image/{}'.format(self.dis_file)))

这样图片挂件就可以显示出来,效果如下:
Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)
文章图片

现在的桌面挂件是静态显示,下面我们可以通过计时器进行挂件动画轮播显示。
3. 动画挂件功能实现 动画轮播:
self.timer = QTimer() self.timer.timeout.connect(self.img_update) self.timer.start(100) def img_update(self): if self.img_num < self.img_count: self.img_num += 1 else: self.img_num = 1 self.img_path = './image/{file}/{img}.png'.format(file=self.dis_file, img=str(self.img_num)) self.qpixmap = QPixmap(self.img_path) self.lab.setPixmap(self.qpixmap)

鼠标控制挂件位置拖动:
def mousePressEvent(self, QMouseEvent): if QMouseEvent.button() == Qt.LeftButton: self.pos_first = QMouseEvent.globalPos() - self.pos() QMouseEvent.accept() self.setCursor(QCursor(Qt.OpenHandCursor))def mouseMoveEvent(self, QMouseEvent): if Qt.LeftButton: self.move(QMouseEvent.globalPos() - self.pos_first) print(self.pos()) self.x, self.y = self.pos().x, self.pos().y QMouseEvent.accept()def quit(self): self.close() sys.exit()

至此,自定义动画挂件功能已经实现完成,动画挂件效果如下:

4. 打包配置 前段时间有粉丝问我,Python能不能打包成exe?如何打包呢?今天就通过这个来一起介绍下。
Python常用的打包工具是第三方库Pyinstaller,首先需要安装下pyinstaller。
pip install Pyinstaller

接下来,我们需要打开命令窗口,切换到项目目录下再执行打包命令。
pyinstaller -F -i ./img.ico Qt_Gadgets.py

打包常用的参数如下:
  • -F 表示生成单个可执行文件
  • -w 表示去掉控制台窗口,这在GUI界面时非常有用。不过如果是命令行程序的话那就把这个选项删除吧!
  • -p 表示你自己自定义需要加载的类路径,一般情况下用不到
  • -i 表示可执行文件的图标
之前有小伙伴问我,打包的图标需要.ico后缀的图片,应该如何把普通图片转成图标格式.ico呢?Python当然可以帮你实现,今天就一起教给大家。核心代码如下:
import PythonMagick# 生成图标ico(png格式图片转成ico) img = PythonMagick.Image('./image/img1/1.png') # 这里要设置一下尺寸,不然会报ico尺寸异常错误 img.sample('128x128') img.write('./img.ico')

图标得到了,下面我们就可以进行打包操作了。
Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)
文章图片

打包完成之后,我们可以看见项目目录下会有生成的exe程序。
Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)
文章图片

至此,整个自定义动画挂件就全部完成了,下面我们一起运行下exe看看动画挂件效果。

源码及数据已上传,关注文末公众号回复【源码】即可获取完整源码
Python往期精彩:
  • 见过仙女蹦迪吗?一起用python做个小仙女代码蹦迪视频
  • python自制一款炫酷音乐播放器,想听啥随便搜!
  • 斗地主老是输?一起用Python做个AI出牌器,豆子蹭蹭涨!
  • 桌面太单调?一起用Python做个自定义动画挂件,好玩又有趣!
  • 一起用Python做个车牌自动识别系统,好玩又实用!
  • 桌面太单调?一起用Python做个自定义动态壁纸,竟然还可以放视频!
  • 【Python|桌面太单调(一起用Python做个自定义动画挂件,好玩又有趣!)】 一起用Python做个自动化弹钢琴脚本,我竟然弹出了《天空之城》!
    往期精彩源码均可通过下方公众号获取

    推荐阅读