为Julia集生成自定义调色板

我需要一种算法或方法来生成调色板以着色朱莉娅设置图像。 当使用转义时间算法生成图像时,我举例说明如下图:

但是我需要一些方法来生成类似维基百科页面上的自定义调色板:

如何获得与此类似的图像? 另外,Julia集应该使用什么颜色的平滑算法?

以下是澄清的代码段:

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

这种颜色映射有许多可能的方法。 最简单的是在下面的程序中勾画出来。

自定义颜色映射更新

这个片段的核心是initColorMap方法。 它需要许多插值步骤和一组颜色来插值。 在截图中,这些都是

  • 红色,绿色
  • 红色,绿色,蓝色(如问题的第一张图片)
  • 红色,黄色,绿色,青色,蓝色,洋红色
  • 黑色,橙色,白色,蓝色,深蓝色(尝试获取类似于问题中第二个图像的颜色图)
  • 红色,绿色,蓝色,带正弦函数的采样

该方法返回一个int数组,其中包含插值颜色的RGB值。 这可以直接使用。 但是为了提高通用性,这些数组被包装到ColorMap1D接口中,该接口提供了一种方法,可以为0.0到1.0之间的任何给定值返回RGB颜色。

对于您的应用案例,这可能使用如下:

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

编辑 :以下描述和代码已根据评论中的请求进行了更新和扩展)

对范围[0.0,1.0]的这种“标准化”和使用界面的抽象通常是有益的。

作为这种抽象可能产生的效果的演示: ColorMaps1D类包含几种创建ColorMap1D实例的方法:

  • ColorMaps1D#createDefault(int steps, Color ... colors) :创建一个默认的颜色映射,它使用预定义的步数(颜色映射的“分辨率”)对给定的颜色序列进行插值
  • ColorMaps1D#create(ColorMap1D delegate, DoubleFunction function) :此方法创建一个颜色映射,其中getColor方法的参数在传递给定委托的getColor方法之前使用给定函数进行转换。

因此,可以轻松创建ColorMap1D ,在颜色之间进行非线性插值。 甚至可以创建一个ColorMap1D实现,该实现可以插入其他几个颜色映射。

作为一个例子,我添加了一个使用默认的简单Red-> Green-> Blue颜色映射的颜色映射,但是使用一个计算参数正弦的函数来访问它。 这样,可以多次“循环”通过红色 – >绿色 – >蓝色图。

 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 { 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() { @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 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 

(关于颜色平滑:这可能是在一个单独的问题中提出的。或者可能不是,因为在StackOverflow上已经有很多关于它的问题。例如,参见Mandelbrot Set渲染的平滑光谱 (或许多其他))