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

桌面太单调?一起用Python做个自定义动画挂件,好玩又有趣!前言前段时间,写了篇博客关于Python自制一款炫酷音乐播放器。有粉丝问我,音乐播放器为什么要用PyQt5,效果是不是比Tkinter赞?PyQt5真的可以实现这些炫酷的UI画面吗?之前没接触过PyQt5,能不能多分享一些这方面的开发案例?今天就带大家,一起用Python的PyQt5开发一个有趣的自定义桌面动画挂件,看看实现的动画挂件效果!下面,我们开始介绍这个自定义桌面动画挂件的制作过程。一、核心功能设计总体来说,我们需要实现将自己喜欢的动态图gif或者视频转成一个桌面动画挂件,并且可以通过鼠

大家好,又见面了,我是你们的朋友全栈君。

前言

前段时间,写了篇博客关于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图转换成图片了,效果如下:

在这里插入图片描述
视频解析:

同理,对视频解析,也是按照每一帧进行解析,转换成图片格式。核心代码如下:

# 将视频按照每一帧转成图片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()   # 释放资源

效果如下:
在这里插入图片描述
逐帧提取的图片已经拿到了,下面我们需要对这些图片中的人像进行分割提取。

人像分割:

我们调用的是百度开放的人体分析接口百度AI开放平台链接

在这里插入图片描述
这里面我们可以创建一个人像分割的应用,其中的API Key及Secret Key后面我们调用人脸识别检测接口时会用到。

在这里插入图片描述
我们可以看到官方提供的帮助文档,介绍地很详细。如何调用请求URL数据格式,向API服务地址使用POST发送请求,必须在URL中带上参数access_token,可通过后台的API Key和Secret Key生成。这里面的API Key和Secret Key就是我们上面提到的。
在这里插入图片描述
那我们如何获取空背景的人像图片呢?根据API文档,可以看到里面有个type属性设置为foreground 就可以提取空背景的人像图片。

在这里插入图片描述
人像分割的接口流程基本就已经清楚了,可以进行代码实现了。

# 保存图片
def save_base_image(img_str, filename):
    img_data = 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=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 = json.loads(content)
        # print(data)
        img_str = data['foreground']
        save_base_image(img_str, resultfilename)

这样我们就可以根据图片,进行人像分割,提取出空背景的人像图。效果如下:

在这里插入图片描述
在这里插入图片描述
如果提取的人像图片大小不符合我们的要求,我们还可以对图片大小进行调整。

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 = 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)))

这样图片挂件就可以显示出来,效果如下:
在这里插入图片描述
现在的桌面挂件是静态显示,下面我们可以通过计时器进行挂件动画轮播显示。

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')

图标得到了,下面我们就可以进行打包操作了。
在这里插入图片描述
打包完成之后,我们可以看见项目目录下会有生成的exe程序。
在这里插入图片描述
至此,整个自定义动画挂件就全部完成了,下面我们一起运行下exe看看动画挂件效果。

在这里插入图片描述

源码及数据已上传,关注文末公众号回复【源码】即可获取完整源码

Python往期精彩:

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/129879.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Java Web前端到后台常用框架介绍

    Java Web前端到后台常用框架介绍

    2020年11月12日
    184
  • 数据库严格模式_mysql关系型数据库

    数据库严格模式_mysql关系型数据库设置严格模式为当前会话设置严格模式:执行SETsql_mode=’STRICT_TRANS_TABLES’或者SETsql_mode=’STRICT_ALL_TABLES’。全局设置严格模式:执行SETglobalsql_mode=’STRICT_TRANS_TABLES’或者SETglobalsql_mode=’STRICT_ALL_TABLES’。或者在MyS…

    2025年7月10日
    7
  • 莫比乌斯反演的两种形式及其证明

    莫比乌斯反演的两种形式及其证明莫比乌斯反演形式一 nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp 证明 把代入右边的式子 得 nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp 根据莫比乌斯函数的性质 有定理 nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp 因此 只有

    2025年6月28日
    3
  • 对单片机毕业设计的理解「建议收藏」

    对单片机毕业设计的理解「建议收藏」对单片机毕业设计的理解我的大学生活即将快要结束了,在这期间,我帮好几个人都做了关于单片机的毕业设计,其中也有接挺多这种单子赚了点辛苦费的,其中有关于51单片机的,也有STM32单片机的,甚至STM32可以细分为F1系列和F4系列。本来我是没有想接单的,一开始是一个高中同学,因为是同一个专业但是不同学校,他的毕业设计就是关于单片机的,他那时就求助我,然后我直接帮他完成了,我帮他做完全是因为关系好,结果帮他做完后他就给我介绍了他的一个大学同学也想完成他的毕业设计,所以我就做了,最后做完也是给了点辛苦费。没想到

    2022年9月28日
    4
  • 监控录像数据恢复方法步骤详解

    监控录像数据恢复方法步骤详解在人们生活日益改善的今天,社会的和谐安定成为了最为重要的一个问题。一些不法分子为了一己私利,通过不法手段谋取他人的财物。这样的行为对社会对个人都是一种威胁,为了能更好的防治这类社会危害因素,那就需要我们的电子警察——视频监控出马了。视频监控在现在生活中随处可见,道路上有治安监控,各家商铺有防盗监控,随处可见的监控给人们的生命财产安全带来了一份保障。利用安全防范技术进行安全防范首先对犯罪分子

    2022年5月4日
    275
  • 模块驱动调试记录 ——platform_driver_register

    模块驱动调试记录 ——platform_driver_register当前module_init中使用platform_driver_register(&dev_driver)注册了设备驱动,在 /sys/bus/platform/drivers生

    2022年7月4日
    18

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号