当前位置:首页 > 文章列表 > 文章 > python教程 > 怎么使用Python绘制分形图案

怎么使用Python绘制分形图案

来源:亿速云 2024-04-02 21:27:29 0浏览 收藏

今日不肯埋头,明日何以抬头!每日一句努力自己的话哈哈~哈喽,今天我将给大家带来一篇《怎么使用Python绘制分形图案》,主要内容是讲解等等,感兴趣的朋友可以收藏或者有更好的建议在评论提出,我都会认真看的!大家一起进步,一起学习!

一、目标

写一个可以画等边三角形的程序,并且在三角形的每条边上,它必须能够绘制一个稍微小一点的向外的三角形。能够根据人的意愿多次重复此过程,从而创建一些有趣的模式。

二、表示图像

把图像表示为一个二维的像素阵列。像素阵列中的每个单元格将代表该像素的颜色(RGB)。

为此,可以使用NumPy库生成像素数组,并使用Pillow将其转换为可以保存的图像。

怎么使用Python绘制分形图案

蓝色像素的x值为3,y值为4,可以通过一个二维数组访问,如pixels[4][3]

三、画一条线

现在开始编码,首先,需要一个可以获取两组坐标并在它们之间画一条线的函数。

下面的代码通过在两点之间插值来工作,每一步都向像素阵列添加新的像素。你可以把这个过程看作是在一条线上逐个像素地进行着色。

可以在每个代码片段中使用连续字符“\”来容纳一些较长的代码行。

import numpy as np
from PIL import Image
import math
def plot_line(from_coordinates, to_coordinates, thickness, colour, pixels):
    # 找出像素阵列的边界
    max_x_coordinate = len(pixels[0])
    max_y_coordinate = len(pixels)
    # 两点之间沿着x轴和y轴的距离
    horizontal_distance = to_coordinates[1] - from_coordinates[1]
    vertical_distance = to_coordinates[0] - from_coordinates[0]
    # 两点之间的总距离
    distance =  math.sqrt((to_coordinates[1] - from_coordinates[1])**2 \
                + (to_coordinates[0] - from_coordinates[0])**2)
    # 每次给一个新的像素上色时,将向前走多远
    horizontal_step = horizontal_distance/distance
    vertical_step = vertical_distance/distance
    # 此时,将进入循环以在像素数组中绘制线
    # 循环的每一次迭代都会沿着线添加一个新的点
    for i in range(round(distance)):
        # 这两个坐标是直线中心的坐标
        current_x_coordinate = round(from_coordinates[1] + (horizontal_step*i))
        current_y_coordinate = round(from_coordinates[0] + (vertical_step*i))
        # 一旦得到了点的坐标,
        # 就在坐标周围画出尺寸为thickness的图案
        for x in range (-thickness, thickness):
            for y in range (-thickness, thickness):
                x_value = current_x_coordinate + x
                y_value = current_y_coordinate + y
                if (x_value > 0 and x_value < max_x_coordinate and \
                    y_value > 0 and y_value < max_y_coordinate):
                    pixels[y_value][x_value] = colour
# 定义图像的大小
pixels = np.zeros( (500,500,3), dtype=np.uint8 )
# 画一条线
plot_line([0,0], [499,499], 1, [255,200,0], pixels)
# 把像素阵列变成一张真正的图片
img = Image.fromarray(pixels)
# 显示得到的图片,并保存它
img.show()
img.save('Line.png')

怎么使用Python绘制分形图案

此函数在像素阵列的每个角之间绘制一条黄线时的结果

四、画三角形

现在有了一个可以在两点之间画线的函数,可以画第一个等边三角形了。

给定三角形的中心点和边长,可以使用公式计算出高度:h = ½(√3a)。

现在利用这个高度、中心点和边长,可以计算出三角形的每个角的位置。使用之前制作的plot_line函数,可以在每个角之间画一条线。

def draw_triangle(center, side_length, thickness, colour, pixels):
    # 等边三角形的高度是,h = ½(√3a)
    # 其中a是边长
    triangle_height = round(side_length * math.sqrt(3)/2)
    # 顶角
    top = [center[0] - triangle_height/2, center[1]]
    # 左下角
    bottom_left = [center[0] + triangle_height/2, center[1] - side_length/2]
    # 右下角
    bottom_right = [center[0] + triangle_height/2, center[1] + side_length/2]
    # 在每个角之间画一条线来完成三角形
    plot_line(top, bottom_left, thickness, colour, pixels)
    plot_line(top, bottom_right, thickness, colour, pixels)
    plot_line(bottom_left, bottom_right, thickness, colour, pixels)

怎么使用Python绘制分形图案

在500x500像素PNG的中心绘制三角形时的结果

五、生成分形

一切都已准备就绪,可以用Python创建第一个分形。

但是最后一步是最难完成的,三角形函数为它的每一边调用自己,需要能够计算每个新的较小三角形的中心点,并正确地旋转它们,使它们垂直于它们所附着的一侧。

通过从旋转的坐标中减去中心点的偏移量,然后应用公式来旋转一对坐标,可以用这个函数来旋转三角形的每个角。

def rotate(coordinate, center_point, degrees):
    # 从坐标中减去旋转的点
    x = (coordinate[0] - center_point[0])
    y = (coordinate[1] - center_point[1])
    # Python的cos和sin函数采用弧度而不是度数
    radians = math.radians(degrees)
    # 计算旋转点
    new_x = (x * math.cos(radians)) - (y * math.sin(radians))
    new_y = (y * math.cos(radians)) + (x * math.sin(radians))
    # 将在开始时减去的偏移量加回旋转点上
    return [new_x + center_point[0], new_y + center_point[1]]

怎么使用Python绘制分形图案

将每个坐标旋转35度的三角形

可以旋转一个三角形后,思考如何在第一个三角形的每条边上画一个新的小三角形。

为了实现这一点,扩展draw_triangle函数,为每条边计算一个新三角形的旋转和中心点,其边长被参数shrink_side_by减少。

一旦它计算出新三角形的中心点和旋转,它就会调用draw_triangle(自身)来从当前线的中心画出新的、更小的三角形。然后,这将反过来打击同一个代码块,为一个更小的三角形计算另一组中心点和旋转。

这就是所谓的循环算法,因为draw_triangle函数现在会调用自己,直到达到希望绘制的三角形的最大深度。有这个转义句子是很重要的,因为理论上这个函数会一直循环下去(但实际上调用堆栈会变得太大,导致堆栈溢出错误)。

def draw_triangle(center, side_length, degrees_rotate, thickness, colour, \
                  pixels, shrink_side_by, iteration, max_depth):
    # 等边三角形的高度是,h = ½(√3a)
    # 其中'a'是边长
    triangle_height = side_length * math.sqrt(3)/2
    # 顶角
    top = [center[0] - triangle_height/2, center[1]]
    # 左下角
    bottom_left = [center[0] + triangle_height/2, center[1] - side_length/2]
    # 右下角
    bottom_right = [center[0] + triangle_height/2, center[1] + side_length/2]
    if (degrees_rotate != 0):
        top = rotate(top, center, degrees_rotate)
        bottom_left = rotate(bottom_left, center, degrees_rotate)
        bottom_right = rotate(bottom_right, center, degrees_rotate)
    # 三角形各边之间的坐标
    lines = [[top, bottom_left],[top, bottom_right],[bottom_left, bottom_right]]
    line_number = 0
    # 在每个角之间画一条线来完成三角形
    for line in lines:
        line_number += 1
        plot_line(line[0], line[1], thickness, colour, pixels)
        # 如果还没有达到max_depth,就画一些新的三角形
        if (iteration < max_depth and (iteration < 1 or line_number < 3)):
            gradient = (line[1][0] - line[0][0]) / (line[1][1] - line[0][1])
            new_side_length = side_length*shrink_side_by
            # 正在绘制的三角形线的中心
            center_of_line = [(line[0][0] + line[1][0]) / 2, \
                              (line[0][1] + line[1][1]) / 2]
            new_center = []
            new_rotation = degrees_rotate
            # 需要旋转traingle的数量
            if (line_number == 1):
                new_rotation += 60
            elif (line_number == 2):
                new_rotation -= 60
            else:
                new_rotation += 180
            # 在一个理想的世界里,这将是gradient=0,
            # 但由于浮点除法的原因,无法
            # 确保永远是这种情况
            if (gradient < 0.0001 and gradient > -0.0001):
                if (center_of_line[0] - center[0] > 0):
                    new_center = [center_of_line[0] + triangle_height * \
                                 (shrink_side_by/2), center_of_line[1]]
                else:
                    new_center = [center_of_line[0] - triangle_height * \
                                  (shrink_side_by/2), center_of_line[1]]
            else:
                # 计算直线梯度的法线
                difference_from_center = -1/gradient
                # 计算这条线距中心的距离
                # 到新三角形的中心
                distance_from_center = triangle_height * (shrink_side_by/2)
                # 计算 x 方向的长度,
                # 从线的中心到新三角形的中心
                x_length = math.sqrt((distance_from_center**2)/ \
                                     (1 + difference_from_center**2))
                # 计算出x方向需要走哪条路
                if (center_of_line[1] < center[1] and x_length > 0):
                    x_length *= -1
                # 现在计算Y方向的长度
                y_length = x_length * difference_from_center
                # 用新的x和y值来偏移线的中心
                new_center = [center_of_line[0] + y_length, \
                              center_of_line[1] + x_length]
            draw_triangle(new_center, new_side_length, new_rotation, \
                          thickness, colour, pixels, shrink_side_by, \
                          iteration+1, max_depth)

怎么使用Python绘制分形图案

三角形分形,收缩边=1/2,最大深度=2

到这里,我们也就讲完了《怎么使用Python绘制分形图案》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于Python的知识点!

版本声明
本文转载于:亿速云 如有侵犯,请联系study_golang@163.com删除
从网络 TCP 连接获取 IPv4 地址从网络 TCP 连接获取 IPv4 地址
上一篇
从网络 TCP 连接获取 IPv4 地址
在泛型 go 中模拟方法类型参数
下一篇
在泛型 go 中模拟方法类型参数
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • 互联网信息服务算法备案系统:如何完成算法备案流程
    互联网信息服务算法备案系统
    了解互联网信息服务算法备案系统,掌握如何进行算法备案的详细步骤和要求,确保您的互联网服务合规运营。
    57次使用
  • SEO标题魔匠AI:高质量学术写作平台,毕业论文生成与优化专家
    魔匠AI
    SEO摘要魔匠AI专注于高质量AI学术写作,已稳定运行6年。提供无限改稿、选题优化、大纲生成、多语言支持、真实参考文献、数据图表生成、查重降重等全流程服务,确保论文质量与隐私安全。适用于专科、本科、硕士学生及研究者,满足多语言学术需求。
    103次使用
  • PPTFake答辩PPT生成器:一键生成高效专业的答辩PPT
    PPTFake答辩PPT生成器
    PPTFake答辩PPT生成器,专为答辩准备设计,极致高效生成PPT与自述稿。智能解析内容,提供多样模板,数据可视化,贴心配套服务,灵活自主编辑,降低制作门槛,适用于各类答辩场景。
    135次使用
  • SEO标题Lovart AI:全球首个设计领域AI智能体,实现全链路设计自动化
    Lovart
    SEO摘要探索Lovart AI,这款专注于设计领域的AI智能体,通过多模态模型集成和智能任务拆解,实现全链路设计自动化。无论是品牌全案设计、广告与视频制作,还是文创内容创作,Lovart AI都能满足您的需求,提升设计效率,降低成本。
    256次使用
  • 美图AI抠图:行业领先的智能图像处理技术,3秒出图,精准无误
    美图AI抠图
    美图AI抠图,依托CVPR 2024竞赛亚军技术,提供顶尖的图像处理解决方案。适用于证件照、商品、毛发等多场景,支持批量处理,3秒出图,零PS基础也能轻松操作,满足个人与商业需求。
    124次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码