Mandelbrot 集渲染的平滑频谱

发布于 2024-07-10 13:34:36 字数 535 浏览 5 评论 0原文

我目前正在编写一个程序来生成非常巨大的(65536x65536 像素及以上)Mandelbrot 图像,我想设计一个光谱和着色方案来使它们公正。 维基百科特色曼德尔布罗图像似乎是一个很好的例子,尤其是调色板如何保持变化在序列的所有缩放级别。 不过,我不确定它是否正在旋转调色板或执行其他一些技巧来实现此目的。

我熟悉 mandelbrot 集的平滑着色算法,所以我可以避免条带,但我仍然需要一种方法来为该算法的输出值分配颜色。

我生成的图像是金字塔形的(例如,一系列图像,每个图像的尺寸是前一个图像的一半),因此我可以使用某种旋转调色板,只要后续图像之间的调色板发生变化即可缩放级别不太明显。

I'm currently writing a program to generate really enormous (65536x65536 pixels and above) Mandelbrot images, and I'd like to devise a spectrum and coloring scheme that does them justice. The wikipedia featured mandelbrot image seems like an excellent example, especially how the palette remains varied at all zoom levels of the sequence. I'm not sure if it's rotating the palette or doing some other trick to achieve this, though.

I'm familiar with the smooth coloring algorithm for the mandelbrot set, so I can avoid banding, but I still need a way to assign colors to output values from this algorithm.

The images I'm generating are pyramidal (eg, a series of images, each of which has half the dimensions of the previous one), so I can use a rotating palette of some sort, as long as the change in the palette between subsequent zoom levels isn't too obvious.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

逆光下的微笑 2024-07-17 13:34:36

这是平滑颜色算法:

假设您从复数 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)

smoothcolormax_iter 相除,得到 0 到 1 之间的值。

从该值中获取平滑颜色:

例如,可以调用此方法(在 Java 中):

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

因为 HSB 颜色参数中的第一个值用于定义色环中的颜色。

This is the smooth color algorithm:

Lets say you start with the complex number z0 and iterate n times until it escapes. Let the end point be zn.

A smooth value would be

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

This only works for mandelbrot, if you want to compute a smooth function for julia sets, then use

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

Then smoothcolor is in the interval (0,max_iter).

Divide smoothcolor with max_iter to get a value between 0 and 1.

To get a smooth color from the value:

This can be called, for example (in Java):

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

since the first value in HSB color parameters is used to define the color from the color circle.

苦行僧 2024-07-17 13:34:36

使用平滑着色算法计算视口内的所有值,然后将调色板从最低值映射到最高值。 因此,当您放大并且更高的值不再可见时,调色板也会缩小。 使用相同的 n 和 B 常数,对于完全缩小的设置,最终的范围将是 0.0 到 1.0,但在更深的缩放时,动态范围会缩小,也就是说,在 200% 缩放时为 0.0 到 0.1,在 200% 缩放时为 0.0 到 0.0001。 20000% 缩放等

Use the smooth coloring algorithm to calculate all of the values within the viewport, then map your palette from the lowest to highest value. Thus, as you zoom in and the higher values are no longer visible, the palette will scale down as well. With the same constants for n and B you will end up with a range of 0.0 to 1.0 for a fully zoomed out set, but at deeper zooms the dynamic range will shrink, to say 0.0 to 0.1 at 200% zoom, 0.0 to 0.0001 at 20000% zoom, etc.

橙幽之幻 2024-07-17 13:34:36

这是朴素曼德尔布罗生成器的典型内循环。 为了获得平滑的颜色,您需要传递真实且复杂的“长度”以及您退出的迭代。 我已经包含了 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 下面:(参见 此链接可获取 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 将救助值从 0 “平滑”到 1,然后可用于映射颜色而不会出现可怕的条带。 使用 MapColour 和/或 hsv 函数可以让您改变使用的颜色。

Here is a typical inner loop for a naive Mandelbrot generator. To get a smooth colour you want to pass in the real and complex "lengths" and the iteration you bailed out at. I've included the Mandelbrot code so you can see which vars to use to calculate the colour.

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

and MapColor below: (see 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 is "smoothing" the bailout values from 0 to 1 which then can be used to map a colour without horrible banding. Playing with MapColour and/or the hsv function lets you alter what colours are used.

我也只是我 2024-07-17 13:34:36

通过反复试验似乎很容易做到。 假设您可以定义要使用的端点颜色(黑色和白色;蓝色和黄色;深红色和浅绿色等)的 HSV1 和 HSV2(色调、饱和度、值),并假设您有一个算法来分配每个像素的 P 值介于 0.0 和 1.0 之间。 然后该像素的颜色就变成了

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

完成后,只需观察结果并看看您是否喜欢它们。 如果分配 P 的算法是连续的,那么梯度也应该是平滑的。

Seems simple to do by trial and error. Assume you can define HSV1 and HSV2 (hue, saturation, value) of the endpoint colors you wish to use (black and white; blue and yellow; dark red and light green; etc.), and assume you have an algorithm to assign a value P between 0.0 and 1.0 to each of your pixels. Then that pixel's color becomes

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

With that done, just observe the results and see how you like them. If the algorithm to assign P is continuous, then the gradient should be smooth as well.

可是我不能没有你 2024-07-17 13:34:36

我最终的解决方案是创建一个漂亮的(而且相当大)的调色板,并将其作为常量数组存储在源中,然后使用平滑着色算法在其中的索引之间进行插值。 调色板环绕(并且设计为连续的),但这似乎并不重要。

My eventual solution was to create a nice looking (and fairly large) palette and store it as a constant array in the source, then interpolate between indexes in it using the smooth coloring algorithm. The palette wraps (and is designed to be continuous), but this doesn't appear to matter much.

小忆控 2024-07-17 13:34:36

该图像中的颜色映射的情况是它在索引上使用“对数传输函数”(根据文档)。 它到底是如何做到的我还没有弄清楚。 生成它的程序使用 400 种颜色的调色板,因此索引范围为 [0,399),如果需要,可以环绕。 我已经设法非常接近匹配它的行为。 我使用 [0,1) 的索引范围并像这样映射它:

    double value = Math.log(0.021 * (iteration + delta + 60)) + 0.72;
    value = value - Math.floor(value);

这有点奇怪,我必须在那里使用这些特殊常量才能使我的结果匹配,因为我怀疑他们会这样做。 但最终不管怎样,对吧?

What's going on with the color mapping in that image is that it's using a 'log transfer function' on the index (according to documentation). How exactly it's doing it I still haven't figured out yet. The program that produced it uses a palette of 400 colors, so index ranges [0,399), wrapping around if needed. I've managed to get pretty close to matching it's behavior. I use an index range of [0,1) and map it like so:

    double value = Math.log(0.021 * (iteration + delta + 60)) + 0.72;
    value = value - Math.floor(value);

It's kind of odd that I have to use these special constants in there to get my results to match, since I doubt they do any of that. But whatever works in the end, right?

筱果果 2024-07-17 13:34:36

在这里你可以找到一个带有 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);
}

here you can find a version with javascript

usage :

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

function

/*
 * 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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文