桌面太单调?一起用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/129881.html原文链接:https://javaforall.net

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


相关推荐

  • Vs下 CCriticalSection::Lock 异常错误的发生「建议收藏」

    Vs下 CCriticalSection::Lock 异常错误的发生「建议收藏」自己在vs下写了一个用 CCriticalSection::Lock来锁定对象的程序,发现给Lock设置dword参数时总会出现异常,后来查看了一下函数的文档,才恍然大悟!!!CCriticalSection类包含成员函数锁定的线程可用于获得一个关键部分对象的所有权。有两个版本的锁定功能没有参数和其他采用DWORD参数之一。后一种版本的锁定文档状态dword值参数指定

    2022年7月20日
    12
  • android生成coredump,详解coredump–全面

    From:http://blog.csdn.net/tenfyguo/article/details/8159176一,什么是coredump我们经常听到大家说到程序core掉了,需要定位解决,这里说的大部分是指对应程序由于各种异常或者bug导致在运行过程中异常退出或者中止,并且在满足一定条件下(这里为什么说需要满足一定的条件呢?下面会分析)会产生一个叫做core的文件。通常情况下,core文件…

    2022年4月12日
    34
  • drone无人机是什么意思_无人机怎么选择

    drone无人机是什么意思_无人机怎么选择所以看到XTDronehttps://mp.weixin.qq.com/s/yU_xj8bMAASm8cIZnn2iZw看到Dronekit

    2022年8月15日
    4
  • eXtremeDB微秒级实时数据库简介「建议收藏」

    eXtremeDB微秒级实时数据库简介「建议收藏」eXtremeDB微秒级实时数据库简介 eXtremeDB实时数据库是美国McObject公司于上世纪九十年代末推出的全世界第一款全内存式实时数据库,特别为高性能、低开销、稳定可靠的极速实时数据管理而设计。 eXtremeDB的性能可以达到微秒一级的惊人速度。eXtremeDB能够达到这样惊人的极限速度,是由其对市场的独特理解、长期的行业经验、持续不断的创新精神和革命性的体系结构等…

    2022年8月31日
    1
  • docker的端口映射_docker修改端口映射

    docker的端口映射_docker修改端口映射1.downloadimage:docker@default:/root#dockerpullmikeraab/hello-earth:latest2.createandstartcontainer(docker主机IP:192.168.99.101)a)默认大写-P自动映射$docker@default:/root#dockerrun-d

    2022年10月17日
    0
  • mysql 全文索引无效_为什么MySQL全文索引不起作用?

    mysql 全文索引无效_为什么MySQL全文索引不起作用?在尝试了我能做的一切之后,我终于创建了这个测试表:CREATETABLEtest_table(idint(11)NOTNULLAUTO_INCREMENT,titletextNOTNULL,PRIMARYKEY(id),FULLTEXTKEYtitle(title))ENGINE=MyISAMDEFAULTCHARSET=utf8使用以下测试数据:INSERT…

    2022年6月21日
    43

发表回复

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

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