Spettro regolare per il rendering di Mandelbrot Set

Attualmente sto scrivendo un programma per generare enormi immagini (65536×65536 pixel e sopra) di Mandelbrot, e mi piacerebbe ideare uno spettro e uno schema di colorazione che faccia loro giustizia. L’ immagine di mandelbrot in wikipedia sembra un eccellente esempio, specialmente come la tavolozza rimane varia a tutti i livelli di zoom della sequenza. Non sono sicuro che ruoti la tavolozza o faccia qualche altro trucco per raggiungere questo objective.

Ho familiarità con l’ algoritmo di colorazione uniforms per il set di mandelbrot, quindi posso evitare il banding, ma ho ancora bisogno di un modo per assegnare i colors ai valori di output da questo algoritmo.

Le immagini che sto generando sono piramidali (ad esempio, una serie di immagini, ognuna delle quali ha la metà delle dimensioni del precedente), quindi posso usare una palette rotante di qualche tipo, purché il cambiamento nella palette tra successivi i livelli di zoom non sono troppo evidenti.

Questo è l’algoritmo del colore uniforms:

Diciamo che inizi con il numero complesso z0 e iterate n volte finché non scappa. Lascia che il punto finale sia zn .

Un valore regolare sarebbe

 nsmooth := n + 1 - Math.log(Math.log(zn.abs()))/Math.log(2) 

Funziona solo con mandelbrot, se si desidera calcolare una funzione uniforms per i set di julia, quindi utilizzare

 Complex z = new Complex(x,y); double smoothcolor = Math.exp(-z.abs()); for(i=0;i 

Poi smoothcolor è nell'intervallo (0,max_iter) .

Dividi smoothcolor con max_iter per ottenere un valore compreso tra 0 e 1.

Per ottenere un colore uniforms dal valore:

Questo può essere chiamato, ad esempio (in Java):

 Color.HSBtoRGB(0.95f + 10 * smoothcolor ,0.6f,1.0f); 

poiché il primo valore nei parametri di colore HSB viene utilizzato per definire il colore dal cerchio di colors.

Utilizzare l’algoritmo di colorazione uniforms per calcolare tutti i valori all’interno della finestra, quindi mappare la tavolozza dal valore più basso a quello più alto. Pertanto, mentre si ingrandisce e i valori più alti non sono più visibili, anche la tavolozza si ridimensiona. Con le stesse costanti per n e B ci si ritroverà con un intervallo da 0,0 a 1,0 per un set completamente ingrandito, ma a zoom più profondi la gamma dynamic si ridurrà, per dire da 0,0 a 0,1 con zoom del 200%, da 0,0 a 0,0001 a Zoom del 20000%, ecc.

Ecco un tipico loop interno per un ingenuo generatore di Mandelbrot. Per ottenere un colore omogeneo, si desidera passare nelle “lunghezze” reali e complesse e nell’iterazione a cui è stato salvato. Ho incluso il codice Mandelbrot in modo da poter vedere quali variabili utilizzare per calcolare il colore.

 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); } 

e MapColor di seguito: (vedere questo link per ottenere la funzione 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 sta "uniformando" i valori del bailout da 0 a 1, che poi possono essere utilizzati per mappare un colore senza strisce orribili. Giocare con MapColour e / o la funzione hsv consente di modificare i colors utilizzati.

Sembra semplice da fare per tentativi ed errori. Supponiamo di poter definire HSV1 e HSV2 (tonalità, saturazione, valore) dei colors dell’endpoint che desideri utilizzare (bianco e nero, blu e giallo, rosso scuro e verde chiaro, ecc.) E presumi di avere un algoritmo per assegnare un valore P tra 0.0 e 1.0 per ciascuno dei tuoi pixel. Quindi il colore di quel pixel diventa

 (H2 - H1) * P + H1 = HP (S2 - S1) * P + S1 = SP (V2 - V1) * P + V1 = VP 

Fatto ciò, basta osservare i risultati e vedere come ti piacciono. Se l’algoritmo per assegnare P è continuo, anche il gradiente dovrebbe essere liscio.

La mia soluzione finale è stata quella di creare una palette piacevole (e abbastanza grande) e conservarla come array costante nella sorgente, quindi interpolare tra gli indici in essa contenuti utilizzando l’algoritmo di colorazione uniforms. La palette si avvolge (ed è progettata per essere continua), ma non sembra che importi molto.

qui puoi trovare una versione con javascript

utilizzo:

 var rgbcol = [] ; var rgbcol = MapColor ( Iteration , Zy2,Zx2 ) ; point ( ctx , iX, iY ,rgbcol[0],rgbcol[1],rgbcol[2] ); 

funzione

 /* * 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://stackoverflow.com/questions/369438/smooth-spectrum-for-mandelbrot-set-rendering // alex russel : http://stackoverflow.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); }