上帝的指纹——Mandelbrot集合的绘制

322px-mandel_zoom_00_mandelbrot_set

曼德博集合(Mandelbrot Set)是一个在复平面上的点集。有人认为 Mandelbrot 集合是“人类有史以来做出的最奇异、最瑰丽的几何图形”,曾被称为“上帝的指纹”。

Mandelbrot 集合是一个分形(fractal),将它无限放大都能够有精妙的细节在内,而这瑰丽的图案仅仅由一个简单的公式生成。

Mandelbrot 集合的定义是由法国数学家 Adrien Douady 做出的,而它的命名则是为了纪念被称为“分形学之父”的 Benoit Mandelbrot。

在计算机出现后,对于分形的绘制成为了可能。在这篇文章中,我会介绍如何用 C++ 以及高精度库 MPFR 绘制 Mandelbrot 集合,以及对图像色彩渲染的一些方法。

具体代码可以参考 https://github.com/miskcoo/mandelbrot-render

迭代计算

Mandelbrot 集合事实上是在复平面上的点 c 的集合,这些点满足从 z_0 = 0 开始按照公式

 z_{n+1} = z_n^2 + c

迭代下去 |z_n| 始终有界。形式化的描述就是

 M = \{ c \in \mathbb{C} : \exists s \in \mathbb{R}, \forall n \in \mathbb{N}, |z_n| \leq s \}

一个点 c 在 Mandelbrot 集合中,当且仅当对于所有的 n \geq 0 都满足 |z_n| \leq 2。这个性质特别适合让我们通过迭代来判断一个点是否不属于 Mandelbrot 集合。

由于我们不可能进行无限次迭代来判断一个点是否属于 Mandelbrot 集合,因此在进行计算的时候通常都会先设定一个最大的迭代次数,如果迭代超过这个次数 |z_n| 仍然小于或等于 2,那么就认为这个点在这个集合中。

由于 Mandelbrot 集的图像是可以无限放大的,当放大到一定程度的时候通常所用的 double 的精度就会出现不足,因此需要使用像 MPFR 这样的高精度库来实现。不过,为了加快速度,在 double 的精度能够满足需求的时候我们还是利用它来计算。

颜色渲染

在通过迭代判断出一个点是否属于 Mandelbrot 集后,我们还需要做的就是将这个图形可视化,而这最关键的一步就是着色!通常情况下,我们把属于 Mandelbrot 集的点渲染为黑色,对于其它不属于它的点,这里提供几个着色方法以供参考

利用迭代次数着色

最简单的一个办法就是利用迭代次数来着色,对于不属于 Mandelbrot 集的点来说,它一定会在某一次迭代中满足  |z_n| > 2,我们可以直接按照迭代次数和最大迭代深度的比值来决定该点的 RGB 值。

 (R, G, B) = (\frac{\text{iter}}{\text{max_iter}}, \frac{\text{iter}}{\text{max_iter}}, \frac{\text{iter}}{\text{max_iter}})

但是这样随着图像的放大或者最大迭代深度被设置地太大的时候就有可能出现很多细节丢失的情况。

mandelbrot-iteration-50 mandelbrot-iteration-255 mandelbrot-iteration-500

上面三幅图分别是最大迭代深度为 50, 250, 500 的时候,按照上面所说的方法着色后的图像。

当然,最大迭代次数肯定不是越少越好,如果它太少的话就会有些需要迭代很多次后才可以判断出不属于 Mandelbrot 集的点被认为是属于它,这样也会丢失很多细节。

另外一种着色方案是在这个方案上稍加修改,使得着色与最大迭代次数无关。

前面一种方案是从头到尾只有一个区间由黑色到白色渐变,现在我们设置多个区间由黑色到白色,白色到黑色,黑色到白色这样循环渐变,比如在迭代次数为 [0, 150] 的区间按照先前的方案由黑到白线性渐变,之后在迭代次数为 [150, 300] 的区间从白到黑线性渐变,以此类推…… 这样的话效果会比刚刚好非常多。

还有一些给图像渲染彩色的方法可以通过对色相(hue)进行渐变的方法来进行,利用 HSV/HSL(hue-saturation-value/luminosity)这种颜色格式来计算,之后再转换成 RGB 输出。

综合迭代次数和逃逸半径着色

你可能会注意到前面迭代次数为 50 的那张图外边两种颜色之间有明显的分界线,事实上,我们可以利用最后一次迭代得到的 |z_n| 来进行平滑处理,就是通过下面这个公式让迭代次数从整数变为浮点

 \text{smooth_iter} = \text{iter} + 1 - \log_2{\log_2{|z_n|}}

然后再利用前面按照迭代次数的方法进行着色。

Miskcoo's Space,版权所有丨如未注明,均为原创
转载请注明转自:http://blog.miskcoo.com/2016/10/mandelbrot-set

miskcoo

顺利从福州一中毕业!感觉大学周围都是聚聚十分可怕QAQ 想要联系的话欢迎发邮件:miskcoo [at] gmail [dot] com

Leave a Reply

Your email address will not be published. Required fields are marked *

NOTE: If you want to add mathematical formulas, use $$ to wrap them. For example, use $$x_0$$ to get $$x_0$$.

If you want to get a newline, hit Enter twice, that is, use double newlines to get a newline.