java - Generating Custom Color Palette for Julia set -
i need algorithm or method generate color palette color julia set images. when using escape time algorithm generate image example come following image:
however need way generate custom color palette on the wikipedia page:
how achieve image similar that? also, color smoothing algorithm should used julia set?
here code snippet 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 = < 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 many possible approaches such color mapping. simplest sketched in program below.
the core of snippet initcolormap
method. takes number of interpolation steps , array of colors interpolate between. in screenshot, these have been
- red
- red, green
- red, green, blue (like in first image of question)
- red, yellow, green, cyan, blue, magenta
- black, orange, white, blue, dark blue (an attempt obtain color map similar second image in question)
- red, green, blue, sampled sine function
the method returns int
array containing rgb values of interpolated colors. might used directly. improved versatility, these arrays wrapped colormap1d
interface, offers method returns rgb color given value between 0.0 , 1.0.
for application case, used this:
double value = (double)iterations / maxiterations; int rgb = colormap.getcolor(value);
(edit: following description , code have been updated , extended based on request in comment)
such "normalization" range [0.0, 1.0] , abstraction using interfaces beneficial.
as demonstration of effects possible abstraction: colormaps1d
class contains several methods create colormap1d
instances:
colormaps1d#createdefault(int steps, color ... colors)
: creates default color map interpolates on given sequence of colors predefined number of steps (the "resolution" of color map)colormaps1d#create(colormap1d delegate, doublefunction<double> function)
: method creates color map argument ofgetcolor
method transformed given function before passed thegetcolor
method of given delegate.
thus, 1 can create colormap1d
interpolates non-linearly between colors. 1 create colormap1d
implementation interpolates on several other color maps.
as example, have added color map uses default, simple red->green->blue color map, accesses function computes sine of argument. way, possible "cycle" through 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 on "+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 on "+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(); (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: interface equivalent functional // interface in java 8. in environment java 8 available, // interface may omitted, , java 8 version of // interface may used instead. interface doublefunction<r> { r apply(double value); } /** * interface classes can map single value range * [0,1] int represents rgb color */ interface colormap1d { /** * returns int representing rgb color, given value in [0,1] * * @param value value in [0,1] * @return rgb color */ int getcolor(double value); } /** * default implementation of {@link colormap1d} backed * simple int array */ class defaultcolormap1d implements colormap1d { /** * backing array containing rgb colors */ private final int colormaparray[]; /** * creates color map backed given array * * @param colormaparray 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 = (int)(d * (colormaparray.length - 1)); return colormaparray[i]; } } /** * methods create {@link colormap1d} instances */ class colormaps1d { /** * creates {@link colormap1d} walks through given delegate * color map using sine function given frequency * * @param delegate delegate * @param frequency frequency * @return 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 {@link colormap1d} convert argument * given function before looking color * in given delegate * * @param delegate delegate {@link colormap1d} * @param function function converting argument * @return 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 new colormap1d maps value between 0.0 , 1.0 * (inclusive) specified color range, internally using * given number of steps interpolating between colors * * @param steps number of interpolation steps * @param colors colors * @return color map */ static colormap1d createdefault(int steps, color ... colors) { return new defaultcolormap1d(initcolormap(steps, colors)); } /** * creates color array contains rgb colors integers, * interpolated through given colors. * * @param steps number of interpolation steps, , size * of resulting array * @param colors colors array * @return 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); (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 = (int)(a0 + localrel * da); int rgb = (a << 24) | (r << 16) | (g << 8) | (b << 0); colormap[i] = rgb; } return colormap; } /** * private constructor prevent instantiation */ private colormaps1d() { // private constructor prevent instantiation } } /** * panel painting {@link colormap1d} */ class colormappanel1d extends jpanel { /** * {@link colormap1d} painted */ private final colormap1d colormap; /** * creates new panel paints given color map * * @param colormap {@link colormap1d} painted */ colormappanel1d(colormap1d colormap) { this.colormap = colormap; } @override protected void paintcomponent(graphics g) { super.paintcomponent(g); (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 color smoothing: should asked in separate question. or maybe not, because there many questions on stackoverflow. example, see smooth spectrum mandelbrot set rendering (or many others))
Comments
Post a Comment