将颜色层添加到 mandelbrot 集

Adding color layers to the mandelbrot set

我对分形很感兴趣,但直到最近才有机会实现它们。我首先实现了一个黑色和白色的 mandelbrot 集,然后我尝试为其添加颜色。

这是我的 mandelbrot 实现(我使用 org.apache.commons.math3.complex.Complex 表示复数)

public class MyMandelbrot {

    public static int numberOfIterationsToCheck(Complex z0, int max) {
        Complex z = z0;
        for (int t = 0; t < max; t++) {
            if (z.abs() > 2.0) return t;
            z =z.multiply(z).add(z0);
        }
        return max;
    }

    public static void main(String[] args)  {
        double xc   = Double.parseDouble(args[0]);
        double yc   = Double.parseDouble(args[1]);
        double size = Double.parseDouble(args[2]);

        int N   = 512;   
        int max = 255;   

        Viewer viewer = new Viewer(N, N);
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                double x0 = xc - size/2 + size*i/N;
                double y0 = yc - size/2 + size*j/N;
                Complex z0 = new Complex(x0, y0);
                int gray = max - numberOfIterationsToCheck(z0, max);

                Color color = new Color(gray, gray, gray);
                if (z0.abs() > 2.0 ) {

                    color = new Color(gray, 128, gray);
                } else if (z0.abs() > 2.0 && numberOfIterationsToCheck(z0,     max) > max/2) {
                    color = new Color(255, gray, 255);
                } else  if (z0.abs() > 2.0 &&  numberOfIterationsToCheck(z0,     max) < max/2) {
                    color = new Color(gray, 128,128);
                }

                else if (z0.abs() > 1.0 &&  numberOfIterationsToCheck(z0,     max) < max/2 ) {
                    color = new Color(128, gray, 128);
                } else if (z0.abs() > 1.0) {

                    color = new Color(128, gray, 128);
                }

                else if (z0.abs() <= 1.0) {
                    color = new Color(gray, gray, 128);
                }

                viewer.set(i, N-1-j, color);
            }
        }
        viewer.show();
    }

}

我正在使用自定义查看器 class 在图像对象中绘制后查看集合。这里是Viewer

的set方法
 public void set(int col, int row, Color color) {
    if (col < 0 || col >= width())  throw new IndexOutOfBoundsException("col must be between 0 and " + (width()-1));
    if (row < 0 || row >= height()) throw new IndexOutOfBoundsException("row  must be between 0 and " + (height()-1));
    if (color == null) throw new NullPointerException("can't set Color to null");
    if (isOriginUpperLeft) image.setRGB(col, row, color.getRGB());
    else                   image.setRGB(col, height - row - 1, color.getRGB());
}

代码正确地渲染了集合,但我没有获得预期的结果。我想要的是能够制作出类似于这些的彩色集

或者这个

但我找不到比这更好的彩色套装了。

我已经阅读了一些关于它的理论解释here and here,但我在实践中显然做错了。我的着色方法有什么问题?我该如何解决?谢谢

在您展示的示例中,颜色仅基于点逃逸前的迭代次数,而不是基于初始复数坐标 z0。一种方法是使用 getHSBColor() 的 Hue-Saturation-Brightness 颜色值,并在它逃逸之前根据迭代次数更改色调,例如:

        double x0 = xc - size/2 + size*i/N;
        double y0 = yc - size/2 + size*j/N;
        Complex z0 = new Complex(x0, y0);
        int escapeIterations = numberOfIterationsToCheck(z0, max);

        // set color varying hue based on escape iterations:
        Color color = Color.getHSBColor((float)escapeIterations / (float)max, 1.0f, 1.0f);

        viewer.set(i, N-1-j, color);

上面的代码不会改变饱和度或亮度(两者都设置为 1.0),但您也可以根据需要的效果改变它们。

您可以通过将色相值乘以常数来使颜色在色相的色环中循环不止一次,例如:

(float)escapeIterations * 2.0f / (float)max

您还可以添加一个常量,使其以特定颜色开始。

因为escapeIterations是一个整数,所以每次迭代颜色都会跳跃。您可以通过从 numberOfIterationsToCheck:

返回一个浮点数来使颜色更平滑
public static float numberOfIterationsToCheckSmooth(Complex z0, int max) {
    Complex z = z0;
    for (int t = 0; t < max; t++) {
        double fAbs = z.abs();
        if (fAbs > 2.0)
        {
             // based on the final value, add a fractional amount based on
             // how much it escaped by (fAbs will be in the range of 2 to around 4):                 
             return (float)t + (2.0f - (Math.log(fAbs) / Math.log(2.0)));
        }
        z =z.multiply(z).add(z0);
    }
    return (float)max;
}

最后,另一种对颜色给予最大自由度和控制的方法是使用 table 颜色,每次迭代使用一个颜色,并可选择在它们之间进行插值。