Skip to main content
edited title
Link

Mandelbrot fractalimage generator with parallel iteration

deleted 15 characters in body; edited tags; edited title
Source Link
200_success
  • 145.6k
  • 22
  • 191
  • 480

Optimize Mandelbrot and Bitmap SetPixelsfractal generator with parallel iteration

I'm currently trying to optimize this class I have for Fractalfractal generation, it's. The equation is meant to be able to plug in an equation, for thispluggable; I have setused z => z*z + c so that it's not using the Complex.Pow method (eliminating a method call per iteration). Without changing it from the Complex data type, how else can I optimize this method, and is there a better way I can set the colors in the bitmap? Methods shown below.

Optimize Mandelbrot and Bitmap SetPixels

I'm currently trying to optimize this class I have for Fractal generation, it's meant to be able to plug in an equation, for this I have set z => z*z + c so that it's not using the Complex.Pow method (eliminating a method call per iteration). Without changing it from the Complex data type, how else can I optimize this method, and is there a better way I can set the colors in the bitmap? Methods shown below.

Mandelbrot fractal generator with parallel iteration

I'm currently trying to optimize this class I have for fractal generation. The equation is meant to be pluggable; I have used z => z*z + c so that it's not using the Complex.Pow method (eliminating a method call per iteration). Without changing it from the Complex data type, how else can I optimize this method, and is there a better way I can set the colors in the bitmap? Methods shown below.

Source Link

Optimize Mandelbrot and Bitmap SetPixels

I'm currently trying to optimize this class I have for Fractal generation, it's meant to be able to plug in an equation, for this I have set z => z*z + c so that it's not using the Complex.Pow method (eliminating a method call per iteration). Without changing it from the Complex data type, how else can I optimize this method, and is there a better way I can set the colors in the bitmap? Methods shown below.

    public void Calculate()
    {
        var maxIterations = MaxIterations;
        var stopwatch = new Stopwatch();
        var histogram = new int[maxIterations];
        var width = Bitmap.Width;
        var height = Bitmap.Height;
        var iterationCount = new int[width, height];
        var colors = new Color[width, height];
        var epsilon = new Vector2((MaxBounds.X - MinBounds.X) / (width-1), (MaxBounds.Y - MinBounds.Y) / (height-1));
        var scale = new Vector2(1 / epsilon.X, 1 / epsilon.Y);
        var escapeRadiusSquared = EscapeRadius*EscapeRadius;

        stopwatch.Start();
        Parallel.ForEach(Multithreading.Iterate(MinBounds.X, MaxBounds.X, epsilon.X), cx =>
        {
            for (var cy = MinBounds.Y; cy < MaxBounds.Y; cy += epsilon.Y)
            {
                var iterations = 0;
                var c = new Complex(cx, cy);
                var z = StartingPoint(c);

                while (z.Real*z.Real + z.Imaginary*z.Imaginary < escapeRadiusSquared && iterations < maxIterations)
                {
                    z = Algorithm(z, c);
                    iterations++;
                }
                var xx = (int) Math.Round((cx - MinBounds.X)*scale.X);
                var yy = height - 1 - (int) Math.Round((cy - MinBounds.Y)*scale.Y);
                if (iterations >= maxIterations)
                {
                    colors[xx, yy] = Color.Black;
                }
                else if (SmoothingType == SmoothingType.Continuous || SmoothingType == SmoothingType.Smooth)
                {
                    for (var i = 0; i < 3; i++)
                    {
                        z = Algorithm(z, c);
                        iterations++;
                    }

                    var mu = iterations + 1 - Math.Log(Math.Log(z.Magnitude))/Math.Log(2);
                    if (SmoothingType == SmoothingType.Continuous)
                    {
                        mu = mu/ maxIterations * ColorPalette.Count;
                    }
                    colors[xx, yy] = ColorUtils.GetColor(mu, ColorPalette);
                }
                else if (SmoothingType == SmoothingType.None)
                {
                    colors[xx, yy] = iterations == maxIterations
                        ? Color.Black
                        : ColorPalette[iterations%ColorPalette.Count];
                }
                else if (SmoothingType == SmoothingType.Histogram)
                {
                    iterationCount[xx, yy] = iterations;
                    histogram[iterations]++;
                }
                else
                {
                    throw new ArgumentOutOfRangeException();
                }
            }
        });

        stopwatch.Stop();
        TimeElapsed = stopwatch.Elapsed;
        if (SmoothingType == SmoothingType.Histogram)
        {
            Parallel.ForEach(Multithreading.Iterate(MinBounds.X, MaxBounds.X, epsilon.X), cx =>
            {
                for (var cy = MinBounds.Y; cy < MaxBounds.Y; cy += epsilon.Y)
                {
                    var xx = (int)Math.Round((cx - MinBounds.X) * scale.X);
                    var yy = height - 1 - (int)Math.Round((cy - MinBounds.Y) * scale.Y);
                    var total = 0;
                    for (var i = 0; i < MaxIterations; i++)
                    {
                        total += histogram[i];
                    }

                    var hue = 0.0;
                    for (var i = 0; i < iterationCount[xx, yy]; i += 1)
                    {
                        hue += ((double)histogram[i])/total;
                    }
                    hue = Math.Round(hue*(ColorPalette.Count - 1));
                    colors[xx, yy] = ColorPalette[(int)hue];
                }
            });
        }
        FastBitmap.SetPixels(colors);
    }

And the FastBitmap class.

    public unsafe void SetPixels(Color[,] colors)
    {
        var data = Bitmap.LockBits(new Rectangle(0, 0, Bitmap.Width, Bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
        var scan0 = data.Scan0;
        var width = colors.GetLength(0);
        var height = colors.GetLength(1);

        Parallel.For(0, width, x =>
        {
            for (var y = 0; y < height; y++)
            {
                var color = colors[x, y];
                var imagePointer = (byte*) scan0.ToPointer(); // Pointer to first pixel of image
                var offset = y*data.Stride + 3*x; // 3x because we have 24bits/px = 3bytes/px
                var px = imagePointer + offset; // pointer to the pixel we want
                px[0] = color.B; // Red component
                px[1] = color.G; // Green component
                px[2] = color.R; // Blue component
            }
        });

        Bitmap.UnlockBits(data); // Set the data again
    }

Multithreading.Iterate:

public static class Multithreading
{
    public static IEnumerable<double> Iterate(
        double fromInclusive, double toExclusive, double step)
    {
        for (var d = fromInclusive; d < toExclusive; d += step) yield return d;
    }
}