我正在编写一个程序来生成真正巨大的(65536x65536像素及以上)Mandelbrot图像,我想设计一种能够正义的光谱和着色方案。 wikipedia featured mandelbrot image似乎是一个很好的例子,尤其是调色板在序列的所有缩放级别上保持变化的方式。不过,我不确定它是在旋转调色板还是做其他一些技巧来实现这一点。
我熟悉mandelbrot集的smooth coloring algorithm,所以我可以避免使用条带,但我仍然需要一种方法来为此算法的输出值指定颜色。
我正在生成的图像是金字塔形的(例如,一系列图像,每个图像的尺寸都是前一个图像的一半),所以我可以使用某种旋转调色板,只要改变一下。后续缩放级别之间的调色板不太明显。
答案 0 :(得分:31)
这是平滑的颜色算法:
让我们假设你从复数z0
开始并迭代n
次,直到它逃脱。设终点为zn
。
平滑的值将是
nsmooth := n + 1 - Math.log(Math.log(zn.abs()))/Math.log(2)
这仅适用于mandelbrot,如果你想为julia集计算平滑函数,那么使用
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());
}
然后smoothcolor
位于(0,max_iter)
区间内。
将smoothcolor
与max_iter
分开,得到0到1之间的值。
要从值中获得平滑的颜色:
这可以被调用,例如(在Java中):
Color.HSBtoRGB(0.95f + 10 * smoothcolor ,0.6f,1.0f);
因为HSB颜色参数中的第一个值用于定义色环的颜色。
答案 1 :(得分:5)
使用平滑着色算法计算视口中的所有值,然后将调色板从最低值映射到最高值。因此,当您放大并且较高的值不再可见时,调色板也会缩小。对于n和B使用相同的常量,对于完全缩小的集合,最终会得到0.0到1.0的范围,但是在更深的缩放处,动态范围将缩小,例如在200%缩放时为0.0到0.1,0.0到0.0001 at 20000%缩放等
答案 2 :(得分:5)
这是一个天真的Mandelbrot发电机的典型内环。要获得平滑的颜色,您需要传递真实和复杂的“长度”以及您提供的迭代。我已经包含了Mandelbrot代码,因此您可以看到用于计算颜色的变量。
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);
}
和下面的MapColor :(见this link to get the ColorFromHSV function)
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将救助值“平滑”为0到1,然后可以用来映射颜色而不会出现可怕的条带。使用MapColour和/或hsv函数可以改变使用的颜色。
答案 3 :(得分:4)
通过反复试验似乎很简单。假设您可以定义要使用的端点颜色的HSV1和HSV2(色调,饱和度,值)(黑色和白色;蓝色和黄色;深红色和浅绿色等),并假设您有一个算法来分配每个像素的值P介于0.0和1.0之间。然后该像素的颜色变为
(H2 - H1) * P + H1 = HP
(S2 - S1) * P + S1 = SP
(V2 - V1) * P + V1 = VP
完成后,只需观察结果,看看你喜欢它们。如果分配P的算法是连续的,那么梯度也应该是平滑的。
答案 4 :(得分:4)
我最终的解决方案是创建一个漂亮的(并且相当大)调色板并将其作为常量数组存储在源中,然后使用平滑着色算法在其中的索引之间进行插值。调色板包装(并设计为连续的),但这似乎并不重要。
答案 5 :(得分:0)
该图像中的颜色映射所发生的情况是,它在索引上使用了“日志传递函数”(根据文档)。效果如何我还没有弄清楚。产生它的程序使用了400种颜色的调色板,因此索引范围为[0,399],如果需要的话,可以换行。我已经设法接近匹配它的行为。我使用[0,1)的索引范围并将其映射为:
double value = Math.log(0.021 * (iteration + delta + 60)) + 0.72;
value = value - Math.floor(value);
奇怪的是,我必须在其中使用这些特殊常量来使我的结果匹配,因为我怀疑它们是否可以执行任何这些操作。但是最终有什么效果对吧?
答案 6 :(得分:-1)
在这里你可以找到一个带有javascript的版本
用法:
var rgbcol = [] ;
var rgbcol = MapColor ( Iteration , Zy2,Zx2 ) ;
point ( ctx , iX, iY ,rgbcol[0],rgbcol[1],rgbcol[2] );
功能
/*
* 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);
}