Adding color layers to the mandelbrot set
Asked Answered
H

1

6

I have a great interest in fractals but did not have the opportunity to implement them until recently. I first implemented a mandelbrot set in black and white then I tried to add colors to it.

Here is my mandelbrot's implementation (I am using org.apache.commons.math3.complex.Complex for complex numbers)

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();
    }

}

I am using a custom Viewer class to view the set after drawing it in an image object. Here is the set method of the Viewer

 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());
}

The code is rendering the set correctly but I am not obtaining the expected result. What I want is to be able to produce a colored set similar to these

beautiful mandelbrot

Or this

Beautiful mandelbrot II

But I could not get a better colored set than this.

not very beautiful mandelbrot

I have read some theorical explanation about it here and here, but I am obviously doing something wrong in practice. What is wrong with my coloring approach? How can I fix it? Thanks

Halfcock answered 16/4, 2015 at 2:34 Comment(0)
S
4

In the examples you show, the color is just based on the number of iterations before the point escapes, and not on the initial complex co-ordinate z0. One approach is to use Hue-Saturation-Brightness color values using getHSBColor(), and change the hue based on the number of iterations before it escapes, e.g:

        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);

The code above doesn't change the saturation or the brightness (both are set to 1.0) but you could vary them as well depending on what kind of effect you want.

You could make the color cycle through the color circle of hues more than once by multiplying the hue value by a constant e.g:

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

You can also add a constant to make it start at a particular color.

Because escapeIterations is an int, the color will jump in steps for each iteration. You can make the colors smoother by returning a float from 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;
}

Lastly, another approach that will give the most freedom and control over the colors is to use a table of colors, one for each iteration up the maximum, and optionally interpolate between them.

Selfrestraint answered 16/4, 2015 at 2:55 Comment(2)
OK, let me apply this in a minutes and I will be backHalfcock
thank you for the additional explanations, I will play with it.Halfcock

© 2022 - 2024 — McMap. All rights reserved.