Python 分形算法代码详解

目录
  • 1. 前言
    • 什么是分形算法?
  • 2. 分形算法
    • 2.1 科赫雪花
    • 2.2 康托三分集
    • 2.3 谢尔宾斯基三角形
    • 2.4 分形树
  • 3. 总结

1. 前言

分形几何是几何数学中的一个分支,也称大自然几何学,由著名数学家本华曼德勃罗( 法语:BenoitB.Mandelbrot)在 1975 年构思和发展出来的一种新的几何学。

分形几何是对大自然中微观与宏观和谐统一之美的发现,分形几何最大的特点:

  • 整体与局部的相似性: 一个完整的图形是由诸多相似的微图形组成,而整体图形又是微图形的放大。

局部是整体的缩影,整体是局部的放大。

  • 具有自我叠加性: 整体图形是由微图形不断重复叠加构成,且具有无限叠加能力。

什么是分形算法?

所谓分形算法就是使用计算机程序模拟出大自然界的分形几何图案,是分形几何数学与计算机科学相融合的艺术。

由于分形图形相似性的特点,分形算法多采用递归实现。

2. 分形算法

2.1 科赫雪花

科赫雪花是由瑞典数学家科赫在 1904 年提出的一种不规则几何图形,也称为雪花曲线。

分形图形的特点是整体几何图形是由一个微图形结构自我复制、反复叠加形成,且最终形成的整体图案和微图形结构一样。在编写分形算法时,需要先理解微图案的生成过程。

科赫雪花的微图案生成过程:

  • 先画一条直线。科赫雪花本质就由一条直线演化而成。
  • 三等分画好的直线。
  • 取中间线段,然后用夹角为 60° 的两条等长线段替代。
  • 可在每一条线段上都采用如上方式进行迭代操作,便会构造出多层次的科赫雪花。

科赫微图形算法实现:

使用 Python 自带小海龟模块绘制,科赫雪花递归算法的出口的是画直线。

import turtle
'''
size:直线的长度
level: 科赫雪花的层次
'''
def koch(size, level):
    if n == 1:
        turtle.fd(size)
    else:
        for i in [0, 60, -120, 60]:
            turtle.left(i)
            # 旋转后,再绘制
            koch(size // 3, level - 1)

参数说明:

  • size: 要绘制的直线长度。
  • level: 科赫雪花的层次。

0 阶和 1 阶 科赫雪花递归流程:

import turtle
turtle.speed(100)
def ke_line(line_, n):
    if n == 0:
        turtle.fd(line_)
    else:
        line_len = line_ // 3
        for i in [0, 60, -120, 60]:
            turtle.left(i)
            ke_line(line_len, n - 1)
# 原始直线长度
line = 300
# 移动小海龟到画布左下角
turtle.penup()
turtle.goto(-150, -150)
turtle.pendown()
# 1 阶科赫雪花
di_gui_deep = 1
ke_line(line, di_gui_deep)
turtle.done()

2 阶科赫雪花:

可以多画几个科赫雪花,布满整个圆周。

import turtle
turtle.speed(100)
def ke_line(line_, n):
    if n == 0:
        turtle.fd(line_)
    else:
        line_len = line_ // 3
        for i in [0, 60, -120, 60]:
            turtle.left(i)
            ke_line(line_len, n - 1)
# 原始线长度
line = 300
# 移动小海龟画布左下角
turtle.penup()
turtle.goto(-150, -150)
turtle.pendown()
# 几阶科赫雪花
di_gui_deep = int(input("请输入科赫雪花的阶数:"))
while True:
    # 当多少科赫雪花围绕成一个圆周时,就构成一个完整的雪花造型
    count = int(input("需要几个科赫雪花:"))
    if 360 % count != 0:
        print("请输入 360 的倍数")
    else:
        break
for i in range(count):
    ke_line(line, di_gui_deep)
    turtle.left(360 // count)
turtle.done()

4 个 3 阶科赫雪花: 每画完一个后旋转 90 度,然后再绘制另一个。

6 个 3 阶科赫雪花: 每画完一个后,旋转 60 度再画另一个。

科赫雪花的绘制并不难,本质就是画直线、旋转、再画直线……

2.2 康托三分集

由德国数学家格奥尔格·康托尔在1883年引入,是位于一条线段上的一些点的集合。最常见的构造是康托尔三分点集,由去掉一条线段的中间三分之一得出。

构造过程:

  • 绘制一条给定长度的直线段,将它三等分,去掉中间一段,留下两段。
  • 再将剩下的两段再分别三等分,同样各去掉中间一段,剩下更短的四段……
  • 将这样的操作一直继续下去,直至无穷,由于在不断分割舍弃过程中,所形成的线段数目越来越多,长度越来越小,在极限的情况下,得到一个离散的点集,称为康托尔点集。

编码实现: 使用递归实现。

import turtle
''''
(sx,sy)线段的开始位置
(ex,ey)线段的结束位置
'''
turtle.speed(100)
turtle.pensize(2)
def draw_kt(sx, sy, ex, ey):
    turtle.penup()
    # 小海龟移动开始位置
    turtle.goto(sx, sy)
    turtle.pendown()
    # # 小海龟移动结束位置
    turtle.goto(ex, ey)
    # 起始点与结束点之间的距离
    length = ex - sx
    # 如果直线长线大于 5 则继续画下去
    if length > 5:
        # 左边线段的开始 x 坐标
        left_sx = sx
        # y 坐标向下移动 30
        left_sy = sy - 50
        # 左边线段的结束坐标
        left_ex = sx + length / 3
        left_ey = left_sy
        # 右边线段的开始坐标
        right_sx = ex - length / 3
        right_sy = ey - 50
        # 右边线段的结束坐标
        right_ex = ex
        right_ey = right_sy
        draw_kt(left_sx, left_sy, left_ex, left_ey)
        draw_kt(right_sx, right_sy, right_ex, right_ey)
draw_kt(-300, 200, 300, 200)
turtle.done()

康托三分集的递归算法很直观。

2.3 谢尔宾斯基三角形

谢尔宾斯基三角形(英语:Sierpinski triangle)由波兰数学家谢尔宾斯基在1915年提出。

构造过程:

  • 取一个实心的三角形(最好是等边三角形)。
  • 沿三边中点的连线,将它分成四个小三角形。
  • 去掉中间的那一个小三角形。
  • 对其余三个小三角形重复上述过程直到条件不成立。

编码实现: 谢尔宾斯基三角形就是不停的画三角形,在编码之前约定三角形点之间的关系以及绘制方向如下图所示。

import turtle
import math
turtle.speed(100)
'''
 通过连接 3 个点的方式绘制三角形
 pos是元组的元组((x1,y1),(x2,y2),(x3,y3))
def draw_triangle(pos):
    turtle.penup()
    # 移到第一个点
    turtle.goto(pos[0])
    turtle.pendown()
    # 连接 3 个点
    for i in [1, 2, 0]:
        turtle.goto(pos[i])

# 计算三角形任意两边的中点坐标
def get_mid(p1, p2):
    return (p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2
绘制 谢尔宾斯基三角形
def sierpinski_triangle(*pos):
    # 用给定的点绘制三角形
    draw_triangle(pos)
    p1, p2, p3 = pos
    # 计算三角形的边长
    side = math.fabs((p3[0] - p1[0]) / 2)
    # 如果边长满足条件,继续绘制其它三角形
    if side > 10:
        # p1和p2线段 的中心点
        p1_p2_center_x, p1_p2_center_y = get_mid(p1, p2)
        # p2和p3线段 的中心点
        p2_p3_center_x, p2_p3_center_y = get_mid(p2, p3)
        # p1和p3线段 的中心点
        p1_p3_center_x, p1_p3_center_y = get_mid(p1, p3)
        # 绘制左下角三角形
        sierpinski_triangle(p1, (p1_p2_center_x, p1_p2_center_y), (p1_p3_center_x, p1_p3_center_y))
        # 绘制上边三角形
        sierpinski_triangle((p1_p2_center_x, p1_p2_center_y), p2, (p2_p3_center_x, p2_p3_center_y))
        # 绘制右下角三角形
        sierpinski_triangle((p1_p3_center_x, p1_p3_center_y), (p2_p3_center_x, p2_p3_center_y), p3)
# 第一个点指左边点,第二点指上面的点,第三个指右边的点。
sierpinski_triangle((-200, -100), (0, 200), (200, -100))
turtle.done()

代码执行之后的结果:

用随机的方法(Chaos Game),绘制谢尔宾斯基三角形:

构造过程:

任意取平面上三点 A,B,C,组成一个三角形。

在三角形 ABC 内任意取一点 P,并画出该点。

找出 P 和三角形其中一个顶点的中点,并画出来。

把刚才找出来的中心点和三角形的任一顶点相连接,同样取其中点,并画出来。

重复上述流程,不停的获取中心点。

注意,是画点,上面的线段是为了直观理解中心点位置。

编码实现:

import turtle
import random
turtle.speed(100)
turtle.bgcolor('black')
colors = ['red', 'green', 'blue', 'orange', 'yellow']
# 画等边三角形
def draw_triangle(pos):
    turtle.penup()
    turtle.goto(pos[0])
    turtle.pendown()
    for i in [1, 2, 0]:
        turtle.goto(pos[i])

def sierpinski_triangle(*pos):
    # 画三角形
    draw_triangle(pos)
    p1, p2, p3 = pos
    # 在三角形中任取一点
    ran_x, ran_y = (p1[0] + p3[0]) / 2, (p2[1] + p3[1]) / 2
    for i in range(10000):
        # 画点
        turtle.penup()
        turtle.goto(ran_x, ran_y)
        turtle.pendown()
        turtle.dot(3, colors[i % 5])
        # 随机选择 3 个顶点的一个顶点
        ran_i = random.randint(0, 2)
        ding_p = pos[ran_i]
        # 计算任意点和顶点的中心点
        ran_x, ran_y = (ran_x + ding_p[0]) / 2, (ran_y + ding_p[1]) / 2
sierpinski_triangle((-200, -100), (0, 200), (200, -100))
turtle.done()

随机法是一个神奇的存在,当点数量很少时,看不出到底在画什么。当点的数量增加后,如成千上万后,会看到谢尔宾斯基三角形跃然于画布上,不得不佩服数学家们天才般的大脑。

下图是点数量为 10000 时的谢尔宾斯基三角形,是不是很震撼。

2.4 分形树

绘制分形树对于递归调用过程的理解有很大的帮助,其实前面所聊到的递归算法都是树形递进。分形树能很形象的描述树形递归的过程。

分形树的算法实现:

import turtle
def draw_tree(size):
    if size >= 20:
        turtle.forward(size) # 1
        # 画右边树
        turtle.right(20)
        draw_tree(size - 40) # 2
        # 画左边树
        turtle.left(40)
        draw_tree(size - 40)
        # 后退
        turtle.right(20)
        turtle.backward(size)
turtle.left(90)
draw_tree(80)
turtle.done()

为了理解分形树的递归过程,如上代码可以先仅画一个树干两个树丫。

下面以图示方式显示左右两边的树丫绘制过程。

3. 总结

分形几何是大自然对数学的馈赠,当然这离不开数学家们的发现与研究,通过计算机科学对分形几何的模拟,可以以可视化的方式更直观地研究分形几何学。这也是计算机科学对于各学科的巨大贡献。

到此这篇关于Python 分形算法代码详解的文章就介绍到这了,更多相关Python 分形算法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 基于Python实现Hash算法

    目录 1 前言 2 一般hash算法 2.1 算法逻辑 2.2 代码实现 2.3 总结 3 一致性hash算法 3.1 算法逻辑 3.2 代码实现 3.3 总结 1 前言 Simhash的算法简单的来说就是,从海量文本中快速搜索和已知simhash相差小于k位的simhash集合,这里每个文本都可以用一个simhash值来代表,一个simhash有64bit,相似的文本,64bit也相似,论文中k的经验值为3.该方法的缺点如优点一样明显,主要有两点,对于短文本,k值很敏感:另一个是由于算法是以空

  • Python&Matlab实现灰狼优化算法的示例代码

    目录 1 灰狼优化算法基本思想 2 灰狼捕食猎物过程 2.1 社会等级分层 2.2 包围猎物 2.3 狩猎 2.4 攻击猎物 2.5 寻找猎物 3 实现步骤及程序框图 3.1 步骤 3.2 程序框图 4 Python代码实现 5 Matlab实现 1 灰狼优化算法基本思想 灰狼优化算法是一种群智能优化算法,它的独特之处在于一小部分拥有绝对话语权的灰狼带领一群灰狼向猎物前进.在了解灰狼优化算法的特点之前,我们有必要了解灰狼群中的等级制度. 灰狼群一般分为4个等级:处于第一等级的灰狼用α表示,处于第

  • Python实现孤立随机森林算法的示例代码

    目录 1 简介 2 孤立随机森林算法 2.1 算法概述 2.2 原理介绍 2.3 算法步骤 3 参数讲解 4 Python代码实现 5 结果 1 简介 孤立森林(isolation Forest)是一种高效的异常检测算法,它和随机森林类似,但每次选择划分属性和划分点(值)时都是随机的,而不是根据信息增益或基尼指数来选择. 2 孤立随机森林算法 2.1 算法概述 Isolation,意为孤立/隔离,是名词,其动词为isolate,forest是森林,合起来就是“孤立森林”了,也有叫“独异森林”,好

  • Python学习Turtle库画对称勾股树体会分形惊艳

    分形,具有以非整数维形式充填空间的形态特征.通常被定义为"一个粗糙或零碎的几何形状,可以分成数个部分,且每一部分都(至少近似地)是整体缩小后的形状",即具有自相似的性质.分形(Fractal)一词,是芒德勃罗创造出来的,其原意具有不规则.支离破碎等意义.1973年,芒德勃罗(B.B.Mandelbrot)在法兰西学院讲课时,首次提出了分维和分形的设想. 分形是一个数学术语,也是一套以分形特征为研究主题的数学理论.分形理论既是非线性科学的前沿和重要分支,又是一门新兴的横断学科,是研究一类

  • Python 分形算法代码详解

    目录 1. 前言 什么是分形算法? 2. 分形算法 2.1 科赫雪花 2.2 康托三分集 2.3 谢尔宾斯基三角形 2.4 分形树 3. 总结 1. 前言 分形几何是几何数学中的一个分支,也称大自然几何学,由著名数学家本华曼德勃罗( 法语:BenoitB.Mandelbrot)在 1975 年构思和发展出来的一种新的几何学. 分形几何是对大自然中微观与宏观和谐统一之美的发现,分形几何最大的特点: 整体与局部的相似性: 一个完整的图形是由诸多相似的微图形组成,而整体图形又是微图形的放大. 局部是整

  • Python实现调度算法代码详解

    调度算法 操作系统管理了系统的有限资源,当有多个进程(或多个进程发出的请求)要使用这些资源时,因为资源的有限性,必须按照一定的原则选择进程(请求)来占用资源.这就是调度.目的是控制资源使用者的数量,选取资源使用者许可占用资源或占用资源. 在操作系统中调度是指一种资源分配,因而调度算法是指:根据系统的资源分配策略所规定的资源分配算法.对于不同的的系统和系统目标,通常采用不同的调度算法,例如,在批处理系统中,为了照顾为数众多的段作业,应采用短作业优先的调度算法:又如在分时系统中,为了保证系统具有合理

  • python动态规划算法实例详解

    如果大家对这个生僻的术语不理解的话,那就先听小编给大家说个现实生活中的实际案例吧,虽然现在手机是相当的便捷,还可以付款,但是最初的时候,我们经常会使用硬币,其中,我们如果遇到手中有很多五毛或者1块钱硬币,要怎么凑出来5元钱呢?这么一个过程也可以称之为动态规划算法,下面就来看下详细内容吧. 从斐波那契数列看动态规划 斐波那契数列:Fn = Fn-1 + Fn-2 ( n = 1,2 fib(1) = fib(2) = 1) 练习:使用递归和非递归的方法来求解斐波那契数列的第 n 项 代码如下: #

  • python 图像增强算法实现详解

    使用python编写了共六种图像增强算法: 1)基于直方图均衡化 2)基于拉普拉斯算子 3)基于对数变换 4)基于伽马变换 5)限制对比度自适应直方图均衡化:CLAHE 6)retinex-SSR 7)retinex-MSR其中,6和7属于同一种下的变化. 将每种方法编写成一个函数,封装,可以直接在主函数中调用. 采用同一幅图进行效果对比. 图像增强的效果为: 直方图均衡化:对比度较低的图像适合使用直方图均衡化方法来增强图像细节 拉普拉斯算子可以增强局部的图像对比度 log对数变换对于整体对比度

  • Java版超大整数阶乘算法代码详解-10,0000级

    当计算超过20以上的阶乘时,阶乘的结果值往往会很大.一个很小的数字的阶乘结果就可能超过目前个人计算机的整数范围.如果需求很大的阶乘,比如1000以上完全无法用简单的递归方式去解决.在网上我看到很多用C.C++和C#写的一些关于大整数阶乘的算法,其中不乏经典但也有很多粗糙的文章.数组越界,一眼就可以看出程序本身无法运行.转载他人文章的时候,代码倒是仔细看看啊.唉,粗糙.过年了,在家闲来蛋疼,仔细分析分析,用Java实现了一个程序计算超大整数阶乘.思想取自网上,由我个人优化和改进. 这个方法采用"数

  • Python模块文件结构代码详解

    本文研究的主要是Python模块文件结构的相关内容,具体如下. Python文件结构 文件结构(范例全文) #/usr/bin/env python "this is a test module" import sys import os debug = True class FooClass (object): "Foo class" pass def test(): "test function" foo = FooClass() if de

  • C语言冒泡排序算法代码详解

    今天我们来用C语言实现一下冒泡排序 首先我们来了解一下什么叫做冒泡排序,冒泡顾名思义把质量轻的气体(如二氧化碳一样)浮到水面上(如可乐中的二氧化碳),因此冒泡排序的原理就是N个元素在一个周期中,微观上依次进行两两元素的比较,小的元素就被放在前面,大的元素放在后面,以此来进行N-1个周期,来完成冒泡排序. 上文中的一个周期,即外循环,依次进行比较,即内循环. 文字看着很迷糊?没事儿,上图 如图所示,两两元素依次进行比较,小的元素往前移动,大的元素往后移动,直至元素顺序是升序的形式,即移动了 元素-

  • 堆排序原理及算法代码详解

    目录 二.二叉树定义 三.堆的定义 四.堆排序Java代码实现 总结 一.堆排序算法原理和动态图解 将待排序的序列构造成一个大顶堆.此时,整个序列的最大值就是堆顶的根节点.将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次最大值.如此反复执行,就能得到一个有序序列了.这个过程其实就是先构建一个最大/最小二叉堆,然后不停的取出最大/最小元素(头结点),插入到新的队列中,以此达到排序的目的.如下图所示: 二.二

  • Python装饰器代码详解

    目录 一.理解装饰器 二.装饰器原型 1.不带参数的装饰器 2.带参数的被装饰的函数 3.带参数的装饰器 4.使用类作为装饰器 5.使用对象作为装饰器 6.多层装饰器的嵌套 总结 一.理解装饰器 所有东西都是对象(函数可以当做对象传递) 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. def function_one(): print("测试函数") #可以将一个函数赋值给一个变量,比如 foo =function_one #这里没有在使用小括号,因

  • Python日志采集代码详解

    目录 一,日志概述 1,日志作用 2,日志级别 3,日志格式 4,日志位置 二,logging模块 1,简介 2,文档 三,logging第一种使用方法:简单配置使用 1,使用方法 2,basicConfig()部分参数说明 3,示例1:日志打印至控制台 4,示例2:日志保存至文件 四,logging的第二种使用方式:日志流处理流程 1,logging四大组件介绍 2,Logger 记录器 3,Handler 处理器 3.1,StreamHandler 3.2,FileHandler 4,Fil

随机推荐