生成自定义调色板Julia集 [英] Generating Custom Color Palette for Julia set

查看:179
本文介绍了生成自定义调色板Julia集的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个算法或方法来生成一个调色板颜色Julia集图像。当使用逃逸时间算法来生成图像I例如想出如下图:

不过,我需要一些方法来生成自定义调色板像的维基百科页面

我如何实现类似的形象呢?此外,应该用于朱莉娅什么颜色的平滑算法设置?

下面是code段澄​​清:

  INT max_iter = 256;
ComplexNumber常数=新ComplexNumber(CREAL,cImag);
浮动饱和度= 1F;
    对于(INT X = 0,X< WIDTH; X ++)
    {
        对于(INT Y = 0; Y<身高; Y ++)
        {
            ComplexNumber oldz =新ComplexNumber();
            ComplexNumber newz =新ComplexNumber(2.0 *(X-WIDTH / 2)/(宽度/ 2),1.33 *(Y-HEIGHT / 2)/(高度/ 2));
            INT I;
            对于(i = 0; I< max_iter;我++)
            {
                oldz = newz;
                newz = newz.square();
                newz.add(常数);
                如果(newz.mod()→2)
                    打破;
            }
            浮动亮度= I< max_iter? 1F:0;
            浮动色相=(I%256)/255.0f;
            色色= Color.getHSBColor((浮点)色调,饱和度,亮度);
            img.setRGB(X,Y,color.getRGB());
        }
    }
 

解决方案

有这样的颜色映射许多可能的方法。最简单的就是勾勒在下面的程序。

该片段的核心是 initColorMap 方法。它需要数量的内插步骤和颜色之间进行内插的阵列。在截图中,这些已经

  • 红色
  • 在红,绿
  • 在红,绿,蓝(如在问题的第一张图像)
  • 红,黄,绿,青,蓝,品红
  • 黑色,橙色,白,蓝,深蓝(试图获得色彩映射类似于从在问题的第二图像)
  • 在红,绿,蓝,采样与正弦函数

该方法返回一个包含的插值颜色的RGB值的 INT 阵列。这可能直接使用。但对于改进的多功能性,这些阵列被裹成 Col​​orMap1D 接口,它提供了一个返回的RGB颜色介于0.0和1.0之间的任何给定值的方法。

有关应用程序的情况下,这很可能使用的是这样的:

 双值=(双)迭代/ maxIterations;
INT RGB = colorMap.getColor(值);
 

修改:下面的描述和code已被更新,并根据该意见要求下延长)

这样的正常化到范围[0.0,1.0]而使用接口的抽象是经常有益的。

由于这是可能的这种抽象的效果展示: Col​​orMaps1D 类包含一些方法来创建 Col​​orMap1D 实例:

  • Col​​orMaps1D#createDefault(INT步骤,颜色......颜色):创建一个默认颜色的地图,通过插值的颜色给定顺序以predefined数量步骤(彩色地图的决议)
  • Col​​orMaps1D#创建(ColorMap1D委托​​,DoubleFunction<双>功能):此方法创建一个彩色地图,其中的参数的的getColor 法转化具有给定功能才能通过的给定委托的的getColor 方法。

因此​​,人们可以很容易地创建一个 Col​​orMap1D 的内插的非线性的颜色之间。我们甚至可以创建一个 Col​​orMap1D 的实现,插值比其他几种颜色的地图。

作为一个例子,我补充说,使用默认的,简单的红 - >绿 - >蓝彩色地图,但访问它与一个函数,计算参数的正弦彩色地图。这种方式,有可能为循环,通过红 - >绿 - >蓝彩色地图几次

 进口java.awt.BorderLayout中;
进口java.awt.Color中;
进口java.awt.Graphics;
进口java.awt.GridLayout中;
进口java.util.Arrays中;

进口javax.swing.JFrame中;
进口javax.swing.JLabel中;
进口javax.swing.JPanel中;
进口javax.swing.SwingUtilities中;

公共类ColorMapsTest
{
    公共静态无效的主要(字串[] args)
    {
        SwingUtilities.invokeLater(新的Runnable()
        {
            @覆盖
            公共无效的run()
            {
                createAndShowGUI();
            }
        });
    }

    私有静态无效createAndShowGUI()
    {
        JFrame的F =新的JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        。f.getContentPane()的setLayout(新的网格布局(0,1));

        INT步骤= 1024;
        f.getContentPane()。增加(
            createPanel(步骤Color.RED));
        f.getContentPane()。增加(
            createPanel(步骤Color.RED,Color.GREEN));
        f.getContentPane()。增加(
            createPanel(步骤Color.RED,Color.GREEN,Color.BLUE));
        f.getContentPane()。增加(
            createPanel(步骤,
                Color.RED,Color.YELLOW,
                Color.GREEN,Color.CYAN,
                Color.BLUE,Color.MAGENTA));
        f.getContentPane()。增加(
            createPanel(步骤,
                Color.BLACK,Color.ORANGE,Color.WHITE,
                Color.BLUE,新的颜色(0,0,128)));


        的JPanel面板=的新JPanel(新的BorderLayout());
        颜色颜色[] =新的颜色[] {Color.RED,Color.GREEN,Color.BLUE};
        字符串信息=随着正弦超过+ createString(颜色);
        panel.add(新JLabel的(信息),BorderLayout.NORTH);
        ColorMapPanel1D colorMapPanel =
            新ColorMapPanel1D(
                ColorMaps1D.createSine(
                    ColorMaps1D.createDefault(步,颜色),Math.PI * 4));
        panel.add(colorMapPanel,BorderLayout.CENTER);
        。f.getContentPane()加(板);


        f.setSize(500,400);
        f.setLocationRelativeTo(空);
        f.setVisible(真正的);
    }



    私有静态的JPanel createPanel(INT步骤,颜色...颜色)
    {
        的JPanel面板=的新JPanel(新的BorderLayout());
        字符串信息=在+步+步过+ createString(颜色);
        panel.add(新JLabel的(信息),BorderLayout.NORTH);
        ColorMapPanel1D colorMapPanel =
            新ColorMapPanel1D(ColorMaps1D.createDefault(步骤,颜色));
        panel.add(colorMapPanel,BorderLayout.CENTER);
        返回面板;
    }

    私有静态字符串createString(颜色...颜色)
    {
        StringBuilder的SB =新的StringBuilder();
        的for(int i = 0; I< colors.length;我++)
        {
            sb.append(createString(颜色[I]));
            如果(ⅰ&所述; colors.length  -  1)
            {
                sb.append(,);
            }
        }
        返回sb.toString();
    }
    私有静态字符串createString(色色)
    {
        返回(+ color.getRed()+,+ color.getGreen()+,+ color.getBlue()+);
    }
}

//注意:这是一个接口,它等效于所述功能
//接口中的Java 8.的环境下的Java 8是可用的,
//这个接口可以被省略,以及Java版本8的这个
//可以使用接口代替。
接口DoubleFunction&所述; R GT;
{
    r使用(double值);
}



/ **
 *接口类,可以从范围映射的单个值
 * [0,1]到重新$ P $一个int psents RGB颜色
 * /
接口ColorMap1D
{
    / **
     *返回一个int再presenting RGB颜色,在给定值[0,1]
     *
     *参数值值[0,1]
     返回:RGB颜色
     * /
    INT的getColor(double值);
}

/ **
 *默认实施{@link ColorMap1D},是通过支持
 *一个简单的int数组
 * /
类DefaultColorMap1D实现ColorMap1D
{
    / **
     *包含RGB颜色的支持数组
     * /
    私人最终诠释colorMapArray [];

    / **
     *创建一个由给定数组支持的彩色地图
     *
     *参数colorMapArray包含RGB颜色数组
     * /
    DefaultColorMap1D(INT colorMapArray [])
    {
        this.colorMapArray = colorMapArray;
    }

    @覆盖
    公众诠释的getColor(double值)
    {
        双D = Math.max(0.0,Math.min(1.0,值));
        INT I =(INT)(D *(colorMapArray.length  -  1));
        返回colorMapArray [I]
    }
}


/ **
 *方法来创建{@link ColorMap1D}实例
 * /
类ColorMaps1D
{
    / **
     *创建{@link ColorMap1D}是遍历给定的委托
     *使用正弦函数具有给定频率的彩色地图
     *
     *参数代表的委托
     *参数频率频率
     * @返回新的{@link ColorMap1D}
     * /
    静态ColorMap1D createSine(ColorMap1D代表,最终双频)
    {
        返回创建(会议代表,新DoubleFunction<双>()
        {
            @覆盖
            公共双申请(double值)
            {
                返回0.5 + 0.5 * Math.sin(值*频率);
            }
        });
    }

    / **
     *创建一个{@link ColorMap1D},将参数转换
     *用给定的功能,然后才抬起头来颜色
     *在给定的委托
     *
     *参数代表的委托{@link ColorMap1D}
     *参数函数的函数转换参数
     * @返回新的{@link ColorMap1D}
     * /
    静态ColorMap1D创建(
        最后ColorMap1D代表,最终DoubleFunction<双>功能)
    {
        返回新ColorMap1D()
        {
            @覆盖
            公众诠释的getColor(double值)
            {
                返回delegate.getColor(function.apply(值));
            }
        };
    }


    / **
     *创建映射0.0和1.0之间的值的新ColorMap1D
     *(包括)到指定的色彩范围,内部使用
     *给定的步数为颜色之间内插
     *
     * @参数的步骤的插值步数
     *参数色的颜色
     返回:彩色地图
     * /
    静态ColorMap1D createDefault(INT步骤,颜色...颜色)
    {
        返回新DefaultColorMap1D(initColorMap(步,颜色));
    }

    / **
     *创建的颜色数组,它包含的RGB颜色为整数,
     *通过给定的色彩插值。
     *
     * @参数的步骤的内插步骤的数量,和尺寸
     *最终阵列
     *参数色彩的颜色数组
     返回:颜色数组
     * /
    静态INT [] initColorMap(INT步骤,颜色...颜色)
    {
        INT的颜色表[] =新的INT [措施];
        如果(colors.length == 1)
        {
            Arrays.fill(颜色表,颜色[0] .getRGB());
            返回颜色表;
        }
        双colorDelta = 1.0 /(colors.length  -  1);
        的for(int i = 0; I<步骤;我++)
        {
            双globalRel =(双)I /(步骤 -  1);
            INT的index0 =(INT)(globalRel / colorDelta);
            INT索引1 = Math.min(colors.length-1,的index0 + 1);
            双localRel =(globalRel  - 位于index0 * colorDelta)/ colorDelta;

            颜色C =颜色[的index0]
            INT R0 = c0.getRed();
            INT G0 = c0.getGreen();
            INT B0 = c0.getBlue();
            INT A0 = c0.getAlpha();

            颜色C1 =颜色[索引1];
            INT R1 = c1.getRed();
            INT G1 = c1.getGreen();
            INT B1 = c1.getBlue();
            INT A1 = c1.getAlpha();

            INT博士= R1-R0;
            INT DG = G1-G0;
            INT DB = B1-B0;
            诠释DA = A1,A0;

            INT R =(INT)(R0 + localRel * DR);
            INT G =(INT)(G0 + localRel * DG);
            INT B =(INT)(B0 + localRel *分贝);
            诠释一个=(INT)(A0 + localRel * DA);
            INT RGB =
                (一个&其中;&所述; 24)|
                (为r&所述; 16)|
                (G<< 8)|
                (b将℃下);
            颜色表[i] = RGB;
        }
        返回颜色表;
    }

    / **
     *私人构造​​函数prevent实例
     * /
    私人ColorMaps1D()
    {
        //私有构造函数prevent实例
    }
}


/ **
 *一个面板上画一个{@link ColorMap1D}
 * /
类ColorMapPanel1D继承JPanel
{
    / **
     *在{@link ColorMap1D}这是画
     * /
    私人最终ColorMap1D色彩表;

    / **
     *创建一个新的面板,油漆给定的彩色地图
     *
     *参数colormap中的{@link ColorMap1D}被涂
     * /
    ColorMapPanel1D(ColorMap1D颜色表)
    {
        this.colorMap =颜色表;
    }

    @覆盖
    保护无效paintComponent(图形G)
    {
        super.paintComponent方法(G);

        为(中间体X = 0 X  - 其中;的getWidth(); X ++)
        {
            双D =(双)X /(的getWidth() -  1);
            INT RGB = colorMap.getColor(D);
            g.setColor(新颜色(RGB));
            g.drawLine(X,0,X,的getHeight());
        }

    }
}
 

(关于颜色平滑:这是什么,也许应该问一个单独的问题或许不是,因为那里已经是许多的有关在StackOverflow上的问题。例如,见<一。 HREF =htt​​p://stackoverflow.com/q/369438/3182664>平滑谱Mandelbrot集渲染(或许多其他的))

I need an algorithm or a method to generate a color palette to Color the Julia set images. When using the escape time algorithm to generate the image I for example come up with the following image:

However I need some way to generate a custom color palette like on the Wikipedia page:

How do I achieve an image similar to that? Also, what color smoothing algorithm should be used for Julia set?

Here is the code snippet for clarification:

int max_iter = 256;
ComplexNumber constant = new ComplexNumber(cReal,cImag);
float Saturation = 1f;
    for(int X=0; X<WIDTH; X++)
    {
        for(int Y=0; Y<HEIGHT; Y++)
        {
            ComplexNumber oldz = new ComplexNumber();
            ComplexNumber newz = new ComplexNumber(2.0*(X-WIDTH/2)/(WIDTH/2), 1.33*(Y-HEIGHT/2)/(HEIGHT/2) );
            int i;
            for(i=0;i<max_iter; i++)
            {
                oldz = newz;
                newz = newz.square();
                newz.add(constant);
                if(newz.mod() > 2)
                    break;
            }
            float Brightness = i < max_iter ? 1f : 0;
            float Hue = (i%256)/255.0f;
            Color color = Color.getHSBColor((float)Hue, Saturation, Brightness);
            img.setRGB(X,Y,color.getRGB());
        }
    }

解决方案

There are many possible approaches for such a color mapping. The simplest is sketched in the program below.

The core of this snippet is the initColorMap method. It takes a number of interpolation steps and an array of colors to interpolate between. In the screenshot, these have been

  • red
  • red, green
  • red, green, blue (like in the first image of the question)
  • red, yellow, green, cyan, blue, magenta
  • black, orange, white, blue, dark blue (an attempt to obtain a color map similar to that from the second image in the question)
  • red, green, blue, sampled with a sine function

The method returns an int array containing the RGB values of the interpolated colors. This might be used directly. But for an improved versatility, these arrays are wrapped into a ColorMap1D interface, which offers a method that returns an RGB color for any given value between 0.0 and 1.0.

For your application case, this could probably used like this:

double value = (double)iterations / maxIterations;
int rgb = colorMap.getColor(value);

(EDIT: The following description and the code have been updated and extended based on the request in the comment)

Such a "normalization" to the range [0.0, 1.0] and the abstraction using interfaces is often beneficial.

As a demonstration of the effects that are possible with this abstraction: The ColorMaps1D class contains several methods to create ColorMap1D instances:

  • ColorMaps1D#createDefault(int steps, Color ... colors): Creates a default color map that interpolates over a given sequence of colors with a predefined number of steps (the "resolution" of the color map)
  • ColorMaps1D#create(ColorMap1D delegate, DoubleFunction<Double> function) : This method creates a color map where the argument of the getColor method is transformed with the given function before it is passed the the getColor method of the given delegate.

Thus, one can easily create a ColorMap1D that interpolates non-linearly between colors. One could even create a ColorMap1D implementation that interpolates over several other color maps.

As an example, I have added a color map that uses the default, simple Red->Green->Blue color map, but accesses it with a function that computes the sine of the argument. This way, it is possible to "cycle" through the Red->Green->Blue color map several times.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.util.Arrays;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ColorMapsTest
{
    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI()
    {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        f.getContentPane().setLayout(new GridLayout(0,1));

        int steps = 1024;
        f.getContentPane().add(
            createPanel(steps, Color.RED));
        f.getContentPane().add(
            createPanel(steps, Color.RED, Color.GREEN));
        f.getContentPane().add(
            createPanel(steps, Color.RED, Color.GREEN, Color.BLUE));
        f.getContentPane().add(
            createPanel(steps,
                Color.RED, Color.YELLOW,
                Color.GREEN, Color.CYAN,
                Color.BLUE, Color.MAGENTA));
        f.getContentPane().add(
            createPanel(steps,
                Color.BLACK, Color.ORANGE, Color.WHITE,
                Color.BLUE, new Color(0,0,128)));


        JPanel panel = new JPanel(new BorderLayout());
        Color colors[] = new Color[]{ Color.RED, Color.GREEN, Color.BLUE };
        String info = "With sine over "+createString(colors);
        panel.add(new JLabel(info), BorderLayout.NORTH);
        ColorMapPanel1D colorMapPanel =
            new ColorMapPanel1D(
                ColorMaps1D.createSine(
                    ColorMaps1D.createDefault(steps, colors), Math.PI * 4));
        panel.add(colorMapPanel, BorderLayout.CENTER);
        f.getContentPane().add(panel);


        f.setSize(500, 400);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }



    private static JPanel createPanel(int steps, Color ... colors)
    {
        JPanel panel = new JPanel(new BorderLayout());
        String info = "In "+steps+" steps over "+createString(colors);
        panel.add(new JLabel(info), BorderLayout.NORTH);
        ColorMapPanel1D colorMapPanel =
            new ColorMapPanel1D(ColorMaps1D.createDefault(steps, colors));
        panel.add(colorMapPanel, BorderLayout.CENTER);
        return panel;
    }

    private static String createString(Color ... colors)
    {
        StringBuilder sb = new StringBuilder();
        for (int i=0; i<colors.length; i++)
        {
            sb.append(createString(colors[i]));
            if (i < colors.length - 1)
            {
                sb.append(", ");
            }
        }
        return sb.toString();
    }
    private static String createString(Color color)
    {
        return "("+color.getRed()+","+color.getGreen()+","+color.getBlue()+")";
    }
}

// NOTE: This is an interface that is equivalent to the functional
// interface in Java 8. In an environment where Java 8 is available,
// this interface may be omitted, and the Java 8 version of this
// interface may be used instead.
interface DoubleFunction<R>
{
    R apply(double value);
}



/**
 * Interface for classes that can map a single value from the range
 * [0,1] to an int that represents an RGB color
 */
interface ColorMap1D
{
    /**
     * Returns an int representing the RGB color, for the given value in [0,1]
     *
     * @param value The value in [0,1]
     * @return The RGB color
     */
    int getColor(double value);
}

/**
 * Default implementation of a {@link ColorMap1D} that is backed by
 * a simple int array
 */
class DefaultColorMap1D implements ColorMap1D
{
    /**
     * The backing array containing the RGB colors
     */
    private final int colorMapArray[];

    /**
     * Creates a color map that is backed by the given array
     *
     * @param colorMapArray The array containing RGB colors
     */
    DefaultColorMap1D(int colorMapArray[])
    {
        this.colorMapArray = colorMapArray;
    }

    @Override
    public int getColor(double value)
    {
        double d = Math.max(0.0, Math.min(1.0, value));
        int i = (int)(d * (colorMapArray.length - 1));
        return colorMapArray[i];
    }
}


/**
 * Methods to create {@link ColorMap1D} instances
 */
class ColorMaps1D
{
    /**
     * Creates a {@link ColorMap1D} that walks through the given delegate
     * color map using a sine function with the given frequency
     *
     * @param delegate The delegate
     * @param frequency The frequency
     * @return The new {@link ColorMap1D}
     */
    static ColorMap1D createSine(ColorMap1D delegate, final double frequency)
    {
        return create(delegate, new DoubleFunction<Double>()
        {
            @Override
            public Double apply(double value)
            {
                return 0.5 + 0.5 * Math.sin(value * frequency);
            }
        });
    }

    /**
     * Creates a {@link ColorMap1D} that will convert the argument
     * with the given function before it is looking up the color
     * in the given delegate
     *
     * @param delegate The delegate {@link ColorMap1D}
     * @param function The function for converting the argument
     * @return The new {@link ColorMap1D}
     */
    static ColorMap1D create(
        final ColorMap1D delegate, final DoubleFunction<Double> function)
    {
        return new ColorMap1D()
        {
            @Override
            public int getColor(double value)
            {
                return delegate.getColor(function.apply(value));
            }
        };
    }


    /**
     * Creates a new ColorMap1D that maps a value between 0.0 and 1.0
     * (inclusive) to the specified color range, internally using the
     * given number of steps for interpolating between the colors
     *
     * @param steps The number of interpolation steps
     * @param colors The colors
     * @return The color map
     */
    static ColorMap1D createDefault(int steps, Color ... colors)
    {
        return new DefaultColorMap1D(initColorMap(steps, colors));
    }

    /**
     * Creates the color array which contains RGB colors as integers,
     * interpolated through the given colors.
     *
     * @param steps The number of interpolation steps, and the size
     * of the resulting array
     * @param colors The colors for the array
     * @return The color array
     */
    static int[] initColorMap(int steps, Color ... colors)
    {
        int colorMap[] = new int[steps];
        if (colors.length == 1)
        {
            Arrays.fill(colorMap, colors[0].getRGB());
            return colorMap;
        }
        double colorDelta = 1.0 / (colors.length - 1);
        for (int i=0; i<steps; i++)
        {
            double globalRel = (double)i / (steps - 1);
            int index0 = (int)(globalRel / colorDelta);
            int index1 = Math.min(colors.length-1, index0 + 1);
            double localRel = (globalRel - index0 * colorDelta) / colorDelta;

            Color c0 = colors[index0];
            int r0 = c0.getRed();
            int g0 = c0.getGreen();
            int b0 = c0.getBlue();
            int a0 = c0.getAlpha();

            Color c1 = colors[index1];
            int r1 = c1.getRed();
            int g1 = c1.getGreen();
            int b1 = c1.getBlue();
            int a1 = c1.getAlpha();

            int dr = r1-r0;
            int dg = g1-g0;
            int db = b1-b0;
            int da = a1-a0;

            int r = (int)(r0 + localRel * dr);
            int g = (int)(g0 + localRel * dg);
            int b = (int)(b0 + localRel * db);
            int a = (int)(a0 + localRel * da);
            int rgb =
                (a << 24) |
                (r << 16) |
                (g <<  8) |
                (b <<  0);
            colorMap[i] = rgb;
        }
        return colorMap;
    }

    /**
     * Private constructor to prevent instantiation
     */
    private ColorMaps1D()
    {
        // Private constructor to prevent instantiation
    }
}


/**
 * A panel painting a {@link ColorMap1D}
 */
class ColorMapPanel1D extends JPanel
{
    /**
     * The {@link ColorMap1D} that is painted
     */
    private final ColorMap1D colorMap;

    /**
     * Creates a new panel that paints the given color map
     *
     * @param colorMap The {@link ColorMap1D} to be painted
     */
    ColorMapPanel1D(ColorMap1D colorMap)
    {
        this.colorMap = colorMap;
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        for (int x=0; x<getWidth(); x++)
        {
            double d = (double)x / (getWidth() - 1);
            int rgb = colorMap.getColor(d);
            g.setColor(new Color(rgb));
            g.drawLine(x, 0, x, getHeight());
        }

    }
}

(Regarding the color smoothing: This is something that should probably be asked in a separate question. Or maybe not, because there already are many questions about that on StackOverflow. For example, see Smooth spectrum for Mandelbrot Set rendering (or many others))

这篇关于生成自定义调色板Julia集的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆