programing

N개의 "구분이 되는" 색상을 자동으로 생성하는 방법은 무엇입니까?

firstcheck 2022. 7. 3. 19:15
반응형

N개의 "구분이 되는" 색상을 자동으로 생성하는 방법은 무엇입니까?

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

이 질문은 SO에 관한 많은 설명에서 볼 수 있습니다.

다양한 솔루션이 제안되지만 최적의 솔루션은 없습니다.다행히도, 과학이 도움을 준다.

임의의 N

마지막 2개는 대부분의 대학 도서관/대리점에서 무료입니다.

N은 유한하고 비교적 작다.

이 경우 리스트 솔루션을 선택할 수 있습니다.이 주제에 관한 매우 흥미로운 기사는 자유롭게 볼 수 있다.

고려해야 할 색상 목록은 다음과 같습니다.

  • Boynton의 거의 혼동을 일으키지 않는 11가지 색상 목록(이전 섹션의 첫 번째 논문에서 확인 가능)
  • Kelly의 최대 대비 22가지 색상 (위 문서에서 확인 가능)

이 팔레트는 MIT 학생도 우연히 본 적이 있습니다.마지막으로, 다음 링크는 다른 색계/좌표 변환에 도움이 될 수 있습니다(예를 들어 문서의 일부 색상은 RGB로 지정되어 있지 않습니다.

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

RGB 값은 16진수 및 8비트/채널 표현으로 다음과 같습니다.

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

아래는 위 순서에 따라 정렬되지 않은 켈리 컬러입니다.

얼룩이 없는 켈리색

다음은 색상에 따라 정렬된 켈리 색상입니다(노란색은 그다지 대조적이지 않습니다).

정렬된 켈리 컬러

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

Uri Cohen의 대답처럼, 대신 발전기입니다.먼저 멀리 떨어진 색부터 사용하겠습니다.결정론적이다.

먼저 : 플, 、 쪽 first 、 쪽 first first :샘플

#!/usr/bin/env python3
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)

다음 세대를 위해 여기에 파이썬으로 인정된 답변을 덧붙입니다.

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

이렇게 하는 건 어때.HSV 실린더를 상상해 보십시오.

밝기 및 채도에 대해 원하는 상한과 하한을 정의합니다.공간 내에 사각 단면 링을 정의합니다.

이제 이 공간 내에서 N개의 점을 랜덤하게 분산시킵니다.

그런 다음 고정된 반복 횟수 동안 또는 점이 안정될 때까지 반복 반발 알고리즘을 적용합니다.

이제 N개의 점이 N개의 색상을 나타내며, 원하는 색 공간 내에서 가능한 한 다른 색을 나타내야 합니다.

휴고

모든 사람들은 인간의 시각 시스템에서 인식되는 색 차이를 나타내기 위해 고안된 매우 유용한 YUV 색 공간의 존재를 그리워하는 것 같다.YUV의 거리는 인간의 인식의 차이를 나타낸다.4차원 루빅 큐브와 임의의 수의 얼굴을 가진 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 컬러 모델은 색상 정렬에 매우 적합할 수 있지만 시각적으로 뚜렷한 색상을 찾는 경우 Lab 컬러 모델이 반드시 필요합니다.

CIELAB는 인간의 색각과 관련하여 지각적으로 균일하도록 설계되었으며, 이는 이러한 값의 동일한 수치 변화가 시각적으로 인지된 거의 동일한 양에 해당한다는 것을 의미한다.

일단 그것을 알게 되면, 다양한 색상에서 N색의 최적의 서브셋을 찾는 것은 (NP) 어려운 문제입니다.이것은 Traveling 세일즈맨의 문제와 비슷합니다.k-mean 알고리즘이나 다른 것을 사용하는 모든 솔루션은 그다지 도움이 되지 않습니다.

즉, N이 너무 크지 않고 한정된 색상으로 시작하면 간단한 랜덤 기능으로 랩 거리에 따라 구별되는 색상의 서브셋을 쉽게 찾을 수 있습니다.

이러한 도구를 내 용도에 맞게 코딩했습니다(https://mokole.com/palette.html),는 N=7에 대한 정보입니다).

모두 javascript이므로, 페이지의 출처를 보고, 자신의 요구에 맞추어 수정해 주세요.

다음은 완전히 과장된 "분명한" 문제를 관리하기 위한 솔루션입니다.

단위 구를 만들고 그 위에 역류 전하가 있는 지점을 떨어뜨립니다.파티클 시스템이 더 이상 움직이지 않을 때까지(또는 델타가 "충분히 작음") 파티클 시스템을 실행합니다.이 시점에서 각 점은 가능한 한 서로 멀리 떨어져 있습니다.(x, y, z)를 rbg로 변환합니다.

특정 종류의 문제에서는 이런 종류의 해결책이 폭력보다 더 효과적일 수 있기 때문에 언급하는 것입니다.

저는 원래 구를 테셀링하기 위해 이 방법을 보았습니다.

HSL 공간 또는 RGB 공간을 횡단하는 가장 명백한 솔루션은 아마도 제대로 작동할 것입니다.

매우 좋은 답변이 많이 있지만, 빠른 파이썬 솔루션을 찾고 있는 경우 python 패키지가 구별된다는 것을 언급하는 것이 도움이 될 수 있습니다.이 패키지는 매우 사용하기 쉬운 pypi에서 제공되는 경량 패키지입니다.

from distinctipy import distinctipy

colors = distinctipy.get_colors(12)

print(colors)

# display the colours
distinctipy.color_swatch(colors)

rbg tuples 목록을 반환합니다.

[(0, 1, 0), (1, 0, 1), (0, 0.5, 1), (1, 0.5, 0), (0.5, 0.75, 0.5), (0.4552518132842178, 0.12660764790179446, 0.5467915225460569), (1, 0, 0), (0.12076092516775849, 0.9942188027771208, 0.9239958090462229), (0.254747094970068, 0.4768020779917903, 0.02444859177890535), (0.7854526395841417, 0.48630704929211144, 0.9902480906347156), (0, 0, 1), (1, 1, 0)]

여기에 이미지 설명 입력

또, 기존의 색목록과는 다른 색채를 내는 등, 뛰어난 기능도 갖추고 있습니다.

채도와 조도를 최대한으로 맞추고 색상에만 초점을 맞추려고 합니다.제가 봤을 때 H는 0에서 255까지 갈 수 있어요.두 가지 대비되는 색상을 원하는 경우 이 링의 반대쪽인 0과 128을 선택합니다.4가지 색상을 원하는 경우 원 길이 256의 1/4로 구분하여 0, 64,128,192를 선택합니다.그리고 물론, N가지 색상이 필요할 때 다른 사람들이 제안했듯이 256/N으로 분리하면 됩니다.

이 아이디어에 덧붙이고 싶은 것은 2진수의 역표현을 사용하여 이 수열을 만드는 것입니다.이것 좀 봐.

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

...이렇게 하면 N개의 다른 색상이 필요한 경우 첫 번째 N개의 숫자를 역방향으로 하여 가능한 한 먼 점(N이 2의 거듭제곱일 경우)을 얻을 수 있으며, 동시에 시퀀스의 각 접두사는 크게 다릅니다.

이 색상으로 커버된 영역별로 색상이 정렬된 차트를 가지고 있었기 때문에 이 점은 사용 사례에서 중요한 목표였습니다.나는 차트의 가장 큰 영역이 큰 대비를 이루기를 원했고, 작은 영역도 10위권 영역과 비슷한 색상으로 괜찮았는데, 그 영역을 관찰하는 것만으로 어느 쪽이 어느 쪽인지는 독자들에게 분명했기 때문이다.

이 세쌍 사이의 최대 거리를 가진 RGB 세쌍의 범위만 있으면 됩니다.

심플한 선형 램프를 정의하고 원하는 수의 색상을 얻을 수 있도록 램프의 크기를 조정할 수 있습니다.

python:

def distinguishable_colors(n, shuffle = True, 
                           sinusoidal = False,
                           oscillate_tone = False): 
    ramp = ([1, 0, 0],[1,1,0],[0,1,0],[0,0,1], [1,0,1]) if n>3 else ([1,0,0], [0,1,0],[0,0,1])
    
    coltrio = np.vstack(ramp)
    
    colmap = np.round(resize(coltrio, [n,3], preserve_range=True, 
                             order = 1 if n>3 else 3
                             , mode = 'wrap'),3)
    
    if sinusoidal: colmap = np.sin(colmap*np.pi/2)
    
    colmap = [colmap[x,] for x  in range(colmap.shape[0])]
    
    if oscillate_tone:
        oscillate = [0,1]*round(len(colmap)/2+.5)
        oscillate = [np.array([osc,osc,osc]) for osc in oscillate]
        colmap = [.8*colmap[x] + .2*oscillate[x] for x in range(len(colmap))]
    
    #Whether to shuffle the output colors
    if shuffle:
        random.seed(1)
        random.shuffle(colmap)
        
    return colmap

여기에 이미지 설명 입력

여기에 이미지 설명 입력

여기에 이미지 설명 입력

N이 충분히 크면 비슷한 색이 나올 거예요.세상에 그렇게 많지는 않아요.

이렇게 스펙트럼 전체에 균등하게 분포하는 것은 어떨까요?

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

유사한 색상이 서로 옆에 있지 않도록 시퀀스를 혼합하려면 결과 목록을 섞을 수 있습니다.

내가 이걸 제대로 생각하고 있지 않은 거야?

이것은 MATLAB에서는 사소한 것입니다(hsv 명령어가 있습니다).

cmap = hsv(number_of_colors)

저는 이 목적을 위해 특별히 설계된 qualpalr이라는 R용 패키지를 작성했습니다.vignett을 보고 어떻게 작동하는지 알아보는 것을 추천합니다만, 요점을 정리해 보겠습니다.

qualpalr은 HSL 색공간(이 스레드에서 이전에 설명됨)에서 색상의 사양을 취하여 DIN99d 색공간(지각적으로 균일한)에 투영하고 이를 찾아냅니다.n최소 거리를 최대화할 수 있습니다.

# 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)

여기에 이미지 설명 입력

나는 이 단순한 재귀 알고리즘이 명확한 색상 값을 생성하기 위해 인정된 답을 보완한다고 생각한다.hsv용으로 만들었는데 다른 색공간에서도 사용할 수 있어요.

각 사이클에서 서로 가능한 한 분리하여 사이클마다 색조를 생성합니다.

/**
 * 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;
    }
}

여기서 이런 알고리즘을 찾을 수 없었습니다.도움이 됐으면 좋겠는데, 여기 첫 게시물이에요.

Python 사용자를 위한 Seaborn은 매우 깔끔합니다.

>>> import seaborn as sns
>>> sns.color_palette(n_colors=4)

여기에 이미지 설명 입력
RGB 튜플 목록을 반환합니다.

[(0.12156862745098039, 0.4666666666666667, 0.7058823529411765),
(1.0, 0.4980392156862745, 0.054901960784313725),
(0.17254901960784313, 0.6274509803921569, 0.17254901960784313),
(0.8392156862745098, 0.15294117647058825, 0.1568627450980392)]

이 OpenCV 함수는 HSV 컬러 모델을 사용하여n최대 S=1.0 및 V=1.0으로 0<=H<=360° 주위에 균등하게 분포된 색상.이 함수는 BGR 색상을 출력합니다.bgr_mat:

void distributed_colors (int n, cv::Mat_<cv::Vec3f> & bgr_mat) {
  cv::Mat_<cv::Vec3f> hsv_mat(n,CV_32F,cv::Vec3f(0.0,1.0,1.0));
  double step = 360.0/n;
  double h= 0.0;
  cv::Vec3f value;
  for (int i=0;i<n;i++,h+=step) {
    value = hsv_mat.at<cv::Vec3f>(i);
    hsv_mat.at<cv::Vec3f>(i)[0] = h;
  }
  cv::cvtColor(hsv_mat, bgr_mat, CV_HSV2BGR);
  bgr_mat *= 255;
}

야누스의 대답은 읽기 쉽지만색조도 살짝 조정하고 수정 가능한 부분까지 표시해 두었습니다.

저는 이것을 주피터 노트북에 직접 붙여넣기 위한 조각으로 만들었습니다.

import colorsys
import itertools
from fractions import Fraction
from IPython.display import HTML as html_print

def infinite_hues():
    yield Fraction(0)
    for k in itertools.count():
        i = 2**k # zenos_dichotomy
        for j in range(1,i,2):
            yield Fraction(j,i)

def hue_to_hsvs(h: Fraction):
    # tweak values to adjust scheme
    for s in [Fraction(6,10)]:
        for v in [Fraction(6,10), Fraction(9,10)]: 
            yield (h, s, v) 

def rgb_to_css(rgb) -> str:
    uint8tuple = map(lambda y: int(y*255), rgb)
    return "rgb({},{},{})".format(*uint8tuple)

def css_to_html(css):
    return f"<text style=background-color:{css}>&nbsp;&nbsp;&nbsp;&nbsp;</text>"

def show_colors(n=33):
    hues = infinite_hues()
    hsvs = itertools.chain.from_iterable(hue_to_hsvs(hue) for hue in hues)
    rgbs = (colorsys.hsv_to_rgb(*hsv) for hsv in hsvs)
    csss = (rgb_to_css(rgb) for rgb in rgbs)
    htmls = (css_to_html(css) for css in csss)

    myhtmls = itertools.islice(htmls, n)
    display(html_print("".join(myhtmls)))

show_colors()

색채

언급URL : https://stackoverflow.com/questions/470690/how-to-automatically-generate-n-distinct-colors

반응형