предисловие
Некоторое время назад я написал блог о классном музыкальном проигрывателе, сделанном на Python . Некоторые фанаты спрашивали меня, почему я использую PyQt5 для музыкальных плееров, эффект лучше, чем у Tkinter? Может ли PyQt5 действительно достичь этих крутых изображений пользовательского интерфейса? Я никогда раньше не контактировал с PyQt5, можете ли вы поделиться другими примерами разработки в этом отношении?
Сегодня я возьму вас всех, чтобы разработать интересную пользовательскую подвеску с анимацией для рабочего стола с помощью Python PyQt5 и увидеть эффект подвески с анимацией!
Далее мы начинаем знакомить вас с процессом производства этого индивидуального анимационного кулона для рабочего стола.
Перейдите прямо к концу статьи , чтобы получить эксклюзивные преимущества для поклонников.
1. Дизайн основных функций
В общем, нам нужно преобразовать наш любимый динамический gif или видео в кулон с анимацией на рабочем столе.Точки знаний в основном включают анализ изображения / видео GIF , извлечение и сегментацию портрета , настройки формы PyQt5 , реализацию пользовательской подвесной анимации , создание значков ico , упаковку программ. , и т.д.
Требования к демонтажу можно грубо разобрать, и нам нужно разделить их на следующие шаги для выполнения:
- Проанализируйте gif или видео кадр за кадром, получите преобразованное изображение, извлеките область человеческого тела на изображении, а также измените и замените размер изображения в пакетном режиме.
- Инициализируйте и задайте эффект отображения формы анимационной подвески, положение и размер формы и т. д.
- Реализация функции подвески анимации рабочего стола, карусель анимации, перетаскивание положения подвески управления мышью
- Настройки значка упаковки подвески, конфигурация упаковки
2. Этапы реализации
1. Разбирать и извлекать, изменять картинки
Анализ 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() # 释放资源
Эффект следующий:
Получены кадр за кадром извлеченные картинки, и нам нужно сегментировать и извлечь портреты на этих картинках.
Портретная сегментация:
То, что мы называем открытым интерфейсом Baidu для анализа человеческого тела — Baidu AI Open Platform Link .
Здесь мы можем создать приложение портретной сегментации, в котором ключ API и секретный ключ будут использоваться позже, когда мы вызовем интерфейс обнаружения распознавания лиц.
Мы можем увидеть официальную справочную документацию, которая очень подробная. Как вызвать формат данных URL-адреса запроса и отправить запрос на адрес службы API с помощью POST , параметр access_token должен быть включен в URL-адрес , который может быть сгенерирован API-ключом и секретным ключом в фоновом режиме. Ключ API и секретный ключ — это те, о которых мы упоминали выше.
Так как же нам получить портретное изображение с пустым фоном? Согласно документации 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 запаковать в исполняемый файл? Как его упаковать? Давайте представим его вместе сегодня.
Обычно используемым инструментом упаковки для Python является сторонняя библиотека Pyinstaller.Во-первых, вам нужно установить pyinstaller.
pip install Pyinstaller
Далее нам нужно открыть командное окно, переключиться в директорию проекта и выполнить команду пакета.
pyinstaller -F -i ./img.ico Qt_Gadgets.py
Обычно используемые параметры упаковки следующие:
-
-F означает генерировать один исполняемый файл
-
-w означает удалить окно консоли, что очень полезно в графическом интерфейсе. Но если это программа командной строки, то удалите эту опцию!
-
-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:
Python — отличный музыкальный проигрыватель, вы можете искать все, что хотите послушать!
Используя Python для создания сценария автоматической игры на фортепиано, я на самом деле выдал «City in the Sky»!
Замечательный исходный код в прошлом можно получить через следующий публичный аккаунт