草庐IT

java - 为 Julia 集生成自定义调色板

coder 2024-03-12 原文

我需要一种算法或方法来生成调色板来为 Julia 集图像着色。例如,当使用逃逸时间算法生成图像时,我得出了以下图像:

但是我需要一些方法来生成自定义调色板,例如 the Wikipedia page :

如何获得类似的图像?另外,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<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());
        }
    }

最佳答案

这种颜色映射有很多可能的方法。最简单的是下面的程序。

这段代码的核心是 initColorMap 方法。它需要一些插值步骤和一组颜色来插值。在截图中,这些已经

  • 红色
  • 红色,绿色
  • 红色、绿色、蓝色(如问题的第一张图片)
  • 红、黄、绿、青、蓝、品红
  • 黑色、橙色、白色、蓝色、深蓝色(试图从问题中的第二张图片中获得类似的颜色图)
  • 红、绿、蓝,用正弦函数采样

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

对于您的应用案例,这可能会像这样使用:

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

(编辑:根据评论中的要求更新和扩展了以下描述和代码)

[0.0, 1.0] 范围内的这种“规范化”和使用接口(interface)的抽象通常是有益的。

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

  • ColorMaps1D#createDefault(int steps, Color ... colors) :创建一个默认颜色图,该颜色图以预定义的步骤数(颜色图的“分辨率”)对给定的颜色序列进行插值
  • ColorMaps1D#create(ColorMap1D delegate, DoubleFunction<Double> function) :此方法创建一个颜色映射,其中 getColor 方法的参数在传递给给定委托(delegate)的 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<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());
        }

    }
}

(关于颜色平滑:这可能应该在一个单独的问题中提出。也可能不是,因为在 StackOverflow 上已经有很多问题。例如,请参阅 Smooth spectrum for Mandelbrot Set rendering (或许多其他))

关于java - 为 Julia 集生成自定义调色板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23711681/

有关java - 为 Julia 集生成自定义调色板的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  3. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  4. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  5. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  6. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  7. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  8. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  9. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  10. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

随机推荐