N 가지 색상을 자동으로 선택하기 위해 아래 두 가지 방법을 작성했습니다. RGB 큐브에서 부분 선형 함수를 정의하여 작동합니다. 이것의 장점은 원하는 경우 점진적 스케일을 얻을 수 있지만 N이 커지면 색상이 비슷해지기 시작할 수 있다는 것입니다. RGB 큐브를 격자로 균등하게 세분화 한 다음 점을 그리는 것을 상상할 수도 있습니다. 다른 방법을 아는 사람이 있습니까? 목록을 정의하지 않고 순환합니다. 나는 또한 그들이 충돌하거나 멋지게 보이지 않는다면 일반적으로 신경 쓰지 말고 시각적으로 구별해야한다고 말해야합니다.
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);
}
답변
HSL 컬러 모델을 사용할 수 있습니다 귀하의 색상을 만들 수 있습니다.
원하는 색조가 다를 수 있고, 가벼움이나 채도에 약간의 차이가있는 경우 색조를 다음과 같이 분배 할 수 있습니다.
// 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);
}
답변
이 질문은 몇 가지 SO 토론에서 나타납니다.
다른 솔루션이 제안되었지만 최적의 솔루션은 없습니다. 다행히 과학 이 구조에 온다
임의의 N
- 범주 형 이미지 용 컬러 디스플레이 (무료 다운로드)
- 지도 색 맞춤을위한 웹 서비스 (무료 다운로드, 웹 서비스 솔루션은 다음 달에 제공 될 예정 임)
- 고 대비 색상 세트 선택 알고리즘 (저자에게는 무료 C ++ 구현 제공)
- 고 대비 색상 세트 (문제의 첫 번째 알고리즘)
마지막 2 개는 대부분의 대학 도서관 / 프록시를 통해 무료입니다.
N은 유한하고 상대적으로 작습니다
이 경우 목록 솔루션을 사용할 수 있습니다. 주제에 대한 매우 흥미로운 기사를 자유롭게 사용할 수 있습니다.
고려해야 할 몇 가지 색상 목록이 있습니다.
- 거의 혼란스럽지 않은 Boynton의 11 가지 색상 목록 (이전 섹션의 첫 번째 논문에서 사용 가능)
- 켈리의 최대 명암 대비 22 가지 색상 (위의 논문에서 사용 가능)
나는 또한 우연히 이 MIT의 학생에 의해 팔레트입니다. 마지막으로, 다음 링크는 다른 색상 시스템 / 좌표 간 변환에 유용 할 수 있습니다 (예를 들어 기사의 일부 색상은 RGB로 지정되지 않음).
- http://chem8.org/uch/space-55036-do-blog-id-5333.html
- https://metacpan.org/pod/Color::Library::Dictionary::NBS_ISCC
- 색상 이론 : Munsell HVC에서 RGB / HSB / HSL로 변환하는 방법
Kelly와 Boynton의 목록을 위해 이미 RGB로 변환했습니다 (흰색과 검은 색 제외). 일부 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);
}
다음은 16 진수 및 채널당 8 비트 표현의 RGB 값입니다.
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))
모든 Java 개발자에게 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
};
다음은 위의 순서에 따라 분류되지 않은 켈리 색상입니다.
다음은 색조에 따라 정렬 된 켈리 색상입니다 (일부 노란색은 매우 대조적이지 않습니다)
답변
Uri Cohen의 답변과 같지만 대신 발전기입니다. 멀리 떨어진 색상을 사용하여 시작합니다. 결정 론적.
샘플, 왼쪽 색상이 먼저 :
#!/usr/bin/env python3.5
from typing import Iterable, Tuple
import colorsys
import itertools
from fractions import Fraction
from pprint import pprint
def zenos_dichotomy() -> Iterable[Fraction]:
"""
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 fracs() -> Iterable[Fraction]:
"""
[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 Fraction(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)
# can be used for the v in hsv to map linear values 0..1 to something that looks equidistant
# bias = lambda x: (math.sqrt(x/3)/Fraction(2,3)+Fraction(1,3))/Fraction(6,5)
HSVTuple = Tuple[Fraction, Fraction, Fraction]
RGBTuple = Tuple[float, float, float]
def hue_to_tones(h: Fraction) -> Iterable[HSVTuple]:
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
def hsv_to_rgb(x: HSVTuple) -> RGBTuple:
return colorsys.hsv_to_rgb(*map(float, x))
flatten = itertools.chain.from_iterable
def hsvs() -> Iterable[HSVTuple]:
return flatten(map(hue_to_tones, fracs()))
def rgbs() -> Iterable[RGBTuple]:
return map(hsv_to_rgb, hsvs())
def rgb_to_css(x: RGBTuple) -> str:
uint8tuple = map(lambda y: int(y*255), x)
return "rgb({},{},{})".format(*uint8tuple)
def css_colors() -> Iterable[str]:
return map(rgb_to_css, rgbs())
if __name__ == "__main__":
# sample 100 colors in css format
sample_colors = list(itertools.islice(css_colors(), 100))
pprint(sample_colors)
답변
여기 아이디어가 있습니다. HSV 실린더를 상상해보십시오
밝기 및 채도에 대한 상한 및 하한을 정의하십시오. 이것은 공간 내에서 정사각형 단면 링을 정의합니다.
이제이 공간 내에서 N 개의 점을 무작위로 산란시킵니다.
그런 다음 고정 된 반복 횟수에 대해 또는 포인트가 안정화 될 때까지 반복 반발 알고리즘을 적용하십시오.
이제 관심있는 색 공간 내에서 가능한 한 다른 N 개의 색을 나타내는 N 개의 점이 있어야합니다.
휴고
답변
다음 세대를 위해 파이썬으로 받아 들여진 대답을 여기에 추가합니다.
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
답변
모두가 인간 시각 시스템에서 인식 된 색상 차이를 나타내도록 설계된 매우 유용한 YUV 색상 공간의 존재를 놓친 것 같습니다. YUV의 거리는 인간의 인식의 차이를 나타냅니다. 4 차원 Rubik의 큐브와 임의의 수의 얼굴을 가진 다른 4D 트위스 티 퍼즐을 구현하는 MagicCube4D 에이 기능이 필요했습니다.
내 솔루션은 YUV에서 임의의 점을 선택한 다음 가장 가까운 두 점을 반복적으로 나누고 결과를 반환 할 때만 RGB로 변환하여 시작합니다. 이 방법은 O (n ^ 3)이지만 작은 수나 캐시 할 수있는 것은 중요하지 않습니다. 확실히 더 효율적으로 만들 수는 있지만 결과는 훌륭합니다.
이 기능을 사용하면 지정된 양보다 밝거나 어두운 구성 요소가없는 색상을 생성하지 않도록 밝기 임계 값을 선택적으로 지정할 수 있습니다. IE 당신은 검은 색이나 흰색에 가까운 값을 원하지 않을 수 있습니다. 결과 색상이 나중에 조명, 레이어링, 투명도 등을 통해 음영 처리되고 기본 색상과 다르게 나타나야하는 기본 색상으로 사용될 때 유용합니다.
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));
}
}
답변
HSL 색상 모델은 “정렬”색상에 적합 할 수 있지만 시각적으로 다른 색상을 찾으려면 대신 실험실 색상 모델이 필요 합니다.
CIELAB은 사람의 색각과 관련하여 지각 적으로 균일하게 설계되었습니다. 즉,이 값에서 같은 양의 수치 변화는 시각적으로 인식 된 변화와 거의 같은 양에 해당합니다.
일단 광범위한 색상에서 N 색상의 최적 하위 집합을 찾는 것은 여행 영업 사원 문제 와 비슷한 일종의 (NP) 어려운 문제이며 k- 평균 알고리즘을 사용하는 모든 솔루션 또는 실제로는 그렇지 않습니다. 도움.
즉, N이 너무 크지 않고 제한된 색상 세트로 시작하면 간단한 임의 함수를 사용하여 Lab 거리에 따라 구별되는 색상의 매우 우수한 하위 세트를 쉽게 찾을 수 있습니다.
나는 내 자신의 사용법을 위해 그러한 도구를 코딩했다 (여기에서 찾을 수 있습니다 : https://mokole.com/palette.html ), 여기 N = 7에 대해 얻은 것이 있습니다 :
그것은 모두 자바 스크립트이므로 페이지 소스를 살펴보고 자신의 필요에 맞게 조정하십시오.
