algorithm - fractales - mandelbrot biografia
Espectro suave para la representaciĆ³n del conjunto de Mandelbrot (6)
Utilice el algoritmo de coloreo uniforme para calcular todos los valores dentro de la ventana gráfica, luego asigne su paleta del valor más bajo al más alto. Por lo tanto, al acercarse y los valores más altos ya no son visibles, la paleta también se reducirá. Con las mismas constantes para ny B, terminará con un rango de 0.0 a 1.0 para un conjunto completamente alejado, pero a un zoom más profundo el rango dinámico se encogerá, para decir 0.0 a 0.1 con un zoom de 200%, 0.0 a 0.0001 en 20000% de zoom, etc.
Actualmente estoy escribiendo un programa para generar imágenes de Mandelbrot realmente enormes (65536x65536 píxeles o más), y me gustaría diseñar un esquema de espectro y coloreado que les haga justicia. La imagen de mandelbrot presentada en wikipedia parece un ejemplo excelente, especialmente cómo la paleta sigue siendo variada en todos los niveles de zoom de la secuencia. Sin embargo, no estoy seguro de si está girando la paleta o haciendo algún otro truco para lograrlo.
Estoy familiarizado con el algoritmo de coloración uniforme para el conjunto de mandelbrot, por lo que puedo evitar las bandas, pero aún necesito una forma de asignar colores a los valores de salida de este algoritmo.
Las imágenes que estoy generando son piramidales (por ejemplo, una serie de imágenes, cada una de las cuales tiene la mitad de las dimensiones que la anterior), así que puedo usar una paleta giratoria de algún tipo, siempre que el cambio en la paleta entre las siguientes los niveles de zoom no son demasiado obvios.
Parece simple de hacer por ensayo y error. Supongamos que puede definir HSV1 y HSV2 (matiz, saturación, valor) de los colores del punto final que desea usar (blanco y negro, azul y amarillo, rojo oscuro y verde claro, etc.), y suponga que tiene un algoritmo para asignar un valor P entre 0.0 y 1.0 para cada uno de sus píxeles. Entonces el color de ese pixel se convierte
(H2 - H1) * P + H1 = HP
(S2 - S1) * P + S1 = SP
(V2 - V1) * P + V1 = VP
Una vez hecho esto, solo observe los resultados y vea cómo le agradan. Si el algoritmo para asignar P es continuo, entonces el gradiente debería ser uniforme también.
Mi solución final fue crear una paleta de aspecto agradable (y bastante grande) y almacenarla como una matriz constante en la fuente, luego interpolar entre los índices utilizando el algoritmo de coloreo uniforme. La paleta se ajusta (y está diseñada para ser continua), pero esto no parece importar mucho.
Este es el algoritmo de color suave:
Digamos que comienzas con el número complejo z0
e iteras n
veces hasta que escapa. Deje que el punto final sea zn
.
Un valor sin problemas sería
nsmooth := n + 1 - Math.log(Math.log(zn.abs()))/Math.log(2)
Esto solo funciona para mandelbrot, si quieres calcular una función suave para julia sets, usa
Complex z = new Complex(x,y);
double smoothcolor = Math.exp(-z.abs());
for(i=0;i<max_iter && z.abs() < 30;i++) {
z = f(z);
smoothcolor += Math.exp(-z.abs());
}
Entonces smoothcolor
está en el intervalo (0,max_iter)
.
Divida smoothcolor
con max_iter
para obtener un valor entre 0 y 1.
Para obtener un color suave a partir del valor:
Esto se puede llamar, por ejemplo (en Java):
Color.HSBtoRGB(0.95f + 10 * smoothcolor ,0.6f,1.0f);
ya que el primer valor en los parámetros de color HSB se usa para definir el color del círculo de color.
aquí puedes encontrar una versión con javascript
uso:
var rgbcol = [] ;
var rgbcol = MapColor ( Iteration , Zy2,Zx2 ) ;
point ( ctx , iX, iY ,rgbcol[0],rgbcol[1],rgbcol[2] );
función
/*
* The Mandelbrot Set, in HTML5 canvas and javascript.
* https://github.com/cslarsen/mandelbrot-js
*
* Copyright (C) 2012 Christian Stigen Larsen
*/
/*
* Convert hue-saturation-value/luminosity to RGB.
*
* Input ranges:
* H = [0, 360] (integer degrees)
* S = [0.0, 1.0] (float)
* V = [0.0, 1.0] (float)
*/
function hsv_to_rgb(h, s, v)
{
if ( v > 1.0 ) v = 1.0;
var hp = h/60.0;
var c = v * s;
var x = c*(1 - Math.abs((hp % 2) - 1));
var rgb = [0,0,0];
if ( 0<=hp && hp<1 ) rgb = [c, x, 0];
if ( 1<=hp && hp<2 ) rgb = [x, c, 0];
if ( 2<=hp && hp<3 ) rgb = [0, c, x];
if ( 3<=hp && hp<4 ) rgb = [0, x, c];
if ( 4<=hp && hp<5 ) rgb = [x, 0, c];
if ( 5<=hp && hp<6 ) rgb = [c, 0, x];
var m = v - c;
rgb[0] += m;
rgb[1] += m;
rgb[2] += m;
rgb[0] *= 255;
rgb[1] *= 255;
rgb[2] *= 255;
rgb[0] = parseInt ( rgb[0] );
rgb[1] = parseInt ( rgb[1] );
rgb[2] = parseInt ( rgb[2] );
return rgb;
}
// http://.com/questions/369438/smooth-spectrum-for-mandelbrot-set-rendering
// alex russel : http://.com/users/2146829/alex-russell
function MapColor(i,r,c)
{
var di= i;
var zn;
var hue;
zn = Math.sqrt(r + c);
hue = di + 1.0 - Math.log(Math.log(Math.abs(zn))) / Math.log(2.0); // 2 is escape radius
hue = 0.95 + 20.0 * hue; // adjust to make it prettier
// the hsv function expects values from 0 to 360
while (hue > 360.0)
hue -= 360.0;
while (hue < 0.0)
hue += 360.0;
return hsv_to_rgb(hue, 0.8, 1.0);
}
Aquí hay un bucle interno típico para un ingenuo generador de Mandelbrot. Para obtener un color uniforme, desea pasar las "longitudes" reales y complejas y la iteración en la que rescató. He incluido el código de Mandelbrot para que pueda ver qué vars usar para calcular el color.
for (ix = 0; ix < panelMain.Width; ix++)
{
cx = cxMin + (double )ix * pixelWidth;
// init this go
zx = 0.0;
zy = 0.0;
zx2 = 0.0;
zy2 = 0.0;
for (i = 0; i < iterationMax && ((zx2 + zy2) < er2); i++)
{
zy = zx * zy * 2.0 + cy;
zx = zx2 - zy2 + cx;
zx2 = zx * zx;
zy2 = zy * zy;
}
if (i == iterationMax)
{
// interior, part of set, black
// set colour to black
g.FillRectangle(sbBlack, ix, iy, 1, 1);
}
else
{
// outside, set colour proportional to time/distance it took to converge
// set colour not black
SolidBrush sbNeato = new SolidBrush(MapColor(i, zx2, zy2));
g.FillRectangle(sbNeato, ix, iy, 1, 1);
}
y MapColor a continuación: (vea este enlace para obtener la función ColorFromHSV )
private Color MapColor(int i, double r, double c)
{
double di=(double )i;
double zn;
double hue;
zn = Math.Sqrt(r + c);
hue = di + 1.0 - Math.Log(Math.Log(Math.Abs(zn))) / Math.Log(2.0); // 2 is escape radius
hue = 0.95 + 20.0 * hue; // adjust to make it prettier
// the hsv function expects values from 0 to 360
while (hue > 360.0)
hue -= 360.0;
while (hue < 0.0)
hue += 360.0;
return ColorFromHSV(hue, 0.8, 1.0);
}
MapColour está "suavizando" los valores de rescate de 0 a 1, que luego se pueden usar para mapear un color sin bandas horribles. Jugar con MapColour y / o la función hsv le permite modificar qué colores se utilizan.