Abdul Fatir
Abdul Fatir

Reputation: 6357

Coloring the Barnsley Fern fractal

While rendering the Barnsley fern fractal I come up with single color images or at most four color images i.e. the bottom left, bottom right, bottom stem and the rest of the leaves. Here is the image I get for example:

My fern

What I want however is to bring shades in the leaves and making stem thicker and of different color like:

The fern example I want

I digged a bit about the algorithms that can be used, then I read in Draves's paper about fractal flames that during iteration of Iterated Function Systems a single point may be rendered many times if we use a single color which results in a loss of information so we need to create a histogram of how many times a point was to be rendered and then perform a rendering pass using the histogram with shades of colors log-density coloring.

I have brought myself to the point where I have the histogram but don't know how to use it to render the shades or using the log-density render technique. Can someone help me with such type of rendering or at least direct me to a source where I can read more about this with practical examples.

Here is what I have tried:

AffineTransformation f1 = new AffineTransformation(0,0,0,0.25,0,-0.4);
AffineTransformation f2 = new AffineTransformation(0.95,0.005,-0.005,0.93,-0.002,0.5);
AffineTransformation f3 = new AffineTransformation(0.035,-0.2,0.16,0.04,-0.09,0.02);
AffineTransformation f4 = new AffineTransformation(-0.04,0.2,0.16,0.04,0.083,0.12);
int N=Width*Height;
int pixelhistogram[] = new int[N];
for(int i=0;i< N*25;i++)
{
    Point newpoint = new Point();
    double probability = Math.random();
    if(probability < 0.01)
    {
        newpoint = f1.transform(point);
    }
    else if(probability < 0.94)
    {
        newpoint = f2.transform(point);
    }
    else if(probability < 0.97)
    {
        newpoint = f3.transform(point);
    }
    else
    {
        newpoint = f4.transform(point);
    }
    point = newpoint;
    // Translating the point to pixel in the image and 
    // incrementing that index in the pixelHistogram array by 1
            // W and H are the Width and Height
    int X=((int)(point.getX()*W/3)+W/2)/2 + W/4-1;
    int Y=H-((int)(point.getY()*H/8) + H/9) -1;
    pixelhistogram[W*Y+X]++;
}
// Now that I have the pixelhistogram
// I don't know how to render the shades using this  

AffineTransformation is a simple class which performs Affine Transformation on a point. I omitted the code because otherwise the question would have become too lengthy.

Upvotes: 1

Views: 2165

Answers (1)

Marc Coram
Marc Coram

Reputation: 56

A simple coloring would be to render pixel (X,Y) light green, green, or brown according to whether pixels[W*Y+X] is less than n1, between n1 and n2, or greater than n2. To determine n1 and n2, trial and error would probably be the simplest solution, but you could make an actual histogram of the log of the pixel counts that you have recorded to help judge where to put the cuts (or more generally you could use clustering algorithms to do it automatically).

PS: In the image that you show it looks like the stem is rendered with an L-system and the fronds are rendered using the three leaf transforms only (i.e. omit the fourth "stem-transform"); I would guess they are using the log pixel counts to shade the level of green but not to shade the stem.

Addition: I was asked, below, to discuss log-histograms. To avoid getting bogged down, I'd recommend first using a full featured data analysis software like R to see if this gets you what you want. Write out the pixels array to a text file with one number per line, then start R and run:

ct=scan('pixels_data.txt')
hist(log(ct))

If you see a a multimodal histogram (i.e. if it has clear peaks and valleys), that will suggest how to choose n1 and n2: put them in the valleys (i.e. if the valley on the plot is at y, set n1=exp(y)).

If you wind up plotting histograms in Java, it can apparently be done with the Jfreechart software. Just create an array with the logs of the values in the pixels array and create the histogram out of that.

At best I expect you to see only one valley in the histogram, if you use the standard 3-transform Barnsley fern, separating the really high stem values from the fronds. To color the fronds, if n is the cut between frond and stem, and pixels[W*Y+X] is less than n, you could color it using, say:

v=128.0*(log(n)-log(pixels[W*Y+X]))/log(n);
RGB=(v,255,v)

PS: Getting thick stems using the random iteration algorithm only is going to be a problem. If you change the 3rd transform to be less singular, your stems will wind up looking like thin ferns and not sticks. E.g.

{"title":"Thick Stem Fern","alist":[[
[0.11378443003074948,-0.005060836319767042,0.013131296101198788,0.21863066144310556,0.44540023470694723,0.01726296943557673],
[0.15415337683611596,-0.17449052243042712,0.23850452316465576,0.2090228040695959,0.3652068203134602,0.11052918709831461],
[-0.09216684947824424,0.20844742602316002,0.2262266208270773,0.22553569847678284,0.6389950926444947,-0.008256440681230735],
[0.8478159879190097,0.027115858923993468,-0.05918196850293869,0.8521840120809901,0.08189073762585078,0.1992198482087391]
]],"va":[1,0,0,1,0,0],"word_length":6,"level_max":40,"rect_size":1}

Is the json data to describe:

Thick Stem Fern

Upvotes: 4

Related Questions