分形小记
2016-08-18 12:49
204 查看
前阵子被何童靴安利了一个知乎帖子:
有没有一段代码,让你觉得人类的智慧也可以璀璨无比?
图形那块美的不要不要~所以基本上一个一个瞅了瞅,所以本文算是个记录吧~
(图片来自知乎)
右侧那浑圆的大屁股,成功的引起的我的注意~
原文代码主要如下:
代码大致是做了这件事:
用 C(Cx,Cy)代表图像上某一点,对参数x=0,y=0作出如下迭代:
x = x*x - y*y + Cx
y = 2 * x * y + Cy
直至x*x+y*y > 4 为止
然后输出迭代所需的次数作为颜色值
代码对三个通道分别作了一些不同的处理,使之更加好看了一丢丢。
刚刚看到这个迭代式其实我是懵逼的……搜了搜终于发现原来就是复数乘法 =_=……
简单而言,Mandelbrot集合是这样的:
对于复平面上的一个点c,和初始点x,对它做如下迭代:
f(x) = x^2 + c
可以得到一个迭代数列。
使这个数列收敛的所有的点,就组成了 Mandelbrot 集合。
所以终于想通了那段代码的含义了~
然后我试图轻微修改下 f(x),看能不能得到更有趣的结果~
t*f(x) = (t*x)^2 + t*c
也就是说,只是影响了收敛判断值,以及把c缩小了t倍。
……不贴效果图了……
这个蛮有意思的……图如下:
第一,这个大屁股变得更圆了,这真是极好的~~
第二,这个aliasing也太严重了。。。。。
大多数情况下都会有一部分显得不规则,贴几种:
t=2.5 :相对而言比较规则了~不过还是可以看到左侧部分那块还是不规则~
t=10:漂亮么~~
嗯,现在还剩下最后一个问题。。。那就是:
这种迭代的数列的收敛性。。。。是怎么控制的。。。数学分析的书里。。。也许有?(逃。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
(图片来自知乎)
写了下注释,虽然没有刚刚那个数学性那么强,但是还是挺难懂的~
个人赶脚,关键是给每个点找到一系列的发散的路径,以及路径的终止点吧~
写完注释就跑好刺激~23333~
PS:刚生成的原图比网站上的图看着效果差远了……走样得不要不要的……
(图片来自知乎)
首先是logistic映射:
logistic映射的关键也是一个迭代数列:
x(t+1) = m * x(t) * (1 - x(t))
这个数列在m等于不同的值的时候,会有不同的收敛性,而我们要画的图,就是将m变化,然后get出它到处分布的那些点~
这里有比较详细的介绍:
Logistic映射 - 集智百科
代码如下:
上边的 r=a*1.6/D+2.4 这部分,其实原式中只有 r 的对吧~
上边的网页里边也很清楚的说了,r将会控制这个数列的收敛性~
也就是说,这个式子里边不美观的hardcode:1.6与2.4,就是代表着对 r 的变换,亦即相当于对纵轴的缩放与平移。
不过因为r本身不能超过4(不然就不收敛了2333),所以我轻微试了几种情况:
记 r = a/D * c1 + c2
从左到右依次为:
c1=1.6, c2=2.4;
c1=2.6, c2=1.4;
c1=3.6, c2=0.4;
其实从式子上也能看出来,从左至右就是把整个图像压扁而已~
然而数学上为何会出现这种美丽的现象,对我而言依然是个谜。。。。(继续逃 ⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄。。。。
(本文几乎完)
有没有一段代码,让你觉得人类的智慧也可以璀璨无比?
图形那块美的不要不要~所以基本上一个一个瞅了瞅,所以本文算是个记录吧~
一、Mandelbrot分形图案
(图片来自知乎)
右侧那浑圆的大屁股,成功的引起的我的注意~
原文代码主要如下:
float x=0,y=0; int k; for(k=0;k++<256;){ float a=x*x-y*y+(i-768.0)/512; x=a; if(x*x+y*y>4)break; } return log(k)*47; /*作者:烧茄子 链接:http://www.zhihu.com/question/30262900/answer/48741026 来源:知乎 著作权归作者所有,转载请联系作者获得授权。*/
代码大致是做了这件事:
用 C(Cx,Cy)代表图像上某一点,对参数x=0,y=0作出如下迭代:
x = x*x - y*y + Cx
y = 2 * x * y + Cy
直至x*x+y*y > 4 为止
然后输出迭代所需的次数作为颜色值
代码对三个通道分别作了一些不同的处理,使之更加好看了一丢丢。
刚刚看到这个迭代式其实我是懵逼的……搜了搜终于发现原来就是复数乘法 =_=……
简单而言,Mandelbrot集合是这样的:
对于复平面上的一个点c,和初始点x,对它做如下迭代:
f(x) = x^2 + c
可以得到一个迭代数列。
使这个数列收敛的所有的点,就组成了 Mandelbrot 集合。
所以终于想通了那段代码的含义了~
然后我试图轻微修改下 f(x),看能不能得到更有趣的结果~
1. f(x) = t * x^2 + c, t为float
结果是trivial的……因为这个参数t其实就相当于这样一个变换:t*f(x) = (t*x)^2 + t*c
也就是说,只是影响了收敛判断值,以及把c缩小了t倍。
……不贴效果图了……
2. f(x) = x^3 + c
// 迭代函数:x^3 + c void f_p3(float x, float y, float cx, float cy, float& x_out, float& y_out) { float new_x_out = t * (x*x*x-3*x*y*y) + cx; float new_y_out = t * (3*x*x*y-y*y*y) + cy; x_out = new_x_out; y_out = new_y_out; }
这个蛮有意思的……图如下:
第一,这个大屁股变得更圆了,这真是极好的~~
第二,这个aliasing也太严重了。。。。。
3. f(x) = x^t + c, t为float
// 迭代函数:x^power + c void f_pn(float x, float y, float cx, float cy, float power, float& x_out, float& y_out) { float angle = atan2(y, x); angle *= power; float radius = x*x+y*y; radius = sqrt(pow(radius, power)); x_out = cos(angle) * radius + cx; y_out = sin(angle) * radius + cy; }
大多数情况下都会有一部分显得不规则,贴几种:
t=2.5 :相对而言比较规则了~不过还是可以看到左侧部分那块还是不规则~
t=10:漂亮么~~
嗯,现在还剩下最后一个问题。。。那就是:
这种迭代的数列的收敛性。。。。是怎么控制的。。。数学分析的书里。。。也许有?(逃。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
二、diffusion-limited aggregation模型的图案
(图片来自知乎)
写了下注释,虽然没有刚刚那个数学性那么强,但是还是挺难懂的~
个人赶脚,关键是给每个点找到一系列的发散的路径,以及路径的终止点吧~
unsigned char RD(int i,int j){ #define D DIM #define M m[(x+D+(d==0)-(d==2))%D][(y+D+(d==1)-(d==3))%D] #define R rand()%D #define B m[x][y] return(i+j)?256-(BL(i,j))/2:0; } unsigned char GR(int i,int j){ return RD(i,j); } unsigned char BL(int i,int j){ static int m[D][D],e,x,y,d,c[4],f,n; // m[D][D]代表整个画面上存储的中间数据,c[4]代表四个方向 if(i+j<1){ for(d=D*D;d;d--) { m[d%D][d/D]= d%6 ? 0 : ( rand()%2000?1:255 ) ; //建立一个静态数组 m[1024][1024],其成员有1/2000的概率为255,否则为1;而且在6倍处永远为0 } for(n=1;n;n++) { x=R; y=R; if(B==1) // 挑选上述生成的静态数组中,为1的那些位置 { f=1; for(d=0;d<4;d++) // 遍历该点的四个方向 { c[d]=M; // 初始化c为该方向上的点的m的数据 f=f<c[d]?c[d]:f; // 取 f 为四个方向上的最大值 } if(f>2) // 如果 f 曾经获得了某个方向上的数据 { B=f-1; // 那么该点的值 -1 } else // 否则 { ++e%=4; // 选取某个方向(对于每次循环轮流选取) d=e; if(!c[e]) // 如果该方向上为 0 { B=0;M=1; // 那么当前位置为 0,刚刚的方向上也置为 0 } } } } } return m[i][j]; }
写完注释就跑好刺激~23333~
PS:刚生成的原图比网站上的图看着效果差远了……走样得不要不要的……
三、logistic 映射得到的 Feigenbaum 分岔图
先上图~(图片来自知乎)
首先是logistic映射:
logistic映射的关键也是一个迭代数列:
x(t+1) = m * x(t) * (1 - x(t))
这个数列在m等于不同的值的时候,会有不同的收敛性,而我们要画的图,就是将m变化,然后get出它到处分布的那些点~
这里有比较详细的介绍:
Logistic映射 - 集智百科
代码如下:
unsigned char BL(int i,int j){ static float c[D][D]; if(i+j<1) { float a=0,b,k,r,x; int e,o; for(;a<D;a+=0.1) // 代表纵轴(步长间隔为 0.1,范围为 0 到 DIM) { for( b=0;b<D;b++) // 代表横轴 { r=a*1.6/D+2.4; // 获得关于纵轴变化的 logistic 映射的系数 x=1.0001*b/D; // 重置下横轴的值,使之更适应于 [0,1] for( k=0;k<D;k++) // 对横轴的值,循环DIM次,来计算 logistic 映射的收敛后的分布 { x=r*x*(1-x); // logistic 映射 if(k>D) // 对于后一半的映射 { e=a; // 转换为int o=(DM1*x); // 转换为int c[e][o]+=0.01; // 对于该点 ,那么把它的颜色增加一点 } } } } } return c[j][i]>255?255:c[j][i] * i / D; // 把颜色转换到能看的地步 }
上边的 r=a*1.6/D+2.4 这部分,其实原式中只有 r 的对吧~
上边的网页里边也很清楚的说了,r将会控制这个数列的收敛性~
也就是说,这个式子里边不美观的hardcode:1.6与2.4,就是代表着对 r 的变换,亦即相当于对纵轴的缩放与平移。
不过因为r本身不能超过4(不然就不收敛了2333),所以我轻微试了几种情况:
记 r = a/D * c1 + c2
从左到右依次为:
c1=1.6, c2=2.4;
c1=2.6, c2=1.4;
c1=3.6, c2=0.4;
其实从式子上也能看出来,从左至右就是把整个图像压扁而已~
然而数学上为何会出现这种美丽的现象,对我而言依然是个谜。。。。(继续逃 ⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄。。。。
(本文几乎完)
相关文章推荐
- “铺地砖”问题
- 分形图(fractal pictures)
- 曼德勃罗集(Mandelbrot Set)
- Mandelbrot Set & Julia Set -- 美丽分形 (C++, MFC + BCG + CxImage 实现)
- 用Qt绘制一张分形图
- 谢宾斯基三角形
- 分形 递归打印之C5
- 分形 递归打印之神奇三角形
- Sierpinski三角
- 树动画
- 分形--Cantor三分集
- 基于复变函数f(z)=z^2+c的迭代分形图
- 哈理工OJ 2308 Invitations(分形题目)
- 分形神经网络
- 分形与计算机图形学
- Step 7:Processing分形之二——Peter de Jong Attractor
- Step 6:Processing分形之一——Wallpaper
- POJ 3768(分形+递归)
- L-System分形
- L-系统语法规则构建三维分形树