paleta colores color blue java colors color-scheme color-picker

java - colores - material ui colors



¿Cómo generar automáticamente N colores "distintos"? (12)

Aquí hay una idea. Imagine un cilindro de HSV

Defina los límites superior e inferior que desea para Brillo y Saturación. Esto define un anillo de sección cuadrada dentro del espacio.

Ahora, esparce N puntos aleatoriamente dentro de este espacio.

A continuación, aplique un algoritmo de repulsión iterativa sobre ellos, ya sea para un número fijo de iteraciones o hasta que los puntos se estabilicen.

Ahora debería tener N puntos que representen N colores que sean tan diferentes como sea posible dentro del espacio de color que le interese.

Hugo

Escribí los dos métodos a continuación para seleccionar N colores distintos. Funciona al definir una función lineal por partes en el cubo RGB. El beneficio de esto es que también puede obtener una escala progresiva si eso es lo que desea, pero cuando N aumenta, los colores pueden comenzar a verse similares. También puedo imaginar subdividir uniformemente el cubo RGB en un enrejado y luego dibujar puntos. ¿Alguien sabe algún otro método? Estoy descartando la definición de una lista y luego simplemente completarla. También debería decir que generalmente no me importa si chocan o no se ven bien, solo tienen que ser visualmente distintos.

public static List<Color> pick(int num) { List<Color> colors = new ArrayList<Color>(); if (num < 2) return colors; float dx = 1.0f / (float) (num - 1); for (int i = 0; i < num; i++) { colors.add(get(i * dx)); } return colors; } public static Color get(float x) { float r = 0.0f; float g = 0.0f; float b = 1.0f; if (x >= 0.0f && x < 0.2f) { x = x / 0.2f; r = 0.0f; g = x; b = 1.0f; } else if (x >= 0.2f && x < 0.4f) { x = (x - 0.2f) / 0.2f; r = 0.0f; g = 1.0f; b = 1.0f - x; } else if (x >= 0.4f && x < 0.6f) { x = (x - 0.4f) / 0.2f; r = x; g = 1.0f; b = 0.0f; } else if (x >= 0.6f && x < 0.8f) { x = (x - 0.6f) / 0.2f; r = 1.0f; g = 1.0f - x; b = 0.0f; } else if (x >= 0.8f && x <= 1.0f) { x = (x - 0.8f) / 0.2f; r = 1.0f; g = 0.0f; b = x; } return new Color(r, g, b); }


Aquí hay una solución para manejar su problema "distinto", que es totalmente exagerado:

Crea una esfera unitaria y coloca puntos sobre ella con cargas repelentes. Ejecute un sistema de partículas hasta que ya no se muevan (o el delta es "lo suficientemente pequeño"). En este punto, cada uno de los puntos está lo más alejado posible entre ellos. Convierta (x, y, z) en rgb.

Lo menciono porque para ciertas clases de problemas, este tipo de solución puede funcionar mejor que la fuerza bruta.

Originalmente vi este enfoque aquí para teselar una esfera.

Una vez más, las soluciones más obvias para atravesar el espacio HSL o el espacio RGB probablemente funcionen bien.


Como la respuesta de Uri Cohen, pero es un generador en su lugar. Comenzará usando colores muy separados. Determinista

Muestra, colores de la izquierda primero:

#!/usr/bin/env python3.3 import colorsys import itertools from fractions import Fraction def zenos_dichotomy(): """ http://en.wikipedia.org/wiki/1/2_%2B_1/4_%2B_1/8_%2B_1/16_%2B_%C2%B7_%C2%B7_%C2%B7 """ for k in itertools.count(): yield Fraction(1,2**k) def getfracs(): """ [Fraction(0, 1), Fraction(1, 2), Fraction(1, 4), Fraction(3, 4), Fraction(1, 8), Fraction(3, 8), Fraction(5, 8), Fraction(7, 8), Fraction(1, 16), Fraction(3, 16), ...] [0.0, 0.5, 0.25, 0.75, 0.125, 0.375, 0.625, 0.875, 0.0625, 0.1875, ...] """ yield 0 for k in zenos_dichotomy(): i = k.denominator # [1,2,4,8,16,...] for j in range(1,i,2): yield Fraction(j,i) bias = lambda x: (math.sqrt(x/3)/Fraction(2,3)+Fraction(1,3))/Fraction(6,5) # can be used for the v in hsv to map linear values 0..1 to something that looks equidistant def genhsv(h): for s in [Fraction(6,10)]: # optionally use range for v in [Fraction(8,10),Fraction(5,10)]: # could use range too yield (h, s, v) # use bias for v here if you use range genrgb = lambda x: colorsys.hsv_to_rgb(*x) flatten = itertools.chain.from_iterable gethsvs = lambda: flatten(map(genhsv,getfracs())) getrgbs = lambda: map(genrgb, gethsvs()) def genhtml(x): uint8tuple = map(lambda y: int(y*255), x) return "rgb({},{},{})".format(*uint8tuple) gethtmlcolors = lambda: map(genhtml, getrgbs()) if __name__ == "__main__": print(list(itertools.islice(gethtmlcolors(), 100)))


Creo que este algoritmo recursivo simple complementa la respuesta aceptada, a fin de generar distintos valores de matiz. Lo hice para hsv, pero también puede usarse para otros espacios de color.

Genera tonalidades en ciclos, lo más separadas posible entre sí en cada ciclo.

/** * 1st cycle: 0, 120, 240 * 2nd cycle (+60): 60, 180, 300 * 3th cycle (+30): 30, 150, 270, 90, 210, 330 * 4th cycle (+15): 15, 135, 255, 75, 195, 315, 45, 165, 285, 105, 225, 345 */ public static float recursiveHue(int n) { // if 3: alternates red, green, blue variations float firstCycle = 3; // First cycle if (n < firstCycle) { return n * 360f / firstCycle; } // Each cycle has as much values as all previous cycles summed (powers of 2) else { // floor of log base 2 int numCycles = (int)Math.floor(Math.log(n / firstCycle) / Math.log(2)); // divDown stores the larger power of 2 that is still lower than n int divDown = (int)(firstCycle * Math.pow(2, numCycles)); // same hues than previous cycle, but summing an offset (half than previous cycle) return recursiveHue(n % divDown) + 180f / divDown; } }

No pude encontrar este tipo de algoritmo aquí. Espero que ayude, es mi primer mensaje aquí.


Esta pregunta aparece en bastantes discusiones SO:

Se proponen diferentes soluciones, pero ninguna es óptima. Afortunadamente, la ciencia viene al rescate

N arbitrario

Los últimos 2 serán gratuitos en la mayoría de las bibliotecas / proxies de la universidad.

N es finito y relativamente pequeño

En este caso, uno podría ir por una solución de lista. Un artículo muy interesante en el tema está disponible gratuitamente:

Hay varias listas de colores a considerar:

  • La lista de Boynton de 11 colores que casi nunca se confunden (disponible en el primer artículo de la sección anterior)
  • Los 22 colores de máximo contraste de Kelly (disponible en el artículo anterior)

También encontré this Paleta por un estudiante del MIT. Por último, los siguientes enlaces pueden ser útiles para la conversión entre diferentes sistemas de color / coordenadas (algunos colores en los artículos no están especificados en RGB, por ejemplo):

Para la lista de Kelly y Boynton, ya hice la conversión a RGB (a excepción de blanco y negro, lo que debería ser obvio). Cierto código C #:

public static ReadOnlyCollection<Color> KellysMaxContrastSet { get { return _kellysMaxContrastSet.AsReadOnly(); } } private static readonly List<Color> _kellysMaxContrastSet = new List<Color> { UIntToColor(0xFFFFB300), //Vivid Yellow UIntToColor(0xFF803E75), //Strong Purple UIntToColor(0xFFFF6800), //Vivid Orange UIntToColor(0xFFA6BDD7), //Very Light Blue UIntToColor(0xFFC10020), //Vivid Red UIntToColor(0xFFCEA262), //Grayish Yellow UIntToColor(0xFF817066), //Medium Gray //The following will not be good for people with defective color vision UIntToColor(0xFF007D34), //Vivid Green UIntToColor(0xFFF6768E), //Strong Purplish Pink UIntToColor(0xFF00538A), //Strong Blue UIntToColor(0xFFFF7A5C), //Strong Yellowish Pink UIntToColor(0xFF53377A), //Strong Violet UIntToColor(0xFFFF8E00), //Vivid Orange Yellow UIntToColor(0xFFB32851), //Strong Purplish Red UIntToColor(0xFFF4C800), //Vivid Greenish Yellow UIntToColor(0xFF7F180D), //Strong Reddish Brown UIntToColor(0xFF93AA00), //Vivid Yellowish Green UIntToColor(0xFF593315), //Deep Yellowish Brown UIntToColor(0xFFF13A13), //Vivid Reddish Orange UIntToColor(0xFF232C16), //Dark Olive Green }; public static ReadOnlyCollection<Color> BoyntonOptimized { get { return _boyntonOptimized.AsReadOnly(); } } private static readonly List<Color> _boyntonOptimized = new List<Color> { Color.FromArgb(0, 0, 255), //Blue Color.FromArgb(255, 0, 0), //Red Color.FromArgb(0, 255, 0), //Green Color.FromArgb(255, 255, 0), //Yellow Color.FromArgb(255, 0, 255), //Magenta Color.FromArgb(255, 128, 128), //Pink Color.FromArgb(128, 128, 128), //Gray Color.FromArgb(128, 0, 0), //Brown Color.FromArgb(255, 128, 0), //Orange }; static public Color UIntToColor(uint color) { var a = (byte)(color >> 24); var r = (byte)(color >> 16); var g = (byte)(color >> 8); var b = (byte)(color >> 0); return Color.FromArgb(a, r, g, b); }

Y aquí están los valores RGB en representaciones hexadecimales y de 8 bits por canal:

kelly_colors_hex = [ 0xFFB300, # Vivid Yellow 0x803E75, # Strong Purple 0xFF6800, # Vivid Orange 0xA6BDD7, # Very Light Blue 0xC10020, # Vivid Red 0xCEA262, # Grayish Yellow 0x817066, # Medium Gray # The following don''t work well for people with defective color vision 0x007D34, # Vivid Green 0xF6768E, # Strong Purplish Pink 0x00538A, # Strong Blue 0xFF7A5C, # Strong Yellowish Pink 0x53377A, # Strong Violet 0xFF8E00, # Vivid Orange Yellow 0xB32851, # Strong Purplish Red 0xF4C800, # Vivid Greenish Yellow 0x7F180D, # Strong Reddish Brown 0x93AA00, # Vivid Yellowish Green 0x593315, # Deep Yellowish Brown 0xF13A13, # Vivid Reddish Orange 0x232C16, # Dark Olive Green ] kelly_colors = dict(vivid_yellow=(255, 179, 0), strong_purple=(128, 62, 117), vivid_orange=(255, 104, 0), very_light_blue=(166, 189, 215), vivid_red=(193, 0, 32), grayish_yellow=(206, 162, 98), medium_gray=(129, 112, 102), # these aren''t good for people with defective color vision: vivid_green=(0, 125, 52), strong_purplish_pink=(246, 118, 142), strong_blue=(0, 83, 138), strong_yellowish_pink=(255, 122, 92), strong_violet=(83, 55, 122), vivid_orange_yellow=(255, 142, 0), strong_purplish_red=(179, 40, 81), vivid_greenish_yellow=(244, 200, 0), strong_reddish_brown=(127, 24, 13), vivid_yellowish_green=(147, 170, 0), deep_yellowish_brown=(89, 51, 21), vivid_reddish_orange=(241, 58, 19), dark_olive_green=(35, 44, 22))

Para todos los desarrolladores de Java, estos son los colores de JavaFX:

// Don''t forget to import javafx.scene.paint.Color; private static final Color[] KELLY_COLORS = { Color.web("0xFFB300"), // Vivid Yellow Color.web("0x803E75"), // Strong Purple Color.web("0xFF6800"), // Vivid Orange Color.web("0xA6BDD7"), // Very Light Blue Color.web("0xC10020"), // Vivid Red Color.web("0xCEA262"), // Grayish Yellow Color.web("0x817066"), // Medium Gray Color.web("0x007D34"), // Vivid Green Color.web("0xF6768E"), // Strong Purplish Pink Color.web("0x00538A"), // Strong Blue Color.web("0xFF7A5C"), // Strong Yellowish Pink Color.web("0x53377A"), // Strong Violet Color.web("0xFF8E00"), // Vivid Orange Yellow Color.web("0xB32851"), // Strong Purplish Red Color.web("0xF4C800"), // Vivid Greenish Yellow Color.web("0x7F180D"), // Strong Reddish Brown Color.web("0x93AA00"), // Vivid Yellowish Green Color.web("0x593315"), // Deep Yellowish Brown Color.web("0xF13A13"), // Vivid Reddish Orange Color.web("0x232C16"), // Dark Olive Green };

a continuación se muestran los colores de kelly sin clasificar según el orden anterior.

los siguientes son los colores de kelly clasificados de acuerdo con los tonos (tenga en cuenta que algunos amarillos no son muy contrastantes)


Esto es trivial en MATLAB (hay un comando hsv):

cmap = hsv(number_of_colors)


He escrito un paquete para R llamado qualpalr que está diseñado específicamente para este propósito. Te recomiendo que mires la vignette para descubrir cómo funciona, pero intentaré resumir los puntos principales.

qualpalr toma una especificación de colores en el espacio de color HSL (que se describió anteriormente en este hilo), lo proyecta al espacio de color DIN99d (que es perceptualmente uniforme) y encuentra el n que maximiza la distancia mínima entre cualquiera de ellos.

# Create a palette of 4 colors of hues from 0 to 360, saturations between # 0.1 and 0.5, and lightness from 0.6 to 0.85 pal <- qualpal(n = 4, list(h = c(0, 360), s = c(0.1, 0.5), l = c(0.6, 0.85))) # Look at the colors in hex format pal$hex #> [1] "#6F75CE" "#CC6B76" "#CAC16A" "#76D0D0" # Create a palette using one of the predefined color subspaces pal2 <- qualpal(n = 4, colorspace = "pretty") # Distance matrix of the DIN99d color differences pal2$de_DIN99d #> #69A3CC #6ECC6E #CA6BC4 #> 6ECC6E 22 #> CA6BC4 21 30 #> CD976B 24 21 21 plot(pal2)


Intentaría fijar la saturación y la iluminación al máximo y centrarme solo en el tono. Como lo veo, H puede ir de 0 a 255 y luego se envuelve. Ahora bien, si quisieras dos colores contrastantes, tomarías los lados opuestos de este anillo, es decir, 0 y 128. Si quisieras 4 colores, tomarías algunos separados por 1/4 de los 256 del largo del círculo, es decir, 0, 64,128,192. Y, por supuesto, como otros sugirieron cuando necesitas N colores, puedes separarlos por 256 / N.

Lo que agregaría a esta idea es usar una representación invertida de un número binario para formar esta secuencia. Mira este:

0 = 00000000 after reversal is 00000000 = 0 1 = 00000001 after reversal is 10000000 = 128 2 = 00000010 after reversal is 01000000 = 64 3 = 00000011 after reversal is 11000000 = 192

... de esta manera, si necesita N colores diferentes, podría tomar los primeros N números, invertirlos, y obtener la mayor cantidad de puntos distantes posible (para N es el poder de dos) mientras que al mismo tiempo preservar cada prefijo de la la secuencia difiere mucho

Este era un objetivo importante en mi caso de uso, ya que tenía un gráfico donde los colores se ordenaban por área cubierta por este color. Quería que las áreas más grandes de la tabla tuvieran un gran contraste, y estaba bien con algunas áreas pequeñas para tener colores similares a los de los 10 principales, ya que era obvio para el lector cuál es cuál con solo observar el área.


Por el bien de las generaciones venideras, agrego aquí la respuesta aceptada en Python.

import numpy as np import colorsys def _get_colors(num_colors): colors=[] for i in np.arange(0., 360., 360. / num_colors): hue = i/360. lightness = (50 + np.random.rand() * 10)/100. saturation = (90 + np.random.rand() * 10)/100. colors.append(colorsys.hls_to_rgb(hue, lightness, saturation)) return colors


Puede usar el modelo de color HSL para crear sus colores.

Si lo único que desea es tonalidades diferentes (probables) y ligeras variaciones de luminosidad o saturación, puede distribuir los tonos de la siguiente manera:

// assumes hue [0, 360), saturation [0, 100), lightness [0, 100) for(i = 0; i < 360; i += 360 / num_colors) { HSLColor c; c.hue = i; c.saturation = 90 + randf() * 10; c.lightness = 50 + randf() * 10; addColor(c); }


Si N es lo suficientemente grande, obtendrás colores similares. Solo hay muchos en el mundo.

¿Por qué no distribuirlos de manera uniforme a través del espectro, así:

IEnumerable<Color> CreateUniqueColors(int nColors) { int subdivision = (int)Math.Floor(Math.Pow(nColors, 1/3d)); for(int r = 0; r < 255; r += subdivision) for(int g = 0; g < 255; g += subdivision) for(int b = 0; b < 255; b += subdivision) yield return Color.FromArgb(r, g, b); }

Si desea mezclar la secuencia para que los colores similares no estén uno al lado del otro, podría mezclar la lista resultante.

¿Estoy compartiendo esto?


Todos parecen haber perdido la existencia del muy útil espacio de color YUV que fue diseñado para representar las diferencias de color percibidas en el sistema visual humano. Las distancias en YUV representan diferencias en la percepción humana. Necesitaba esta funcionalidad para MagicCube4D que implementa cubos de Rubik de 4 dimensiones y un número ilimitado de otros rompecabezas 4D twisty con números arbitrarios de caras.

Mi solución comienza seleccionando puntos aleatorios en YUV y luego dividiendo iterativamente los dos puntos más cercanos, y solo convirtiendo a RGB al devolver el resultado. El método es O (n ^ 3) pero eso no importa para números pequeños o que se pueden almacenar en caché. Sin duda se puede hacer más eficiente, pero los resultados parecen ser excelentes.

La función permite la especificación opcional de umbrales de brillo para no producir colores en los que ningún componente es más brillante o más oscuro que las cantidades dadas. Es posible que no desee valores cercanos a negro o blanco. Esto es útil cuando los colores resultantes se usarán como colores base que posteriormente se sombrearán mediante iluminación, capas, transparencia, etc. y aún deben aparecer de forma diferente a sus colores base.

import java.awt.Color; import java.util.Random; /** * Contains a method to generate N visually distinct colors and helper methods. * * @author Melinda Green */ public class ColorUtils { private ColorUtils() {} // To disallow instantiation. private final static float U_OFF = .436f, V_OFF = .615f; private static final long RAND_SEED = 0; private static Random rand = new Random(RAND_SEED); /* * Returns an array of ncolors RGB triplets such that each is as unique from the rest as possible * and each color has at least one component greater than minComponent and one less than maxComponent. * Use min == 1 and max == 0 to include the full RGB color range. * * Warning: O N^2 algorithm blows up fast for more than 100 colors. */ public static Color[] generateVisuallyDistinctColors(int ncolors, float minComponent, float maxComponent) { rand.setSeed(RAND_SEED); // So that we get consistent results for each combination of inputs float[][] yuv = new float[ncolors][3]; // initialize array with random colors for(int got = 0; got < ncolors;) { System.arraycopy(randYUVinRGBRange(minComponent, maxComponent), 0, yuv[got++], 0, 3); } // continually break up the worst-fit color pair until we get tired of searching for(int c = 0; c < ncolors * 1000; c++) { float worst = 8888; int worstID = 0; for(int i = 1; i < yuv.length; i++) { for(int j = 0; j < i; j++) { float dist = sqrdist(yuv[i], yuv[j]); if(dist < worst) { worst = dist; worstID = i; } } } float[] best = randYUVBetterThan(worst, minComponent, maxComponent, yuv); if(best == null) break; else yuv[worstID] = best; } Color[] rgbs = new Color[yuv.length]; for(int i = 0; i < yuv.length; i++) { float[] rgb = new float[3]; yuv2rgb(yuv[i][0], yuv[i][1], yuv[i][2], rgb); rgbs[i] = new Color(rgb[0], rgb[1], rgb[2]); //System.out.println(rgb[i][0] + "/t" + rgb[i][1] + "/t" + rgb[i][2]); } return rgbs; } public static void hsv2rgb(float h, float s, float v, float[] rgb) { // H is given on [0->6] or -1. S and V are given on [0->1]. // RGB are each returned on [0->1]. float m, n, f; int i; float[] hsv = new float[3]; hsv[0] = h; hsv[1] = s; hsv[2] = v; System.out.println("H: " + h + " S: " + s + " V:" + v); if(hsv[0] == -1) { rgb[0] = rgb[1] = rgb[2] = hsv[2]; return; } i = (int) (Math.floor(hsv[0])); f = hsv[0] - i; if(i % 2 == 0) f = 1 - f; // if i is even m = hsv[2] * (1 - hsv[1]); n = hsv[2] * (1 - hsv[1] * f); switch(i) { case 6: case 0: rgb[0] = hsv[2]; rgb[1] = n; rgb[2] = m; break; case 1: rgb[0] = n; rgb[1] = hsv[2]; rgb[2] = m; break; case 2: rgb[0] = m; rgb[1] = hsv[2]; rgb[2] = n; break; case 3: rgb[0] = m; rgb[1] = n; rgb[2] = hsv[2]; break; case 4: rgb[0] = n; rgb[1] = m; rgb[2] = hsv[2]; break; case 5: rgb[0] = hsv[2]; rgb[1] = m; rgb[2] = n; break; } } // From http://en.wikipedia.org/wiki/YUV#Mathematical_derivations_and_formulas public static void yuv2rgb(float y, float u, float v, float[] rgb) { rgb[0] = 1 * y + 0 * u + 1.13983f * v; rgb[1] = 1 * y + -.39465f * u + -.58060f * v; rgb[2] = 1 * y + 2.03211f * u + 0 * v; } public static void rgb2yuv(float r, float g, float b, float[] yuv) { yuv[0] = .299f * r + .587f * g + .114f * b; yuv[1] = -.14713f * r + -.28886f * g + .436f * b; yuv[2] = .615f * r + -.51499f * g + -.10001f * b; } private static float[] randYUVinRGBRange(float minComponent, float maxComponent) { while(true) { float y = rand.nextFloat(); // * YFRAC + 1-YFRAC); float u = rand.nextFloat() * 2 * U_OFF - U_OFF; float v = rand.nextFloat() * 2 * V_OFF - V_OFF; float[] rgb = new float[3]; yuv2rgb(y, u, v, rgb); float r = rgb[0], g = rgb[1], b = rgb[2]; if(0 <= r && r <= 1 && 0 <= g && g <= 1 && 0 <= b && b <= 1 && (r > minComponent || g > minComponent || b > minComponent) && // don''t want all dark components (r < maxComponent || g < maxComponent || b < maxComponent)) // don''t want all light components return new float[]{y, u, v}; } } private static float sqrdist(float[] a, float[] b) { float sum = 0; for(int i = 0; i < a.length; i++) { float diff = a[i] - b[i]; sum += diff * diff; } return sum; } private static double worstFit(Color[] colors) { float worst = 8888; float[] a = new float[3], b = new float[3]; for(int i = 1; i < colors.length; i++) { colors[i].getColorComponents(a); for(int j = 0; j < i; j++) { colors[j].getColorComponents(b); float dist = sqrdist(a, b); if(dist < worst) { worst = dist; } } } return Math.sqrt(worst); } private static float[] randYUVBetterThan(float bestDistSqrd, float minComponent, float maxComponent, float[][] in) { for(int attempt = 1; attempt < 100 * in.length; attempt++) { float[] candidate = randYUVinRGBRange(minComponent, maxComponent); boolean good = true; for(int i = 0; i < in.length; i++) if(sqrdist(candidate, in[i]) < bestDistSqrd) good = false; if(good) return candidate; } return null; // after a bunch of passes, couldn''t find a candidate that beat the best. } /** * Simple example program. */ public static void main(String[] args) { final int ncolors = 10; Color[] colors = generateVisuallyDistinctColors(ncolors, .8f, .3f); for(int i = 0; i < colors.length; i++) { System.out.println(colors[i].toString()); } System.out.println("Worst fit color = " + worstFit(colors)); } }