Python:生成表白爱心动画(程序的优化与打包)

目录

效果预览

功能的实现

优化内容

完整代码

性能分析


效果预览

程序参考于:python 爱心代码-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_74994771/article/details/137294470?spm=1000.2115.3001.6382&utm_medium=distribute.pc_feed_v2.none-task-blog-hot-11-137294470-null-null.329%5Ev9%5E%E4%B8%AA%E6%8E%A8pc%E9%A6%96%E9%A1%B5%E6%8E%A8%E8%8D%90%E2%80%94%E6%A1%B67&depth_1-utm_source=distribute.pc_feed_v2.none-task-blog-hot-11-137294470-null-null.329%5Ev9%5E%E4%B8%AA%E6%8E%A8pc%E9%A6%96%E9%A1%B5%E6%8E%A8%E8%8D%90%E2%80%94%E6%A1%B67

打包的exe文件:pyhton实现的爱心动画exe文件资源-CSDN文库icon-default.png?t=N7T8https://download.csdn.net/download/YYKand/89117257

功能的实现

优化内容

        1.使用线程

                引入线程,创建线程池。

                将生成光环点、点的偏移放入线程中,提高运行速度

        2.优化计算逻辑

                提前生成随机数,减少在循环中不断生成。

# 计算每一帧的点的方法
    def calc(self, generate_frame):
        # 根据动画帧数计算比例和光环半径
        ratio = 10 * curve(generate_frame / 10 * pi)
        halo_radius = int(4 + 6 * (1 + curve(generate_frame / 10 * pi)))
        halo_number = int(3000 + 4000 * abs(curve(generate_frame / 10 * pi) ** 2))
        all_points = []
        points_to_add = []

        # 预生成随机偏移量和点的大小
        random_offsets = [(random.randint(-14, 14), random.randint(-14, 14)) for _ in range(halo_number)]
        random_sizes = [random.randint(0, 2) for _ in range(halo_number)]

        # 使用线程池并行生成光环点
        def generate_halo_points(halo_number, random_offsets, ratio, halo_radius, all_points):
            heart_halo_point = set()    # 生成光环点的集合
            for i in range(halo_number):
                t = random.uniform(0, 2 * pi)
                x, y = heart_function(t, shrink_ratio=11.6)
                x, y = shrink(x, y, halo_radius)

                if (x, y) not in heart_halo_point:
                    heart_halo_point.add((x, y))
                    x_offset, y_offset = random_offsets[i]
                    x += x_offset
                    y += y_offset
                    size = random_sizes[i]
                    all_points.append((x, y, size))

            # 生成轮廓、边缘扩散点和中心扩散点
            for x, y in self._points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            for x, y in self._edge_diffusion_points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            for x, y in self._center_diffusion_points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            # 将生成的点添加到 all_points
            all_points.extend(points_to_add)
            self.all_points[generate_frame] = all_points

        # 创建线程池
        with ThreadPoolExecutor(max_workers=1) as executor:
            # 提交光环点生成任务
            executor.submit(generate_halo_points, halo_number, random_offsets, ratio, halo_radius, all_points)
        3.提取变量

                将用户可能需要改动的视觉效果提取出来:字体颜色,文本,刷新帧数(结果测试这个帧数变化效果不大)

HEART_COLOR = "#FF99CC"     # 设置爱心的颜色
TXT_DATE = "I Love You"     # 设置文本内容
TXT_COLOR = "#FF99CC"       # 设置字体颜色
Frames_Number = 20          # 动画刷新的帧数
        4.注释

                更详细的代码注释,方便更多的朋友学习研究使用

完整代码

import random
from math import sin, cos, pi, log
from tkinter import *
from concurrent.futures import ThreadPoolExecutor

CANVAS_WIDTH = 640      # 画布宽度
CANVAS_HEIGHT = 480     # 画布高度
CANVAS_CENTER_X = CANVAS_WIDTH / 2      # 画布中心的x坐标
CANVAS_CENTER_Y = CANVAS_HEIGHT / 2     # 画布中心的y坐标
IMAGE_ENLARGE = 11      # 图像放大的比例

HEART_COLOR = "#FF99CC"     # 设置爱心的颜色
TXT_DATE = "I Love You"     # 设置文本内容
TXT_COLOR = "#FF99CC"       # 设置字体颜色
Frames_Number = 60          # 动画刷新的帧数

# 窗口居中显示的辅助函数
def center_window(root, width, height):
    screenwidth = root.winfo_screenwidth()      # 获取显示屏宽度
    screenheight = root.winfo_screenheight()    # 获取显示屏高度
    size = '%dx%d+%d+%d' % (width, height, 
                            (screenwidth - width) /2, 
                            (screenheight - height) / 2)  # 设置窗口居中参数
    root.geometry(size)                         # 让窗口居中显示

# 定义计算爱心形状的函数
def heart_function(t, shrink_ratio: float = IMAGE_ENLARGE):
    # 使用参数t计算爱心形状的x和y坐标,并根据缩放比例进行缩放
    x = 16 * (sin(t) ** 3)
    y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))

    # 根据缩放比例进行缩放
    x *= shrink_ratio
    y *= shrink_ratio

    # 将计算出的坐标移动到画布中央
    x += CANVAS_CENTER_X
    y += CANVAS_CENTER_Y

    # 返回整型的坐标值
    return int(x), int(y)

# 在爱心内部根据beta值生成随机点
def scatter_inside(x, y, beta=0.15):
    # 根据beta值计算随机偏移量
    ratio_x = - beta * log(random.random())
    ratio_y = - beta * log(random.random())
    # 计算并返回偏移后的坐标
    dx = ratio_x * (x - CANVAS_CENTER_X)
    dy = ratio_y * (y - CANVAS_CENTER_Y)
    return x - dx, y - dy

# 定义缩小点的函数
def shrink(x, y, ratio):
    # 计算力量
    force = -1 / (((x - CANVAS_CENTER_X) ** 2 +(y - CANVAS_CENTER_Y) ** 2) ** 0.6)
    # 计算并返回缩小后的坐标
    dx = ratio * force * (x - CANVAS_CENTER_X)
    dy = ratio * force * (y - CANVAS_CENTER_Y)
    return x - dx, y - dy

# 定义曲线函数
def curve(p):
    return 2 * (2 * sin(4 * p)) / (2 * pi)  # 根据参数p计算并返回曲线值

# 定义Heart类,用于生成和渲染爱心形状
class Heart:
    def __init__(self, generate_frame=Frames_Number):       # 初始化方法,生成爱心形状的点集合
        self._points = set()                                # 原始爱心坐标集合
        self._edge_diffusion_points = set()                 # 边缘扩散效果点坐标集合
        self._center_diffusion_points = set()               # 中心扩散效果点坐标集合
        self.all_points = {}                                # 每帧动态点坐标
        self.build(2000)                                    # 构建爱心形状的点集合
        self.random_halo = 500                              # 初始化光环点的数量
        self.generate_frame = generate_frame                # 动画帧数

        for frame in range(generate_frame):                 # 循环计算每一帧的点
            self.calc(frame)

    def build(self, number):                                # 构建爱心形状的点集合的方法
        # 使用heart_function函数生成number个点,构成原始爱心形状
        self._points = {heart_function(random.uniform(0, 2 * pi)) for _ in range(number)}

        # 爱心内扩散,生成边缘扩散效果点坐标集合
        edge_diffusion_points = set()
        for _x, _y in self._points:
            for _ in range(3):
                x, y = scatter_inside(_x, _y, 0.05)
                edge_diffusion_points.add((x, y))
        self._edge_diffusion_points = edge_diffusion_points

        # 爱心内再次扩散,生成中心扩散效果点坐标集合
        center_diffusion_points = set()
        point_list = list(self._points)
        for _ in range(4000):
            x, y = random.choice(point_list)
            x, y = scatter_inside(x, y, 0.17)
            center_diffusion_points.add((x, y))
        self._center_diffusion_points = center_diffusion_points

    # 计算点位置的静态方法
    @staticmethod
    def calc_position(x, y, ratio):
        # 计算力量
        force = 1 / (((x - CANVAS_CENTER_X) ** 2 +(y - CANVAS_CENTER_Y) ** 2) ** 0.520)
        # 计算并返回偏移后的坐标
        dx = ratio * force * (x - CANVAS_CENTER_X) + random.randint(-1, 1)
        dy = ratio * force * (y - CANVAS_CENTER_Y) + random.randint(-1, 1)
        return x - dx, y - dy
    
    # 计算每一帧的点的方法
    def calc(self, generate_frame):
        # 根据动画帧数计算比例和光环半径
        ratio = 10 * curve(generate_frame / 10 * pi)
        halo_radius = int(4 + 6 * (1 + curve(generate_frame / 10 * pi)))
        halo_number = int(3000 + 4000 * abs(curve(generate_frame / 10 * pi) ** 2))
        all_points = []
        points_to_add = []

        # 预生成随机偏移量和点的大小
        random_offsets = [(random.randint(-14, 14), random.randint(-14, 14)) for _ in range(halo_number)]
        random_sizes = [random.randint(0, 2) for _ in range(halo_number)]

        # 使用线程池并行生成光环点
        def generate_halo_points(halo_number, random_offsets, ratio, halo_radius, all_points):
            heart_halo_point = set()    # 生成光环点的集合
            for i in range(halo_number):
                t = random.uniform(0, 2 * pi)
                x, y = heart_function(t, shrink_ratio=11.6)
                x, y = shrink(x, y, halo_radius)

                if (x, y) not in heart_halo_point:
                    heart_halo_point.add((x, y))
                    x_offset, y_offset = random_offsets[i]
                    x += x_offset
                    y += y_offset
                    size = random_sizes[i]
                    all_points.append((x, y, size))

            # 生成轮廓、边缘扩散点和中心扩散点
            for x, y in self._points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            for x, y in self._edge_diffusion_points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            for x, y in self._center_diffusion_points:
                x, y = self.calc_position(x, y, ratio)
                size = random.randint(0, 2)
                points_to_add.append((x, y, size))

            # 将生成的点添加到 all_points
            all_points.extend(points_to_add)
            self.all_points[generate_frame] = all_points

        # 创建线程池
        with ThreadPoolExecutor(max_workers=1) as executor:
            # 提交光环点生成任务
            executor.submit(generate_halo_points, halo_number, random_offsets, ratio, halo_radius, all_points)

    # 在指定的画布上渲染爱心形状
    def render(self, render_canvas, render_frame):
        frame_key = render_frame % self.generate_frame
        if frame_key in self.all_points:
            points = self.all_points[frame_key]
        else:
            points = []
        for x, y, size in points:
            render_canvas.create_rectangle(
                x, y, x + size, y + size, width=0, fill=HEART_COLOR)

# 定义绘制爱心并实现动画效果的函数
def draw(main: Tk, render_canvas: Canvas, render_heart: Heart, render_frame=0):
    render_canvas.delete('all')     # 清除画布上的所有内容,并重新渲染爱心形状
    render_heart.render(render_canvas, render_frame)
    main.after(160, draw, main, render_canvas, render_heart, render_frame + 1)  # 递归调用draw函数以实现动画效果

if __name__ == '__main__':
    root = Tk()
    root.title("爱心")
    root.resizable(0, 0)        # 锁定界面大小
    center_window(root, CANVAS_WIDTH, CANVAS_HEIGHT)  # 窗口居中显示

    canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)     # 创建画布并添加到窗口
    canvas.pack()

    heart = Heart()                 # 创建爱心对象并开始绘制
    draw(root, canvas, heart)       # 调用draw函数开始动画

    # 在画布中心显示文本
    Label(root, 
          text=TXT_DATE, 
          bg="black", 
          fg=TXT_COLOR, 
          font="Helvetic 20 bold").place(relx=.5, rely=.5, anchor=CENTER)
    
    root.mainloop()         # 启动Tkinter事件循环

性能分析

貌似刚刚启动的时候,运行内测会比较高,后面则稳定在40-60MB(可能会因为电脑性能不一致)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/541111.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣 |142. 环形链表 II

用快慢指针的方法 根据推出的表达式:slow和fast相遇的时候,让slow和位于头节点的p同时 向前走,刚好在入环的节点处相遇!注意:b和c交界的点不一定是从例如-4这个节点处, 可能是0节点处。因为相遇的点只能是…

【软件设计师】计算机软考下午题试题六,Java设计模式之简单工厂模式。

【软件设计师】计算机软考下午题试题六,Java设计模式之简单工厂模式。 代码如下: //简单工厂模式 public class SimpleFactory {public static void main(String[] args) {Product ProductAFactory.createProduct("A");ProductA.info();Produc…

C++---vector容器

是STL容器中的一种常用的容器,由于其大小(size)可变,常用于数组大小不可知的情况下来替代数组。vector容器与数组十分相似,被称为动态数组。时间复杂度为O(1)。 数组数据通常存储在栈中,vector数据通常存储…

个人简历主页搭建系列-06:jqcv 简历主题安装

jqcv 介绍 大家好呀,前段时间我在忙毕设的事情,这段时间继续写这个专题。 我们之前网站已经成功搭建起来了对吧,但是这个样式明显和我们的简历需求不符合,难道我们要自己配置 css 文件一点点进行修改吗? 其实并不用…

4月全新热文高科技,套用模板一键生成热文,没脑子拷贝,第二天出盈利

撰写热门文章,如今日头条或微信公众号文章,通常需要多长时间呢?从构思主题、搜集资料,到撰写成文,整个过程至少需要1小时,有时甚至可能需要2小时。 项目 地 址:laoa1.cn/1627.html 现在&…

css animation 动画详细学习

学习 CSS 动画是一个深入且富有创造性的过程,它允许开发者创建出引人入胜且交互性强的网页效果。以下是对 CSS 动画学习的一些总结和要点: 1. 关键帧动画(keyframes) 使用 keyframes 规则定义动画的整个过程。在 keyframes 中&a…

【PyQt5】环境配置

PyQt5 环境配置 一、前言1.1 PyQt5介绍1.2 PyCharm集成Pyqt5 二、pyqt5安装三、PyQt5-tools工具包安装四、常用工具环境配置4.1、环境变量配置4。2、验证是否安装成功 五、pycharm中设置Qt工具(Qt Designer、PyUIC、PyRcc)5.1、配置Qt Designer5.2、配置…

【计算机毕业设计】日用百货交易网站——后附源码

🎉**欢迎来到我的技术世界!**🎉 📘 博主小档案: 一名来自世界500强的资深程序媛,毕业于国内知名985高校。 🔧 技术专长: 在深度学习任务中展现出卓越的能力,包括但不限于…

QT天气预报

QT-天气预报 1.界面设计 2.开发  2.1 重写鼠标右键退出功能  2.2 重写鼠标左键移动窗口  2.3 QtHttp编程获取天气原始数据    2.3.1 发送HTTP请求    2.3.2 读取数据    2.3.3 处理网络失败请求 2.4 JSON数据    2.4.1 QT生成JSON数据    2.4.2 QT解…

[lesson22]对象的销毁

对象的销毁 对象的销毁 生活中的对象都是被初始化后才上市的 生活中的对象被销毁前会做一些清理工作 一般而言,需要销毁的对象都应该做清理 解决方案 为每个类都提供一个public的free函数对象不在需要时立即调用free函数进行清理 存在的问题 free只是一个普通…

wife_wife-攻防世界

题目 注册发现可以注册管理员,但是好像有条件 抓包试试 没思路了 看看其他师傅的wp,用到 js 原型链污染攻击 Nodejs原型链污染攻击基础知识 | Savants Blog (lxscloud.top) 网站后端是Node.js搭建的 原型链污染 简单来讲,通过 newUser.__proto__ …

使用 HBuilderX自动上传Uniapp 微信小程序代码

HBuilderX内置相关环境,开箱即用,无需配置nodejs。本文只介绍发布微信小程序的步骤。 1.下载和安装 HBuilderX hbuilder首页:https://www.dcloud.io/hbuilderx.html 下载hbuilder编辑器,选择对应的系统,Windows和mac正式版即可,下载后免安…

mysql8.0高可用集群架构实战

MySQL :: MySQL Shell 8.0 :: 7 MySQL InnoDB Cluster 基本概述 InnoDB Cluster是MySQL官方实现高可用读写分离的架构方案,其中包含以下组件 MySQL Group Replication,简称MGR,是MySQL的主从同步高可用方案,包括数据同步及角色选举Mysql Shell 是InnoDB Cluster的管理工具,用…

基于SpringBoot+Vue的健身器材用品网站(源码+文档+部署+讲解)

一.系统概述 随着我国经济的高速发展与人们生活水平的日益提高,人们对生活质量的追求也多种多样。尤其在人们生活节奏不断加快的当下,人们更趋向于足不出户解决各种问题,必录德健身器材用品网展现了其蓬勃生命力和广阔的前景。与此同时&#…

AugmentedReality之路-平面检测(5)

本文介绍通过AR检测水平平面和垂直平面,并将检测到的平面转化为Mesh 1、在首页添加功能入口 在首页添加一个按钮,命名为Start World Track 2、自定义ExecStartAREvent 创建ARSessionConfig并取名为ARSessionConfig_World 自定义ExecStartAREvent&…

2024年你应该防范的11个WordPress安全漏洞问题:由资深程序员撰写

微软创始人比尔盖茨曾说过,“安全对每个人都有同样的影响。在网站安全方面,没有特定的主题、目标或受众。” 但WordPress是互联网上最受欢迎的CMS。它也是被黑客攻击次数最多的。针对WordPress的攻击次数超过了每秒2800次。网络攻击会浪费时间、精力和金…

camera驱动学习总结记录

https://www.yuque.com/u2132176/yfiyal/ch1zsrgzevcwf1rw 视频教程里面对应的gc2053c驱动源码注解: gc2053.c(60 KB) 对应的驱动文档: Rockchip_Driver_Guide_VI_CN_v1.1.1(2).pdf(2.3 MB) 视频里面对应的mipi协议文档汇总: MIPI标准文档大…

MoCo v1(CVPR 2020)原理与代码解读

paper:Momentum Contrast for Unsupervised Visual Representation Learning official implementation:https://github.com/facebookresearch/moco 背景 最近的一些研究提出使用对比损失相关的方法进行无监督视觉表征学习并取得了不错的结果。尽管是受…

springcloud第4季 springcloud-alibaba之nacos篇

一 nacos 1.1 nacos作用介绍 nacos是一个分布式的配置中心和注册发现中心。 nacos是 dynamic naming configuration service nacosconfigbus 实现动态刷新;nacosconsul 1.2 各个注册中心对比 注册中心CAP模型控制台管理社区活跃度EureakaAp支持低zkcp不支持中…

leetcode73 矩阵置零

题目描述 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用原地算法。 输入:matrix [[1,1,1],[1,0,1],[1,1,1]] 输出:[[1,0,1],[0,0,0],[1,0,1]] 输入:matrix [[0,1,2,0],[3,4…