用Python画Mandelbrot集

Mandelbrot Set(曼德勃罗集)可能是分形 图形中最有名的图形,关于它的介绍我就不多写了,有兴趣的可以参考这个链接 。下面是关于如何使用Python来画这个图形的尝试。

由于Python标准库中还没有对图形处理的支持,在此我使用了PIL 。先来看一张生成的图形:

Mandelbrot Set

相关的代码大致是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# -*- coding: utf-8 -*-
#
# z<n+1> = z<n> ^ 2 + c
#
# by oldj
#
# last update: 2010-10-22 22:02:05
#
 
import time
import Image, ImageDraw
 
g_size = (40, 30) # 图形最终尺寸
g_max_iteration = 256 # 最大迭代次数
g_bailout = 4 # 最大域
g_zoom = 2.5 / g_size[0] # 缩放参数
g_offset = (-g_size[0] * 0.25, 0) # 偏移量
g_HSL = (210, 80, 50) # HSL色彩基调
 
def draw(antialias = True):
    zi = 2 if antialias else 1 # antialias: 抗锯齿 size = [i * zi
    size = [i * zi for i in g_size]
    zoom = g_zoom / zi
    offset = [i * zi  for i in g_offset]
    bailout = g_bailout * zi
    img = Image.new("RGB", size, 0xffffff)
    dr = ImageDraw.Draw(img)
 
    print "painting Mandelbrot Set.."
    for xy, color in getPoints(size, offset, zoom):
        dr.point(xy, fill = color)
    print "100%n"
 
    del dr
    if antialias:
        img = img.resize(g_size, Image.ANTIALIAS)
    img.show()
    img.save("mandelbrot_set_%dx%d.png" % g_size)
 
def getPoints(size, offset, zoom, ti = 0, tstep = 1):
    "生成需要绘制的点的坐标及颜色"
 
    def getRepeats(c):
        z = c
        repeats = 0
        while abs(z) < g_bailout and repeats < g_max_iteration:
            z = z * z + c
            repeats += 1
        return repeats
 
    def getColor(r):
        color = "hsl(0, 0%, 0%)"
        if r < g_max_iteration:
            v = 1.0 * r / g_max_iteration
            h = ch * (1 - v)
            s = cs
            l = cl * (1 + v)
            color = "hsl(%d, %d%%, %d%%)" % (h, s, l)
        return color
 
    xs, ys = size
    xw, yh = xs / 2, ys / 2
    xo, yo = offset
    ch, cs, cl = g_HSL
 
    progress = 0
    for iy in xrange(ys):
        p = iy * 100 / ys
        if iy % 10 == 0 and p != progress:
            print ("%d%%..." % p) # 显示进度
            progress = p
        for ix in xrange(ti, xs, tstep):
            x = (ix - xw + xo) * zoom
            y = (iy - yh + yo) * zoom
            c = complex(x, y)
            r = getRepeats(c)
            yield (ix, iy), getColor(r)
 
def main():
    t0 = time.time()
    draw()
    t = time.time() - t0
    print "%dm%.3fs" % (t / 60, t % 60)
 
if __name__ == "__main__":
    main()

其中第8行设置了图形最终的尺寸,如果想生成大一些或小一些的图形,可以修改这个参数。第9行是最大迭代次数,这个参数值越高越能得到更多的图像细节,当然,代价就是需要更多的计算时间。

另外,第47~55行的getColor函数定义了每个点颜色的产生规则,可以在这儿修改颜色规则,画出更多不同色彩的Mandelbrot集来。

下面是本程序在不同的参数及颜色规则下生成的另外几副图。

Mandelbrot Set

Mandelbrot Set

Mandelbrot Set

修改一下上面的代码,不难生成更多细节图片。不过,如果不想自己动手,也可以试一下XaoS 这个软件,通过它,你可以将Mandelbrot集的某个局部放大很多倍。当然,你会发现,无论放大了多少,Mandelbrot集始终有无穷无尽的变化与精致细节。