Mandelbrot集Julia集分形的MATLAB实现(分形艺术)

本文首发于 matlab爱好者 微信公众号,欢迎关注。

惯例声明:本人没有相关的工程应用经验,只是纯粹对相关算法感兴趣才写此博客。所以如果有错误,欢迎在评论区指正,不胜感激。本文主要关注于算法的实现,对于实际应用等问题本人没有任何经验,所以也不再涉及。

本文为学习非线性动力学时,搜索资料时发现的一个小例子,感觉很有趣,试着自己尝试一下。相关实现案例非常多,所以这篇文章就简单水一下了。
其余两篇水文链接也一并奉上:
利用matlab进行混沌摆仿真(双摆、三摆、多摆演示)https://blog.csdn.net/weixin_42943114/article/details/121891553
利用matlab实现复数域空间牛顿迭代法的分形图案展示(newton法)https://blog.csdn.net/weixin_42943114/article/details/121905957

参考目录:
[1]GPU Code Generation: The Mandelbrot Set(https://www.mathworks.com/help/gpucoder/gs/gpu-code-generation-the-mandelbrot-set.html)
[2]神奇的分形艺术(四):Julia集和Mandelbrot集(http://www.matrix67.com/blog/archives/292)

1 简单Julia集的实现

对于复平面上某个点z,经过函数z=f(z)的不断迭代,会有两种结局:收敛或发散。

当我们取函数f(z)=z^2+C,对整个平面每个点,都经过上述多次迭代后,记录其收敛或发散的情况,并标记在图上,最终形成的图案就是Julia集。C不一定是实数,也可以是复数。

这里我用matlab简单写了一个当C=0.279的图像:
请添加图片描述
这里的颜色条我借鉴的是Matrix67博客里引用的一个图片的颜色条,自己搭配的,见神奇的分形艺术(四):Julia集和Mandelbrot集

程序算法参见matlab官方的一个介绍gpu加速的文章中GPU Code Generation: The Mandelbrot Set提到的一种算法。

程序如下:

%?res是目标分辨率,iter是循环次数,(xc,yc)是图像中心,xoom是放大倍数
%res分辨率越多,在一张图上能够计算的点越多。iter越多,细节越丰富。
clear;
clc
close all
res=2500;iter=200;xc=0;yc=0;xoom=1.7;

x0=xc-2/xoom;x1=xc+2/xoom;
y0=yc-2/xoom;y1=yc+2/xoom;
x=linspace(x0,x1,res);
y=linspace(y0,y1,res);
[xx,yy]=meshgrid(x,y);
z=xx+yy*1i;

C=0.279;
tic

%matlab官方推荐的方法
N = ones(res,res);
for k = 0:iter
    z = z.*z + C;
    inside = abs( z )<=2;
    N = N + inside;
end
toc

%这里代码参见博客:
%利用matlab构建自己的colormap(色彩搭配)
%https://blog.csdn.net/weixin_42943114/article/details/81811556
%蓝色-橘色颜色条
mycolorpoint=[
    [235 255 255];...
    [243 253 242];...
    [248 247 193];...
    [255 211 49];...
    [236 133 0];...
    [134 36 21];...
    [75 6 34];...
    [15 5 64];...
    [3 8 96];...
    [7 35 154];...
    [24 84 205];...
    [87 169 229];...
    [165 223 247];...
    [235 255 255];...
    ];
mycolorposition=[1 3 7 14 27 45 57 66 74 86 96 109 119 128];
mycolormap_r=interp1(mycolorposition,mycolorpoint(:,1),1:128,'pchip','extrap');
mycolormap_g=interp1(mycolorposition,mycolorpoint(:,2),1:128,'pchip','extrap');
mycolormap_b=interp1(mycolorposition,mycolorpoint(:,3),1:128,'pchip','extrap');
mycolor=[mycolormap_r',mycolormap_g',mycolormap_b']/255;

figure()
pcolor(x,y,log(N));
mycolor=interp1(linspace(1,256,128),mycolor,1:256);
colormap([mycolor;mycolor;mycolor])%重复颜色条
shading interp

1.1 如何实现更光滑的展示效果?

我在网上查阅资料,发现大部分资料就到此为止了。虽然输出的图片的确像回事,但是它是一个台阶一个台阶的,距离想象中的光滑过度变化有很大差别。
请添加图片描述
这个台阶产生的原因是算法本身,算法用整数去衡量该点发散的快与慢。因此只要算法不更改,整数导致的台阶问题无法消除。所以只能从其他角度去消除这个台阶。

因此我这一小节也提出了一个小改进算法,能够二次加工分形图,去除台阶。之前用过各种滤波法,但是效果不好,因为分形图具有特别多的细节,直接滤波会导致分形图的细节全部丢失。所以后来采用了提取等值线边缘提取的思路,来保持图像形状,再进行光滑插值的方法。效果如下:
请添加图片描述

可以看到基本保留了大部分分形细节,而且过渡也比较光滑。边缘部分受插值信息限制,可能过渡受边框影响,有些不自然。当然缺点也比较明显,就是我这个轮廓选择原则是逐个像素4个边来决定的,所以计算量非常大。因为之前试过M = contour()函数提取等高线,效果似乎差不多,喜欢折腾的可以在这里再研究一下,看看像Ultra Fractal 之类的分形软件是怎么实现这种效果的。

完整代码如下:

%?res是目标分辨率,iter是循环次数,(xc,yc)是图像中心,xoom是放大倍数
%res分辨率越多,在一张图上能够计算的点越多。iter越多,细节越丰富。
clear;
clc
close all
res=2500;iter=200;xc=0;yc=0;xoom=1.7;

x0=xc-2/xoom;x1=xc+2/xoom;
y0=yc-2/xoom;y1=yc+2/xoom;
x=linspace(x0,x1,res);
y=linspace(y0,y1,res);
[xx,yy]=meshgrid(x,y);
z=xx+yy*1i;
C=0.279;
tic

%matlab官方推荐
N = ones(res,res);
for k = 0:iter
    z = z.*z + C;
    inside = abs( z )<=2;
    N = N + inside;
end
toc

mycolorpoint=[[235 255 255];[243 253 242];[248 247 193];[255 211 49];...
    [236 133 0];[134 36 21];[75 6 34];[15 5 64];...
    [3 8 96];[7 35 154];[24 84 205];[87 169 229];...
    [165 223 247];[235 255 255]; ];
mycolorposition=[1 3 7 14 27 45 57 66 74 86 96 109 119 128];
mycolormap_r=interp1(mycolorposition,mycolorpoint(:,1),1:128,'pchip','extrap');
mycolormap_g=interp1(mycolorposition,mycolorpoint(:,2),1:128,'pchip','extrap');
mycolormap_b=interp1(mycolorposition,mycolorpoint(:,3),1:128,'pchip','extrap');
mycolor=[mycolormap_r',mycolormap_g',mycolormap_b']/255;

%输出
figure()
pcolor(x,y,log(N));
mycolor=interp1(linspace(1,256,128),mycolor,1:256);
colormap([mycolor;mycolor;mycolor])
shading interp

%二次光滑
Nq=LowPrecision2High(N);
figure()
pcolor(x,y,log(Nq));
colormap([mycolor;mycolor;mycolor])
shading interp


function Zq=LowPrecision2High(Z)
%对阶梯数据进行平滑
[Nx,Ny]=size(Z);
[X,Y]=meshgrid(1:Nx,1:Ny);
XP=[];YP=[];ZP=[];
for kx=1:(Nx-1)
    for ky=1:(Ny-1)
        if Z(kx,ky)~=Z(kx,ky+1)
            x_t=0.5*(X(kx,ky)+X(kx,ky+1));
            y_t=0.5*(Y(kx,ky)+Y(kx,ky+1));
            z_t=0.5*(Z(kx,ky)+Z(kx,ky+1));
            XP=[XP;x_t];YP=[YP;y_t];ZP=[ZP;z_t];
        end
        if Z(kx,ky)~=Z(kx+1,ky)
            x_t=0.5*(X(kx,ky)+X(kx+1,ky));
            y_t=0.5*(Y(kx,ky)+Y(kx+1,ky));
            z_t=0.5*(Z(kx,ky)+Z(kx+1,ky));
            XP=[XP;x_t];YP=[YP;y_t];ZP=[ZP;z_t];
        end
    end
end
%边界值
for kx=1:Nx
    XP=[XP;X(kx,1)];  YP=[YP;Y(kx,1)];  ZP=[ZP;Z(kx,1)];
    XP=[XP;X(kx,end)];YP=[YP;Y(kx,end)];ZP=[ZP;Z(kx,end)];
end
for ky=2:Ny-1
    XP=[XP;X(1,ky)];  YP=[YP;Y(1,ky)];  ZP=[ZP;Z(1,ky)];
    XP=[XP;X(end,ky)];YP=[YP;Y(end,ky)];ZP=[ZP;Z(end,ky)];
end
Zq=griddata(XP,YP,ZP,X,Y,'natural');%'v4'最好,但是速度最慢。实在不行用linear,快一点但不好看。
end

2 Mandelbrot集的实现

Mandelbrot集的求解方法和Julia集类似,就是方程不一样,它不再是常数C,而是把C替换成了z0。
f ( z ) = z 2 + z 0 f(z)=z^2+z_0 f(z)=z2+z0
这里z0代表初始迭代的点坐标。
结果如下:
请添加图片描述
代码如下:

%?res是目标分辨率,iter是循环次数,(xc,yc)是图像中心,xoom是放大倍数
%res分辨率越多,在一张图上能够计算的点越多。iter越多,细节越丰富。
clear;
clc
close all
res=1024;iter=100;xc=-0.5;yc=0;xoom=1;%这个可以自己调试,用来观察细节

x0=xc-2/xoom;x1=xc+2/xoom;
y0=yc-2/xoom;y1=yc+2/xoom;
x=linspace(x0,x1,res);
y=linspace(y0,y1,res);
[xx,yy]=meshgrid(x,y);
z=xx+yy*1i;
C=z;
tic

%matlab官方推荐
N = ones(res,res);
for k = 0:iter
    z = z.*z + C;
    inside = abs( z )<=2;
    N = N + inside;
end
toc

mycolorpoint=[[235 255 255];[243 253 242];[248 247 193];[255 211 49];...
    [236 133 0];[134 36 21];[75 6 34];[15 5 64];...
    [3 8 96];[7 35 154];[24 84 205];[87 169 229];...
    [165 223 247];[235 255 255]; ];
mycolorposition=[1 3 7 14 27 45 57 66 74 86 96 109 119 128];
mycolormap_r=interp1(mycolorposition,mycolorpoint(:,1),1:128,'pchip','extrap');
mycolormap_g=interp1(mycolorposition,mycolorpoint(:,2),1:128,'pchip','extrap');
mycolormap_b=interp1(mycolorposition,mycolorpoint(:,3),1:128,'pchip','extrap');
mycolor=[mycolormap_r',mycolormap_g',mycolormap_b']/255;

%输出
figure()
pcolor(x,y,log(N));
mycolor=interp1(linspace(1,256,128),mycolor,1:256);
colormap([mycolor;mycolor;mycolor])
shading interp

%二次光滑
Nq=LowPrecision2High(N);
figure()
pcolor(x,y,log(Nq));
colormap([mycolor;mycolor;mycolor])
shading interp


function Zq=LowPrecision2High(Z)
%对阶梯数据进行平滑
[Nx,Ny]=size(Z);
[X,Y]=meshgrid(1:Nx,1:Ny);
XP=[];YP=[];ZP=[];
for kx=1:(Nx-1)
    for ky=1:(Ny-1)
        if Z(kx,ky)~=Z(kx,ky+1)
            x_t=0.5*(X(kx,ky)+X(kx,ky+1));
            y_t=0.5*(Y(kx,ky)+Y(kx,ky+1));
            z_t=0.5*(Z(kx,ky)+Z(kx,ky+1));
            XP=[XP;x_t];YP=[YP;y_t];ZP=[ZP;z_t];
        end
        if Z(kx,ky)~=Z(kx+1,ky)
            x_t=0.5*(X(kx,ky)+X(kx+1,ky));
            y_t=0.5*(Y(kx,ky)+Y(kx+1,ky));
            z_t=0.5*(Z(kx,ky)+Z(kx+1,ky));
            XP=[XP;x_t];YP=[YP;y_t];ZP=[ZP;z_t];
        end
    end
end
%边界值
for kx=1:Nx
    XP=[XP;X(kx,1)];  YP=[YP;Y(kx,1)];  ZP=[ZP;Z(kx,1)];
    XP=[XP;X(kx,end)];YP=[YP;Y(kx,end)];ZP=[ZP;Z(kx,end)];
end
for ky=2:Ny-1
    XP=[XP;X(1,ky)];  YP=[YP;Y(1,ky)];  ZP=[ZP;Z(1,ky)];
    XP=[XP;X(end,ky)];YP=[YP;Y(end,ky)];ZP=[ZP;Z(end,ky)];
end
Zq=griddata(XP,YP,ZP,X,Y,'natural');%'v4'最好,但是速度最慢。实在不行用linear,快一点但不好看。
end

3 永恒的细节

分形图案最有意思的,在于其看似有规律却又不可描述的图像,以及无穷无尽直至永恒的细节。

我们以Mandelbort集为例,在上一节的程序里,只需要变动xc=-0.5;yc=0;xoom=1;这几个数,便可以改变镜头的中心位置和放大倍数。
现在将(-0.912,-0.2611)这一点放大,可以得到:
请添加图片描述
可以看到放大图像之后,细节并没有减少,反而更多的细节被展示出来,跳到面前,用精巧的结构引诱人们进一步的放大图像。它的图像最有规律,每一处都透露着美感;它的图像又毫无规律,无法用现有的数学语言去描述。它的方程非常简单,但它产生的结构又非常复杂。

最后用一个动图来展示其魅力(扫兴的是gif图片上传有大小限制,所以只能压缩到渣画质,分割为两个图上传了,非常道歉)

请添加图片描述

第二个图,接上一个:

请添加图片描述
下面放代码:

%Mandelbrot
%http://www.matrix67.com/blog/archives/292
%?res是目标分辨率,iter是循环次数,(xc,yc)是图像中心,xoom是放大倍数
clear;
res=512;iter=200;xc=-0.748766710846959;yc=-0.123640847970064;

mycolorpoint=[[235 255 255];[243 253 242];[248 247 193];[255 211 49];...
    [236 133 0];[134 36 21];[75 6 34];[15 5 64];...
    [3 8 96];[7 35 154];[24 84 205];[87 169 229];...
    [165 223 247];[235 255 255]; ];
mycolorposition=[1 3 7 14 27 45 57 66 74 86 96 109 119 128];
mycolormap_r=interp1(mycolorposition,mycolorpoint(:,1),1:128,'pchip','extrap');
mycolormap_g=interp1(mycolorposition,mycolorpoint(:,2),1:128,'pchip','extrap');
mycolormap_b=interp1(mycolorposition,mycolorpoint(:,3),1:128,'pchip','extrap');
mycolor=[mycolormap_r',mycolormap_g',mycolormap_b']/255;
mycolor=interp1(linspace(1,256,128),mycolor,1:256);
colormap([mycolor;mycolor;mycolor])

GIF=2;%第二段动画
for m=(1+46*GIF):46*(GIF+1)
    xoom=1.2^m;
    %xoom=6.503637847981780e+08;
    
    x0=xc-2/xoom;x1=xc+2/xoom;
    y0=yc-2/xoom;y1=yc+2/xoom;
    x=linspace(x0,x1,res);
    y=linspace(y0,y1,res);
    [xx,yy]=meshgrid(x,y);
    z=xx+yy*1i;
    C=z;
    
    %matlab官方推荐
    N = ones(res,res);
    for k = 0:iter
        z = z.*z + C;
        inside = abs( z )<=2;
        N = N + inside;
    end
    
    Nq=LowPrecision2High(N);
    figure(1)
    clf
    pcolor(x,y,log(Nq));shading interp
    colormap([mycolor;mycolor;mycolor])
    caxis([0,log(iter+2)])
    %生成gif图
    pause(0.1)
    F=getframe(gca);
    I=frame2im(F);
    [I,map]=rgb2ind(I,256);
    if m == (1+46*GIF)
        imwrite(I,map,'test.gif','gif','Loopcount',inf,'DelayTime',0.2);
    else
        imwrite(I,map,'test.gif','gif','WriteMode','append','DelayTime',0.2);
    end
end


function Zq=LowPrecision2High(Z)
[Nx,Ny]=size(Z);
[X,Y]=meshgrid(1:Nx,1:Ny);
XP=[];YP=[];ZP=[];
for kx=1:(Nx-1)
    for ky=1:(Ny-1)
        if Z(kx,ky)~=Z(kx,ky+1)
            x_t=0.5*(X(kx,ky)+X(kx,ky+1));
            y_t=0.5*(Y(kx,ky)+Y(kx,ky+1));
            z_t=0.5*(Z(kx,ky)+Z(kx,ky+1));
            XP=[XP;x_t];YP=[YP;y_t];ZP=[ZP;z_t];
        end
        if Z(kx,ky)~=Z(kx+1,ky)
            x_t=0.5*(X(kx,ky)+X(kx+1,ky));
            y_t=0.5*(Y(kx,ky)+Y(kx+1,ky));
            z_t=0.5*(Z(kx,ky)+Z(kx+1,ky));
            XP=[XP;x_t];YP=[YP;y_t];ZP=[ZP;z_t];
            %pause(0.1)
        end
    end
end
%边界值
for kx=1:Nx
    XP=[XP;X(kx,1)];  YP=[YP;Y(kx,1)];  ZP=[ZP;Z(kx,1)];
    XP=[XP;X(kx,end)];YP=[YP;Y(kx,end)];ZP=[ZP;Z(kx,end)];
end
for ky=2:Ny-1
    XP=[XP;X(1,ky)];  YP=[YP;Y(1,ky)];  ZP=[ZP;Z(1,ky)];
    XP=[XP;X(end,ky)];YP=[YP;Y(end,ky)];ZP=[ZP;Z(end,ky)];
end
Zq=griddata(XP,YP,ZP,X,Y,'natural');%'v4'最好,实在不行用linear
end
  • 14
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: CAD批量生成填充案的边界线插件是一种用于CAD软件的辅助工具,可以帮助用户快速、自动地生成填充案的边界线。 该插件的工作原理是基于对CAD软件的二次开发,它能够识别用户设定的填充案样式,并自动将其应用于选定的区域或对象的边界线上。 使用该插件的方法相对简单。首先,用户需要导入或定义自己的填充案样式库。然后,在CAD软件中选择需要填充的区域或对象,并设置所需的填充案样式。接下来,通过插件的操作界面或快捷命令,用户只需轻松点击“生成”按钮,插件就会自动识别边界线并将填充案应用于其上。 该插件的优势在于能够大大提高用户的工作效率。传统的手工绘制边界线进行填充案常常费时费力,而使用该插件可以快速地批量生成边界线,极大地节省了时间和精力。 同时,该插件还具备一定的灵活性和定制化能力。用户可以根据自己的需求,调整填充案的大小、间距以及方向等参数,以达到更好的填充效果。此外,插件还支持导出边界线数据,方便用户在其他项目中重复使用。 总之,CAD批量生成填充案的边界线插件是一款实用的CAD辅助工具,可大大提升用户填充案的效率和质量。通过它,用户可以轻松地应用各种填充案样式,更加方便地进行CAD设计和绘工作。 ### 回答2: CAD批量生成填充案的边界线插件是一种可以在CAD软件中使用的工具,它可以自动创建填充案的边界线。在CAD设计中,使用填充案可以使形更加丰富和美观,但是手动创建填充案的边界线是一项繁琐而耗时的任务。这个插件的目的就是解决这个问题。 使用这个插件非常简单,只需要将其安装到CAD软件中,然后在插件选项中选择要应用填充案的形对象。一旦选择了形对象,插件就会自动识别形的边界线,并根据用户设置的参数生成填充案的边界线。用户可以根据需要选择不同的填充案和边界线样式,从而在设计中实现各种不同的效果。 通过使用这个插件,设计师可以节省大量的时间和精力,可以更专注于设计细节和创意思考。同时,由于边界线是自动生成的,所以可以保证边界线的准确性和一致性。 这个插件还提供一些额外的功能,比如批量处理多个形对象,根据用户的要求自动调整形的边界线等。这些功能进一步增强了插件的实用性和便利性。 综上所述,CAD批量生成填充案的边界线插件是一种非常实用的工具,可以大大简化设计过程,提高效率。它帮助设计师在CAD软件中快速生成填充案的边界线,使设计更加美观和精确。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值