How to improve buddhabrot color?

  • 7 Replies
  • 320 Views

0 Members and 1 Guest are viewing this topic.

Offline Naografix

  • *
  • Fractal Freshman
  • *
  • Posts: 1
« on: January 11, 2019, 10:22:32 AM »
Hey!

I'm new in fractal and currently, I'm trying to generate buddhabrot in color.
I got a good version of my buddha, but I find colors are a little bland:

How can I improve my colors? (I'm trying to get this render: https://urlz.fr/8Cqk )
I'm working with https://processing.org/ and this is my code:
Thank you for your help.


Code: [Select]
int resolution = 1024;
int[][] pixelArray = new int[resolution*resolution][3];

float realMin = -1.6;
float realMax = 0.8;
float imaginaryMin = -1.2;
float imaginaryMax = 1.2;
float escapeOrbit = 4;
PVector minColor = new PVector(200, 50, 1);
PVector maxColor = new PVector(5000, 500, 100);
                         //red        green         blue
int minIter = round(min(minColor.x, minColor.y, minColor.z));
int maxIter = round(max(maxColor.x, maxColor.y, maxColor.z));

boolean process = true;
int iterations = 1600000;

int maxfound = 0;
int maxfoundR = 0;
int maxfoundG = 0;
int maxfoundB = 0;

float luminosity = 1.2;

void setup() {
  size(1024, 1024);
  background(0);
}

void draw() {
  if (process) {
    for (int i = 0; i < iterations; i++) {
      buddhabrot(realMin, realMax, imaginaryMin, imaginaryMax, minIter, maxIter, escapeOrbit, minColor, maxColor);

      if (i >= iterations - 1) {
        process = false;
      }
    }
  } else {
    drawBuddha();
  }
}

void drawBuddha() {

  loadPixels();

  maxfound = max(maxfoundR, maxfoundG, maxfoundB);

  float maxSqrtR = sqrt(maxfoundR);
  float maxSqrtG = sqrt(maxfoundG);
  float maxSqrtB = sqrt(maxfoundB);

  for (int i = 0; i < width * height; i++)
  {
    int colorR = round( min(  (sqrt(pixelArray[i][0]) / maxSqrtR * 255.0) * luminosity, 255));
    int colorG = round( min(  (sqrt(pixelArray[i][1]) / maxSqrtG * 255.0) * luminosity, 255));
    int colorB = round( min(  (sqrt(pixelArray[i][2]) / maxSqrtB * 255.0) * luminosity, 255));

    pixels[i] = color(colorR, colorG, colorB);
  }

  updatePixels();
  process = true;
}

boolean isInMandlebrot(float cr, float ci, int maxIter, float escapeOrbit) {
  int iter = 0;
  float zr = 0.0;
  float zi = 0.0;
  float ci2 = ci*ci;
  float temp;

  //Quick rejection check if c is in 2nd order period bulb
  if ( (cr+1.0) * (cr+1.0) + ci2 < 0.0625) return true;

  //Quick rejection check if c is in main cardioid
  float q = (cr-0.25)*(cr-0.25) + ci2;
  if ( q*(q+(cr-0.25)) < 0.25*ci2) return true;


  // test for the smaller bulb left of the period-2 bulb
  if (( ((cr+1.309)*(cr+1.309)) + ci*ci) < 0.00345) return true;

  // check for the smaller bulbs on top and bottom of the cardioid
  if ((((cr+0.125)*(cr+0.125)) + (ci-0.744)*(ci-0.744)) < 0.0088) return true;
  if ((((cr+0.125)*(cr+0.125)) + (ci+0.744)*(ci+0.744)) < 0.0088) return true;

  while ( (iter < maxIter) && ((zr*zr+zi*zi) < escapeOrbit) )
  {
    temp = zr * zi;
    zr = zr*zr - zi*zi + cr;
    zi = temp + temp + ci;
    iter++;
  }

  if ( iter < maxIter)
  {
    return false;
  } else {
    return true;
  }
}


void buddhabrot(float realMin, float realMax, float imaginaryMin, float imaginaryMax, int minIter, int maxIter, float escapeOrbit, PVector minColor, PVector maxColor)
{
  float x0 = random( -2, 2 );
  float y0 = random( -2, 2 );

  float deltaReal = (realMax - realMin);
  float deltaImaginary = (imaginaryMax - imaginaryMin);

  float cr = realMin + (realMax - realMin) * x0;
  float ci = imaginaryMin + (imaginaryMax - imaginaryMin) * y0;

  int x, y;
  int iter   = 0;
  float zr   = 0.0;
  float zi   = 0.0;
  float temp = 0.0;


  if ( isInMandlebrot(cr, ci, maxIter, escapeOrbit) == false)
  {   
    while ( (iter < maxIter) && ((zr*zr+zi*zi) < escapeOrbit) )
    {
      temp = zr * zi;
      zr = zr*zr - zi*zi + cr;
      zi = temp + temp + ci;

      x = round(((width) * (zr - realMin) / deltaReal));
      y = round(((height) * (zi - imaginaryMin) / deltaImaginary));

      if ( (iter > minIter) && (x>0) && (y>0) && (x<width) && (y<height) )
      {
        if ( (iter > minColor.x) && (iter < maxColor.x) ) {
          pixelArray[x + (y * width)][0]++;

          //Max red
          if (pixelArray[x + (y * width)][0] > maxfoundR) {
            maxfoundR = round(pixelArray[x + (y * width)][0]);
          }
        }
        if ( (iter > minColor.y) && (iter < maxColor.y) ) {
          pixelArray[x + (y * width)][1]++;

          //Max green
          if (pixelArray[x + (y * width)][1] > maxfoundG) {
            maxfoundG = round(pixelArray[x + (y * width)][1]);
          }
        }
        if ( (iter > minColor.z) && (iter < maxColor.z) ) {
          pixelArray[x + (y * width)][2]++;

          //Max blue
          if (pixelArray[x + (y * width)][2] > maxfoundB) {
            maxfoundB = round(pixelArray[x + (y * width)][2]);
          }
        }
      }
      iter++;
    }
  }
}

Offline Softology

  • *
  • Fractal Fanatic
  • ***
  • Posts: 38
« Reply #1 on: January 13, 2019, 09:04:28 PM »
Try tweaking brightness and contrast after you get your final RGB color values.

A quick edit of brightness and contrast of your image in GIMP got this result much closer to your desired outcome.
https://ibb.co/VD6RMwx

Offline tavis

  • *
  • Fractal Friend
  • **
  • Posts: 13
  • Bill Tavis
    • Mandelmap poster
« Reply #2 on: January 26, 2019, 01:01:24 PM »
I would recommend adjusting your iteration ranges per color. Right now your render has a lot of white and gray, which implies that the same pixels are being colored in each color channel.  It looks like your limit for the blue channel is 100. I isolated the blue channel in the picture you want to emulate, and it's hard to say exactly what it is but it's definitely a lot less that 100, probably more in the range of 25-50.  In my opinion there is not a need to overlap the ranges either, as I think this is adding to the gray.
Check out the Mandelmap poster

Offline claude

  • *
  • 3d
  • ****
  • Posts: 972
    • mathr.co.uk
« Reply #3 on: January 26, 2019, 03:22:46 PM »
You are plotting the buddhabrot in an unusual way, I think.  I think the usual way is to choose the colour channel 1x per orbit, based on the final iteration count, instead of plotting different channels as the orbit proceeds.

You have:
Code: [Select]
if ( isInMandlebrot(cr, ci, maxIter, escapeOrbit) == false)
    while ( (iter < maxIter) && ((zr*zr+zi*zi) < escapeOrbit) )
      if ( (iter > minIter) && (x>0) && (y>0) && (x<width) && (y<height) )
        if ( (iter > minColor.x) && (iter < maxColor.x) ) {
          PLOT RED
        if ( (iter > minColor.y) && (iter < maxColor.y) ) {
          PLOT GREEN
        if ( (iter > minColor.z) && (iter < maxColor.z) ) {
          PLOT BLUE

Should probably be:
Code: [Select]
if ( (count = isInMandlebrotCount(cr, ci, maxIter, escapeOrbit)) < maxiter)
    while ( (iter < maxIter) && ((zr*zr+zi*zi) < escapeOrbit) )
      if ( (iter > minIter) && (x>0) && (y>0) && (x<width) && (y<height) )
        if ( (count > minColor.x) && (count < maxColor.x) ) {
          PLOT RED
        if ( (count > minColor.y) && (count < maxColor.y) ) {
          PLOT GREEN
        if ( (count > minColor.z) && (count < maxColor.z) ) {
          PLOT BLUE

In my own Buddhabrot renderer I have many channels (up to 29 or 30, if I remember correctly) and do something like
Code: [Select]
          PLOT channel[log2(count)]then there are more possibilities for colouring.  But you need many many points for the higher channels to get smooth (not be dominated by a few isolated orbits)

Offline Sharkigator

  • *
  • Fractal Friend
  • **
  • Posts: 17
« Reply #4 on: January 26, 2019, 09:58:41 PM »
You are plotting the buddhabrot in an unusual way, I think.  I think the usual way is to choose the colour channel 1x per orbit, based on the final iteration count, instead of plotting different channels as the orbit proceeds.

Actually, in Buddhabrot Mag, I do it the same way he does.


In general, if you want to make it look sharper, you can try skip drawing the first few (e. g. 10 or 100) pixels/points per orbit.
That will allow it to "warm up", and the background glow goes away.

Offline claude

  • *
  • 3d
  • ****
  • Posts: 972
    • mathr.co.uk
« Reply #5 on: January 30, 2019, 06:11:29 PM »
Actually, in Buddhabrot Mag, I do it the same way he does.
Oh!  It seems we are both different to the classical technique? Wikipedia says (and http://superliminal.com/fractals/bbrot/bbrot.htm says something similar):
Quote
For example, one could assign a 2,000 max iteration image to the red channel, a 200 max iteration image to the green channel, and a 20 max iteration image to the blue channel of an image in an RGB color space.
which implies that a point that escapes at 100 iterations would have all its iterates plotted in the red (escape count 0 - 2000) and green (escape count 0 - 200) channels, but none in the blue (escape count 0 - 20) channel. My method would plot all iterates of the 100 iter point only in the green channel (escape count 20 - 200), with (escape count 0-20) for blue and (escape count 200-2000) for red.

I suppose your method might reduce the hard edges I get from my method?  Also providing a way to reduce "low iteration fog"?

Offline tavis

  • *
  • Fractal Friend
  • **
  • Posts: 13
  • Bill Tavis
    • Mandelmap poster
« Reply #6 on: January 30, 2019, 10:27:09 PM »
Quote
I suppose your method might reduce the hard edges I get from my method?
  If I understand what you are referring to, the hard edges are caused by low iteration limits. A limit as low as 20 like you described would definitely run into this problem. Think about what the border of the Mandelbrot set looks like with only 20 iterations - you still see smooth curves, and this is what the hard edges in the Buddhabrot are made of. In my experience, skipping the first iteration or two does not resolve the issue. I considered having a variable limit to solve this problem i.e. you test to see if the point escapes in 20 + randomOffset iterations, but I have not actually tried implementing this yet... I find that using a limit of around 50 is high enough to eliminate most of the hard edge artifacts while still looking fairly low (not hitting the origin and very foggy). I like the fog, personally  ;D

As far as the coloring goes, I don't know if there needs to be a definite "right" way to do it, but in the case of the example that the OP wants to emulate I would say that the points are being plotted like Claude described

Offline FractalStefan

  • *
  • Fractal Fanatic
  • ***
  • Posts: 20
    • JavaScript Mandelbrot Generator & More (in German)
« Reply #7 on: January 31, 2019, 09:36:21 PM »
You could try to combine several single images to one, each of them representing a different color channel (see here).
I tried this method only for "buddhabrot" images that consist of only a few, but long "Z orbits".


xx
Buddhabrot Mag(nifier) - A realtime buddhabrot zoomer

Started by Sharkigator on Other

15 Replies
1383 Views
Last post December 23, 2017, 08:00:35 PM
by Fraktalist
xx
Buddhabrot

Started by Bill Snowzell on Fractal Image Gallery

0 Replies
195 Views
Last post October 12, 2017, 09:53:06 PM
by Bill Snowzell
xx
Buddhabrot

Started by FractalStefan on Image Threads

3 Replies
351 Views
Last post February 26, 2018, 11:28:21 PM
by FractalStefan
clip
Variations on the Buddhabrot

Started by AlexH on Fractal Mathematics And New Theories

8 Replies
617 Views
Last post February 11, 2019, 12:01:03 PM
by AlexH
xx
A Buddhabrot animation

Started by F. Bernkastel on Fractal movie gallery

5 Replies
449 Views
Last post April 20, 2018, 02:55:35 PM
by F. Bernkastel