Programing

N "고유 한"색상을 자동으로 생성하는 방법은 무엇입니까?

crosscheck 2020. 5. 16. 11:06
반응형

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

당신은 사용할 수 있습니다 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

마지막 2 개는 대부분의 대학 도서관 / 프록시를 통해 무료입니다.

N은 유한하고 상대적으로 작습니다

이 경우 목록 솔루션을 사용할 수 있습니다. 주제에 대한 매우 흥미로운 기사를 자유롭게 사용할 수 있습니다.

고려해야 할 몇 가지 색상 목록이 있습니다.

  • 거의 혼란스럽지 않은 Boynton의 11 가지 색상 목록 (이전 섹션의 첫 번째 논문에서 사용 가능)
  • 켈리의 최대 명암 대비 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);
}

다음은 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.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)))

여기 아이디어가 있습니다. 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));
    }

}

다음은 "고유 한"문제를 관리하기위한 솔루션입니다.

반구 요금으로 유닛 구체와 드롭 포인트를 만듭니다. 파티클 시스템이 더 이상 움직이지 않을 때까지 실행합니다 (또는 델타가 "충분히 작습니다"). 이 시점에서 각 지점은 가능한 멀리 떨어져 있습니다. (x, y, z)를 rgb로 변환하십시오.

특정 유형의 문제에 대해서는 이러한 유형의 솔루션이 무차별 대입보다 더 효과적 일 수 있기 때문에 언급했습니다.

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

다시 말하지만 HSL 공간 또는 RGB 공간을 통과하는 가장 확실한 솔루션은 아마도 잘 작동 할 것입니다.


채도와 루미 네이션을 최대한으로 고치고 색조에만 집중하려고합니다. 내가 알다시피, H는 0에서 255까지 갈 수 있고 랩핑됩니다. 이제 두 개의 대조되는 색상을 원한다면이 링의 반대쪽 (예 : 0과 128)을 사용합니다. 4 개의 색상을 원한다면 256 개의 원 길이의 1/4, 즉 0, 64,128,192로 구분됩니다. 물론 N 컬러가 필요할 때 다른 사람들이 제안했듯이 256 / N으로 분리 할 수 ​​있습니다.

이 아이디어에 추가 할 것은 이진 숫자의 역 표현을 사용 하여이 시퀀스를 형성하는 것입니다. 이것 좀봐:

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의 색상과 비슷한 색상을 갖는 것이 좋았습니다. 독자는 영역을 관찰하여 어느 것이 어느 것인지 알 수 있었기 때문입니다.


HSL 색상 모델은 "정렬"색상에 적합 할 수 있지만 시각적으로 다른 색상을 찾으려면 대신 실험실 색상 모델이 필요 합니다.

CIELAB은 사람의 색각과 관련하여 지각 적으로 균일하게 설계되었습니다. 즉,이 값에서 같은 양의 수치 변화는 시각적으로인지 된 변화와 거의 동일한 양에 해당합니다.

일단 광범위한 색상에서 N 색상의 최적의 하위 집합을 찾는 것은 여행 판매원 문제유사하며 k- 평균 알고리즘을 사용하는 모든 솔루션이나 실제로는 그렇지 않은 (NP) 어려운 문제입니다. 도움.

즉, N이 너무 크지 않고 제한된 색상 세트로 시작하면 간단한 임의 함수를 사용하여 Lab 거리에 따라 구별되는 색상의 매우 우수한 하위 세트를 쉽게 찾을 수 있습니다.

나는 내 자신의 사용법을 위해 그러한 도구를 코딩했다 (여기에서 찾을 수 있습니다 : https://mokole.com/palette.html ), 여기 N = 7에 대해 얻은 것이 있습니다 :여기에 이미지 설명을 입력하십시오

그것은 모두 자바 스크립트이므로 페이지 소스를 살펴보고 자신의 필요에 맞게 조정하십시오.


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 용 패키지를 작성했습니다 . 비 네트살펴보고 그 작동 방식을 알아볼 것을 권장 하지만 요점을 요약하려고 노력할 것입니다.

qualpalr는 HSL 색상 공간 (이 스레드에서 이전에 설명)에서 색상의 사양을 취하여 DIN99d 색상 공간 (지각 적으로 균일 함)으로 투사 n하여 oif 간의 최소 거리를 최대화합니다.

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

여기서 이런 종류의 알고리즘을 찾을 수 없었습니다. 그것이 도움이되기를 바랍니다. 여기의 첫 번째 게시물입니다.

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

반응형