Python - Order in chaos 混乱中的秩序之随机点中值连线

news2025/6/26 6:54:17

一.引言

刷短视频刷到了一个有趣的图形变化,随机给定 N 个点,将 N 个点首尾连接生成一个多边形,随后将每个边的中点连接并得到新的多边形,如此多次循环,最终总会得到一个椭圆形。

A.初始化 N 个点并生成多边形

 B.取多边形中点依次连接生成新的多边形

 C.持续执行多次

循环多次取中点连线操作 ......

D.最终得到椭圆形

二.Python 实现

1.随机生成N个点并生成多边形

A.获取随机点

# 随机生成(x,y) x,y 为 (0-100) 的整数
def getRandomPoint():
    x = int(random.uniform(0, 100))
    y = int(random.uniform(0, 100))
    return x, y

B.生成多边形

        # pointNum = N 为指定的 N 个点
        for num in range(0, pointNum):
            x, y = getRandomPoint()
            x_arr.append(x)
            y_arr.append(y)
        # 这里尾巴添加首个点,达到首尾相连的目的
        x_arr.append(x_arr[0])
        y_arr.append(y_arr[0])
        plt.plot(x_arr, y_arr)
        plt.show()

随机 50 个点,得到第一幅初始图像: 

2.多次循环最终得到椭圆

这里循环执行取中点并连接生成多边形的操作,由于 plot 会根据坐标自动调整比例,所以我们看到的图像总是一样大,但是仔细观察坐标系,可以发现原始多边形已经在不断变下,如果这些图放到一个比例下,最终得到的椭圆在我们视角里会接近一个点。

        x_arr_new = []
        y_arr_new = []
        lastIndex = len(x_arr) - 1
        for i in range(0, len(x_arr)):
            # 防止数组越界
            if (i != lastIndex):
                x_mid = (x_arr[i] + x_arr[i + 1]) / 2
                y_mid = (y_arr[i] + y_arr[i + 1]) / 2
                x_arr_new.append(x_mid)
                y_arr_new.append(y_mid)
            else:
                x_mid = (x_arr[i] + x_arr[0]) / 2
                y_mid = (y_arr[i] + y_arr[0]) / 2
                x_arr_new.append(x_mid)
                y_arr_new.append(y_mid)
        # 保证收尾连接
        x_arr_new.append(x_arr_new[0])
        y_arr_new.append(y_arr_new[0])
        plt.plot(x_arr_new, y_arr_new)
        plt.show()

上图为原始图形经过2次中点连接后形状的转变,可以看到比例尺也在相应的不断减小,下面用9张图观察图像的变化趋势:

3.将完整流程生成 GIF

为了观察整个流程,我们可以调用 python 库例如 imageio 等将上述生成的图片依次保存并最终生成 gif 图像。

    # 生成图形
    frames = []
    for i in range(0, epoch):
        imageName = target_path + str(i) + ".jpg"
        frames.append(imageio.imread(imageName))

    # 生成 GIF 图形
    duration = 10
    gifPath = target_path + "all.gif"
    imageio.mimsave(gifPath, frames, 'GIF', duration=duration)  # 选择'GIF'类型

 下面展示随机初始化 20 个点并进行 100 次迭代达到的椭圆效果:

 

4.换个参数试试

原文中取均值中点,下面尝试➗3 取 1/3 节点连接会有什么区别:

换成 1/3 后最终得到的椭圆似乎更圆润一些,不过这里只做了有限次随机试验,不能下太肯定的结论,有兴趣的同学也可以自己修改代码中的方法,看看不同情况下的图像情况。 

 

三.混乱中的秩序

随着迭代次数的增多,最终的椭圆基本不会发生太大的变化:

下面尝试简单发现下其中蕴含什么奥秘,假设有 N 个点 {(x1,y1), (x2,y2), ..., (xn,yn)},经过 N 次迭代后,每一个元素的值为 [Tips: 这里仅计算横坐标、纵坐标同理]

\begin{bmatrix} x1 & x2 & x3 & ... \\ \frac{x_1+x_2}{2} & \frac{x_2+x_3}{2} & \frac{x_3+x_4}{2} & ... \\ \frac{x_1+2x_2+x_3}{4} & \frac{x_2+2x_3+x_4}{4} & \frac{x_3+2x_4+x_5}{4} & ... \\ ...& ...& ...& ...\\ \frac{x_1+5x_2+10x_3+10x_4+5x_5+x_6}{32}& \frac{x_2+5x_3+10x_4+10x_5+5x_6+x_7}{32} & .\frac{x_3+5x_4+10x_5+10x_6+5x_7+x_8}{32}&... \\ ...& ... & ... & ... \end{bmatrix}

观察分子的系数,我们可以发现这里系数构成一个杨辉三角:

第一行每一个点的系数为 [1],第二行每一个点的构成元素系数为 [1,2,1],以此类推, [1,3,3,1]、[1,4,6,4,1]、[1,5,10,10,5,1] ... 其中每个点满足,即下面的元素由其上面两个元素的值相加而得:

C(n+1,i) = C(n,1) + C(n,i-1) 

而分母的系数由于是不断的取二均值,所以满足:

\frac{1}{2^n}

关于为什么最终会呈现椭圆形,还需要更加严格的证明,通过上面简单的分析我们可以看到,随着迭代次数的增加,每一个点的值都会用到原始列表中的元素,且系数满足杨辉三角,最终的结果推导应该会满足一定规律,有兴趣的小伙伴可以自己动手推理一下。

四.总结

刷视频刷到了好玩的信息,虽然自己没有证明但是能够实现出来也很不错,java 写久了 python 都快忘的差不多了,实现的比较简易,有更高效的实现方法或者证明方法也欢迎大家多多交流,下面铺一下完整的代码:

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import random
import matplotlib.pyplot as plt
import os
import imageio


def getRandomPoint():
    x = int(random.uniform(0, 100))
    y = int(random.uniform(0, 100))
    return x, y


def plotArr(pointNum=50, x_arr=[], y_arr=[], savePath=""):
    if (len(x_arr) == 0 and len(y_arr) == 0):
        for num in range(0, pointNum):
            x, y = getRandomPoint()
            x_arr.append(x)
            y_arr.append(y)
        x_arr.append(x_arr[0])
        y_arr.append(y_arr[0])
        plt.plot(x_arr, y_arr)
        plt.scatter(x_arr, y_arr, c='r')
        plt.savefig(savePath)
        plt.cla()
        return x_arr[:-1], y_arr[:-1]
    else:
        x_arr_new = []
        y_arr_new = []
        lastIndex = len(x_arr) - 1
        for i in range(0, len(x_arr)):
            if (i != lastIndex):
                x_mid = (x_arr[i] + x_arr[i + 1]) / 2
                y_mid = (y_arr[i] + y_arr[i + 1]) / 2
                x_arr_new.append(x_mid)
                y_arr_new.append(y_mid)
            else:
                x_mid = (x_arr[i] + x_arr[0]) / 2
                y_mid = (y_arr[i] + y_arr[0]) / 2
                x_arr_new.append(x_mid)
                y_arr_new.append(y_mid)
        x_arr_new.append(x_arr_new[0])
        y_arr_new.append(y_arr_new[0])
        plt.plot(x_arr_new, y_arr_new)
        plt.scatter(x_arr_new, y_arr_new, c='r')
        plt.savefig(savePath)
        plt.cla()
        return x_arr_new[:-1], y_arr_new[:-1]


if __name__ == '__main__':

    epoch = 200
    pointNum = 20
    x_init = []
    y_init = []
    target_path = "/Users/xxx/..."
    os.mkdir(target_path)

    # 生成图形
    frames = []
    for i in range(0, epoch):
        imageName = target_path + str(i) + ".jpg"
        x_init, y_init = plotArr(pointNum, x_init, y_init, imageName)
        frames.append(imageio.imread(imageName))

    # 生成 GIF 图形
    duration = 1
    gifPath = target_path + "all.gif"
    imageio.mimsave(gifPath, frames, 'GIF', duration=duration)  # 选择'GIF'类型

epoch 代表迭代次数,pointNum 代表初始化点的数量,运行结束后会在 target_path 下得到每一步的图像以及最终的 GIF 图像,快来试试吧:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Transformer实现以及Pytorch源码解读(四)-Encoder层

Transformer结构图 先放一张原论文中的图。从inputs到Poitional Encoding在前三部分中已经分析清楚,接下来往后分析。 Pytorch中对Transformer的调用 Pytorch将图1中左半部分的神经网络层用一个TransformerEncdoer(encoder_layer,num_layers)类进行封装&#xf…

【Kotlin 协程】Flow 异步流 ⑥ ( 调用 Flow#launchIn 函数指定流收集协程 | 通过取消流收集所在的协程取消流 )

文章目录一、调用 Flow#launchIn 函数指定流收集协程1、指定流收集协程2、Flow#launchIn 函数原型3、代码示例二、通过取消流收集所在的协程取消流一、调用 Flow#launchIn 函数指定流收集协程 1、指定流收集协程 响应式编程 , 是 基于事件驱动 的 , 在 Flow 流中会产生源源不断…

MySQL的数据类型和存储引擎介绍

一. MySQL数据类型 1. 整数类型 注:MySQL可以为整数类型指定宽度,比如 int(3)、int(5),这个限制不是限制value的合法范围,所以对绝大数应用没有任何意义,对于存储而言,int(3) 和 int(5) 是相同的&#xff…

机器学习中的数学原理——随机梯度下降法

这个专栏主要是用来分享一下我在机器学习中的学习笔记及一些感悟,也希望对你的学习有帮助哦!感兴趣的小伙伴欢迎私信或者评论区留言!这一篇就更新一下《白话机器学习中的数学——随机梯度下降法》! 一、什么是随机梯度下降法 随机…

NVM安装

注意事项: 1、不能安装任何node版本(如存在请删除后安装nvm); 安装步骤: 1、下载nvm ![在这里插入图片描述](https://img-blog.csdnimg.cn/c9dcc27383aa41888347080438c0914e.png 解压后点击exe文件进行安装: &#x…

负载均衡简介

一、什么是负载均衡? 互联网早期,业务流量比较小并且业务逻辑比较简单,单台服务器便可以满足基本的需求;但随着互联网的发展,业务流量越来越大并且业务逻辑也越来越复杂,单台机器的性能问题以及单点问题凸显…

SMMP:一种基于稳定成员资格的多峰聚类算法(Matlab代码实现)

👨‍🎓个人主页:研学社的博客 💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜…

伦茨LENZE GDC操作指南

1、GDC软件综述 GDC程序可以“在线模式”和“离线模式”使用: 离线模式 可以在没有与目标系统(控制器)相连接条件下使用。该功能允许离线设定参数、编程等工作。 在线模式 通过PC的串口、并口或系统总线实现GDC与目标系统(控制器…

376. 机器任务——最小点覆盖+匈牙利算法

有两台机器 A,B 以及 K 个任务。 机器 A 有 N 种不同的模式(模式 0∼N−1),机器 B 有 M 种不同的模式(模式 0∼M−1)。 两台机器最开始都处于模式 0。 每个任务既可以在 A 上执行,也可以在 B…

艾美捷游离巯基检测试剂盒基本参数和特点说明

游离硫醇(即蛋白质上的游离半胱氨酸、谷胱甘肽和半胱氨酸残基)的检测和测量是研究许多生物系统中的生物过程和事件的基本任务之一。 艾美捷游离巯基检测试剂盒提供了一种简单、可重复和灵敏的工具,用于测定样品(即血浆、血清、组织…

3D格式转换工具HOOPS Exchange助力3D 打印软件实现质的飞跃

HOOPS SDK是用于3D工业软件开发的工具包,其中包括4款工具,分别是用于读取和写入30多种CAD文件格式的HOOPS Exchange、专注于Web端工程图形渲染的HOOPS Communicator、用于移动端和PC端工程图形渲染的HOOPS Visualize、支持将3D数据以原生3D PDF、HTML和标…

解决电脑C盘空间不足,发现微信和qq文件占用了大量内存

项目场景: 电脑C盘空间不足,需要隔一段时间清理垃圾,分析占用空间的文件,将C盘文件迁移到E盘。 问题描述 C盘提示空间不足 原因分析: 通过扫描磁盘发现微信和qq文件占用了几十G的内存,由于微信和qq的一…

C++成员函数当作参数调用的两种方式

平时编程时,多用来将数据进行传参,在考虑回调场景下我们会将函数单做参数传给被调用函数,让被调用函数在时机成熟时进行调用。在某些场景下,需要将类的成员函数当作参数进行回调,此时定义成员函数形参的方式通常有两种…

我的python学习经历及资源整理

对于小白来说,有个人引导会比自学要高效的多,尤其容易坚持不下去的小伙伴。可以试试下面这个入门课程,不用本地安装Python环境,能直接在网页上敲代码,还有大牛老师带着入门,能少走很多弯路!只要…

直播弹幕系统(五)- 整合Stomp替换原生WebSocket方案探究

直播弹幕系统(五)- 整合Stomp替换原生WebSocket方案探究前言一. STOMP 协议简单介绍1.1 客户端编码基础1.2 服务端编码基础1.2.1 SimpMessagingTemplate1.2.2 SendTo 和 MessageMapping二. SpringBoot整合STOMP并实现聊天室2.1 基础配置和依赖2.2 WebSoc…

华为EC6108V9C免拆卡刷固件包

华为EC6108V9C免拆卡刷固件包 固件特点: 1、修改dns,三网通用; 2、开放原厂固件屏蔽的市场安装和u盘安装apk; 3、无开机广告,无系统更新,不在被强制升级; 4、大量精简内置的没用的软件&…

Redis高级篇之最佳实践

Redis高级篇之最佳实践 本章内容 Redis 键值设计批处理优化服务端优化集群最佳实践 笔记整理自 b站_黑马程序员Redis入门到实战教程 1. Redis键值设计 优雅的key结构 Redis 的 Key 虽然可以自定义,但最好遵循下面的几个最佳实践约定: 遵循基本格式&a…

Docker容器中安装Jenkins

众所周知,jenkins是现在比较流行的一种工具,今天就记录一下在工作中如何使用了jenkins, 由于我使用的使用Linux(Debain 11)开发环境使用了jdk1.8,会跟最新版的jenkins(官方介绍最新版要jdk11支持)有不良的化学反应,所以把jenkins放到了容器中…

Hive+Spark离线数仓工业项目实战--项目介绍及环境构建(2)

Docker的介绍 了解Docker的基本功能和设计 - 为什么要用Docker? - 什么是Docker? 路径 - step1:生产环境的问题 - step2:容器的概念 - step3:Docker的设计 实施 生产环境的问题 - 运维层面:一…

Windows下的通用进程守护程序(持续更新中),高仿supervisor。

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:无尽的折腾后,终于又回到…