Welcome to Fractal Forums

Fractal Software => Programming => Topic started by: kronikel on November 21, 2010, 08:33:49 PM




Title: Determining color
Post by: kronikel on November 21, 2010, 08:33:49 PM
Could anyone give me a little example code for finding out what color to make a pixel after finding out its number of "iterations"?

I use
Code:
Color:= HSLToColor(Iterations * CAmount, 100, 50);
This produces a very "pure" color. Full saturation, medium brightness, and a hue based on the iteration.
The Iterations is of course the number of loops for the pixel.
The CAmount is the important part, and this is what will make the image look nice and clean or all pixelated.

Hue is anything from 0-100.
So my first thought was make it where CAmount was (100 / x) where x = the highest iteration found in the image.
This gives every iteration a different number, 0-100.
It works great for lower zooms but as you zoom in a bit there is a problem.
After some debugging I saw that when zoomed in a bit there is a massive difference between the "average iteration" found and the "max iteration" found.
The average might be only 35 while the highest one found could be something like 1000.
So assigning each iteration a hue from 0-100 won't fully work.

There is usually a certain CAmount that makes any rendering look nice and clean but I'm not quite seeing the pattern.
I would either like to figure this out or just find an easier way to assign a color.


Title: Re: Determining color
Post by: jwm-art on November 21, 2010, 10:06:41 PM
An oft used method is to use the iteration count to look-up a colour in an array. If you have 256 colours in the array, then the modulus of the iteration count with 256 is used so that when the iteration count is above 256 the colours wrap around again. The colours you put in the array is up to you.


Title: Re: Determining color
Post by: kronikel on November 22, 2010, 12:17:15 AM
I see what you are saying but using HSLToColor works exactly the same.
For example if the outcome of (Iterations * CAmount) is 173, you would have
HSLToColor(173, 100, 50). It is above 100 so it automatically wraps around and makes the same color as HSLToColor(73, 100, 50)
So any number, even 20945820958 can be plugged into it.


Title: Re: Determining color
Post by: jwm-art on November 22, 2010, 12:45:57 AM
I see what you are saying but using HSLToColor works exactly the same.
For example if the outcome of (Iterations * CAmount) is 173, you would have
HSLToColor(173, 100, 50). It is above 100 so it automatically wraps around and makes the same color as HSLToColor(73, 100, 50)
So any number, even 20945820958 can be plugged into it.

It doesn't work exactly the same because you're not calculating the colour you're translating the iteration count to an array index looking the colour up (ie fractint colour maps). You said the way you're using doesn't work for you and that the results are too saturated. Using a palette to look-up colours allows you to choose exactly the colours to use - and you don't need to worry about working out the minimum and maximum iterations for the image (unless you want to automatically scale the colour palette I guess).


Title: Re: Determining color
Post by: kronikel on November 22, 2010, 02:43:16 AM
You're not understanding.
And my colors aren't too saturated, I'm not sure where you got that.
I know the problem but explaining it is hard so here is a picture.

If you look at all the iterations that were found for the whole image most of them would be around the same number, but as you get really close the the black area the iterations become very distant from the "average iteration" found.
If there were a decent way to just set the color of those pixels to the color of the highest iteration that was commonly found it would fix the problem.

Edit:
Ok making that picture into a .jpg actually made it look not half bad because it made it lose a lot of detail so it's not the best example.
But the closer you get to the black area the more pixelated it gets.


Title: Re: Determining color
Post by: jwm-art on November 22, 2010, 09:55:05 AM
Ok I understand now. I think you will be wanting something called Oversampling (http://en.wikipedia.org/wiki/Oversampling) sometimes also referred to as anti-aliasing. The basic principle is to render a higher resolution image and then down-sample it.

Take a look here:
http://www.fractalforums.com/programming/antialiasing-fractals-how-best-to-do-it/


Title: Re: Determining color
Post by: kronikel on November 22, 2010, 07:18:28 PM
Awesome, after putting "anti aliasing" into wikipedia sure enough I found some before and after pictures of fractals that had been anti alias'd.
The before looked exactly like my problem and the after looked nice.

Thanks for the help and everyone else who has helped me get as far as I have.


Title: Re: Determining color
Post by: kronikel on November 22, 2010, 07:46:54 PM
Ok what I found on that post has me completely confused now.
This looks like what I need though-
Quote
a very simple and effective way to antialias the heightmap is via supersampling: instead of just using 1 sample per heightmap value, divide each "region" of your M x N map into K x K subregions (effectively enlarging it by a factor of K in each dimension, but you don't store all those values) which you evaluate and average to produce your final heightmap value. this is a simple way to bandlimit your signal, discarding all high frequency data that cannot be represented at the current sampling frequency (i.e. above the nyquist limit).

Code:
for (y = 0; y < yres; ++y)
for (x = 0; x < xres; ++x)
{
float r = 0.0f, g = 0.0f, b = 0.0f;

for (v = 0; v < supersample_factor; ++v)
for (u = 0; u < supersample_factor; ++u)
{
float fx = float(x) + float(u) / float(supersample_factor);
float fy = float(y) + float(v) / float(supersample_factor);

colour eval = pixel_function(fx,fy);

r += eval.r;
g += eval.g;
b += eval.b;
}

r /= float(supersample_factor * supersample_factor);
g /= float(supersample_factor * supersample_factor);
b /= float(supersample_factor * supersample_factor);

imagedata[y * xres + x].set(r,g,b);
}

I don't understand how to implement this in my code at all.

Edit:
After some reading I still don't understand that code at all but I think I get SuperSampling.
You take the pixels that have the high iterations that are giving the image the "noise" and zoom in on those, calculate the colors that are around that pixel, then the color is an average of those colors.
That sounds extremely slow to me though unless I'm not thinking of it correctly.


Title: Re: Determining color
Post by: ker2x on November 22, 2010, 08:24:42 PM
That sounds extremely slow to me though unless I'm not thinking of it correctly.

You're thinking correctly \o/
Supersampling is insanely slow  :angry:


Title: Re: Determining color
Post by: kronikel on November 22, 2010, 08:44:24 PM
So that's probably not the way I'm going o.O
My program is already slow.
Any ideas on anti aliasing anyone?


Title: Re: Determining color
Post by: jwm-art on November 22, 2010, 09:13:15 PM
So that's probably not the way I'm going o.O
My program is already slow.
Any ideas on anti aliasing anyone?

Can you time your program so we have an idea of how slow 'slow' is? What language are you using, what hardware is it running on?

For example, how long does it take your program to render the default view of the Mandelbrot set?

Slowness is just something you have to put up with, with fractals unfortunately.


Title: Re: Determining color
Post by: kronikel on November 22, 2010, 10:22:00 PM
It is basically written in delphi but I use a compiler called scar to execute the code.
Scar is not meant for this being the reason it is slow.
Scar compiles code then runs it, which is a lot slower than something precompiled.
I did however make a plugin for the function that counts the iterations of a pixel, so when that function is called it is precompiled and executed in delphi rather than scar and saves a lot of time, but the whole code can't exactly be done like that.
I need to learn more c and I could easily have it running quickly.
The start view of the Mset only takes maybe 2 seconds to render.
Some deeper zooms might take 5-10 seconds.
I keep my render size at 100x100 though which is quite small.
500x500 takes forever.

Also I think anti aliasing might not be my answer.
I took a loot at the color mapping techniques by hpdz and that could work too.
Right now I'm trying to implement "Rank-order" mapping.


Title: Re: Determining color
Post by: kronikel on November 23, 2010, 02:12:39 AM
Now I'm trying "histogram" mapping
Can anyone elaborate on
Code:
J(x) = Sum[H(i), i=0 to x]
u = J(x) / NUM
The 2nd line makes sense.
For the first one I believe Sum adds together a part of an array of numbers.
And I'm really not sure what to do.


Title: Re: Determining color
Post by: jwm-art on November 23, 2010, 02:29:17 AM
Now I'm trying "histogram" mapping
Can anyone elaborate on
Code:
J(x) = Sum[H(i), i=0 to x]
u = J(x) / NUM
The 2nd line makes sense.
For the first one I believe Sum adds together a part of an array of numbers.
And I'm really not sure what to do.

It looks like u is an average of all values in array H, ie NUM is the number of elements in array - at a vaguely informed guess!


Title: Re: Determining color
Post by: kronikel on November 23, 2010, 02:42:23 AM
It is from this article http://www.hpdz.net/TechInfo_Colorizing.htm#IndexDistribution
Where it tells about histogram mapping.
and NUM is "the total number of points in the image (outside the set)"
It doesn't give a lot of info really.


Title: Re: Determining color
Post by: Duncan C on January 21, 2011, 08:00:20 PM
I see what you are saying but using HSLToColor works exactly the same.
For example if the outcome of (Iterations * CAmount) is 173, you would have
HSLToColor(173, 100, 50). It is above 100 so it automatically wraps around and makes the same color as HSLToColor(73, 100, 50)
So any number, even 20945820958 can be plugged into it.

This is an old post. Not sure if you're still looking for updates.

What you need to do is come up with a non-linear mapping from iteration number to pixel color.

The rate of change in iteration value over distance for high iteration pixels is MUCH higher than the rate of change for low iteration pixels. If you use a linear color change, the color change is too gradual at low iteration values and way too large for high iteration areas. As a result, the highest iteration parts of your plot get a riot of colors that your eyes can't make sense of.

It helps if you come up with a scheme where you generate a value from 0 to 1. At 0, you use the starting color. At 1, you use the end color.

One way to handle it is to use the log of the iteration number to calculate the color from start color to end color. You need a way to normalize the numbers so you can plot from start color to end color.


If you calculate the log of the lowest iteration value in the plot {log(min_iterations)}, and the log of the highest iteration in the plot {log(max_iterations)}, you can then calculate the color value for any pixel with color = (log(pixel_iteration) = log(min_iterations)) / (log(max_itrations) - log(min_iterations))

That gives you a value that varies from 0 to 1, where the value changes quite rapidly at the low iteration ranges in your plot, and much more slowly at higher iteration values, and thus reduces the amount of visual noise for high iteration pixels.

As the article you link says, an even better way is to use a histogram of the iteration counts in the image to calculate a color value. For any given pixel, you can use something like:

color = (sum of pixel count for all iteration values < pixel_iterations) / total_non_mandelbrot_pixels_in_plot.

That way, the lowest iteration pixel in the plot gets a color value of 0 (starting color.) The highest iteration non_mandelbrot pixel in the plot gets a color value of 1 (end color) and pixels in-between get a color that's proportional to the total number of pixels with a lower iteration value. This does a great job of evenly distributing color values.

I took a stab at recreating your plot using histogram-based colors in my App, FractalWorks. Here's the result:

(http://www.pbase.com/duncanc/image/131989217/original.jpg)