Hoe automatisch N “verschillende” kleuren genereren?

Ik heb de twee onderstaande methoden geschreven om automatisch N verschillende kleuren te selecteren. Het werkt door een stuksgewijs lineaire functie op de RGB-kubus te definiëren. Het voordeel hiervan is dat je ook een progressieve schaal kunt krijgen als dat is wat je wilt, maar wanneer N groot wordt, kunnen de kleuren op elkaar gaan lijken. Ik kan me ook voorstellen om de RGB-kubus gelijkmatig in een rooster te verdelen en vervolgens punten te tekenen. Weet iemand nog andere methodes? Ik sluit uit dat ik een lijst definieer en er dan gewoon doorheen fiets. Ik moet ook zeggen dat het me over het algemeen niet kan schelen of ze botsen of er niet leuk uitzien, ze moeten gewoon visueel te onderscheiden zijn.

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

Antwoord 1, autoriteit 100%

Deze vraag komt voor in nogal wat SO-discussies:

Er worden verschillende oplossingen voorgesteld, maar geen enkele is optimaal. Gelukkig komt de wetenschapte hulp

Willekeurige N

De laatste 2 zijn gratis via de meeste universiteitsbibliotheken/proxy’s.

N is eindig en relatief klein

In dit geval zou men kunnen kiezen voor een lijstoplossing. Een zeer interessant artikel over het onderwerp is vrij beschikbaar:

Er zijn verschillende kleurenlijsten om te overwegen:

  • Boynton’s lijst van 11 kleuren die bijna nooit verward worden (beschikbaar in het eerste artikel van de vorige sectie)
  • Kelly’s 22 kleuren met maximaal contrast (beschikbaar in het artikel hierboven)

Ik kwam ook ditpalet tegen door een MIT-student.
Ten slotte kunnen de volgende links nuttig zijn bij het converteren tussen verschillende kleursystemen / coördinaten (sommige kleuren in de artikelen zijn bijvoorbeeld niet gespecificeerd in RGB):

Voor de lijst van Kelly en Boynton heb ik de conversie naar RGB al gemaakt (met uitzondering van wit en zwart, wat duidelijk zou moeten zijn). Wat C#-code:

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

En hier zijn de RGB-waarden in hexadecimale en 8-bits per kanaal-representaties:

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

Voor alle Java-ontwikkelaars, hier zijn de JavaFX-kleuren:

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

het volgende is de ongesorteerde kelly-kleuren volgens de bovenstaande volgorde.

ongesorteerde kelly kleuren

het volgende is de gesorteerde Kelly-kleuren volgens tinten (merk op dat sommige geeltinten niet erg contrasterend zijn)

 gesorteerde kelly kleuren


Antwoord 2, autoriteit 33%

Je kunt het HSL-kleurmodelgebruiken om je kleuren te maken.

Als je alleen verschillende tinten wilt (waarschijnlijk) en kleine variaties in lichtheid of verzadiging, kun je de tinten als volgt verdelen:

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

Antwoord 3, autoriteit 17%

Zoals het antwoord van Uri Cohen, maar is in plaats daarvan een generator. Zal beginnen met het gebruik van kleuren ver uit elkaar. Deterministisch.

Voorbeeld, linker kleuren eerst:
voorbeeld

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

Antwoord 4, autoriteit 14%

Voor de komende generaties voeg ik hier het geaccepteerde antwoord in Python toe.

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

Antwoord 5, autoriteit 12%

Hier is een idee. Stel je een HSV-cilinder voor

Definieer de gewenste boven- en ondergrenzen voor Helderheid en Verzadiging. Dit definieert een vierkante doorsnedering binnen de ruimte.

Verspreid nu willekeurig N punten binnen deze ruimte.

Pas er vervolgens een iteratief afstotingsalgoritme op toe, ofwel voor een vast aantal iteraties, of totdat de punten stabiliseren.

Nu zou je N punten moeten hebben die N kleuren vertegenwoordigen die ongeveer zo verschillend mogelijk zijn binnen de kleurruimte waarin je geïnteresseerd bent.

Hugo


Antwoord 6, autoriteit 7%

Iedereen lijkt het bestaan ​​van de zeer bruikbare YUV-kleurruimte te hebben gemist, die is ontworpen om waargenomen kleurverschillen in het menselijke visuele systeem weer te geven. Afstanden in YUV vertegenwoordigen verschillen in menselijke waarneming. Ik had deze functionaliteit nodig voor MagicCube4D die 4-dimensionale Rubik’s kubussen en een onbeperkt aantal andere 4D bochtige puzzels met willekeurig aantal gezichten implementeert.

Mijn oplossing begint met het selecteren van willekeurige punten in YUV en vervolgens iteratief de dichtstbijzijnde twee punten op te splitsen, en alleen te converteren naar RGB wanneer het resultaat wordt geretourneerd. De methode is O(n^3), maar dat maakt niet uit voor kleine getallen of getallen die in de cache kunnen worden opgeslagen. Het kan zeker efficiënter, maar de resultaten lijken uitstekend.

De functie maakt optionele specificatie van helderheidsdrempels mogelijk om geen kleuren te produceren waarin geen enkel onderdeel helderder of donkerder is dan de opgegeven hoeveelheden. IE wilt misschien geen waarden die in de buurt komen van zwart of wit. Dit is handig wanneer de resulterende kleuren worden gebruikt als basiskleuren die later worden gearceerd via belichting, gelaagdheid, transparantie, enz. en nog steeds anders moeten lijken dan hun basiskleuren.

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

7, Autoriteit 5%

HSL-kleurenmodel kan goed geschikt zijn voor “sorteren” kleuren, maar als u op zoek bent naar visueel verschillende kleuren die u definitief nodig hebt Lab kleurenmodel in plaats daarvan.

CIELAB is ontworpen om perceptueel uniform te zijn met betrekking tot de menselijke kleurvisie, wat betekent dat dezelfde hoeveelheid numerieke verandering in deze waarden overeenkomt met ongeveer dezelfde hoeveelheid visueel waargenomen verandering.

Als u eenmaal weet, is het vinden van de optimale subset van n-kleuren uit een breed scala aan kleuren nog steeds een (NP) hard probleem, een soort vergelijkbaar met de Reizende verkoperprobleem en alle oplossingen met k-gemiddelde algoritmen of iets zullen niet echt helpen.

Dat gezegd hebbende, als n niet te groot is en als u begint met een beperkte reeks kleuren, vindt u gemakkelijk een zeer goede subset van onderscheidingskleuren volgens een lab-afstand met een eenvoudige willekeurige functie.

Ik heb zo’n hulpmiddel voor mijn eigen gebruik gecodeerd (je kunt het hier vinden: https: // mokole. com / palette.html ), hier is wat ik heb voor n = 7:
Voer hier beeldbeschrijving in

Het is allemaal javascript, dus neem gerust een kijkje in de bron van de pagina en pas deze aan uw eigen behoeften aan.


Antwoord 8, autoriteit 2%

Hier is een oplossing om uw “verschillende” probleem, dat volledig overdreven is, te beheren:

Maak een eenheidsbol en laat er punten op vallen met afstotende ladingen. Voer een deeltjessysteem uit totdat ze niet meer bewegen (of de delta “klein genoeg” is). Op dit punt zijn alle punten zo ver mogelijk van elkaar verwijderd. Converteer (x, y, z) naar rgb.

Ik noem het omdat dit type oplossing voor bepaalde soorten problemen beter kan werken dan brute kracht.

Ik zag oorspronkelijk deze benadering hiervoor het mozaïeken van een bol.

Nogmaals, de meest voor de hand liggende oplossingen voor het doorkruisen van HSL-ruimte of RGB-ruimte zullen waarschijnlijk prima werken.


Antwoord 9

Ik zou proberen de verzadiging en verlichting op het maximum te zetten en me alleen op de tint te concentreren. Zoals ik het zie, kan H van 0 tot 255 gaan en dan ronddraaien. Als je nu twee contrasterende kleuren wilt, zou je de tegenovergestelde zijden van deze ring nemen, d.w.z. 0 en 128. Als je 4 kleuren wilde, zou je er een paar nemen, gescheiden door 1/4 van de 256 lengte van de cirkel, d.w.z. 0, 64.128.192. En natuurlijk, zoals anderen suggereerden als je N-kleuren nodig hebt, kun je ze gewoon scheiden met 256/N.

Wat ik aan dit idee zou willen toevoegen, is om een ​​omgekeerde weergave van een binair getal te gebruiken om deze reeks te vormen. Kijk hier eens naar:

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


op deze manier, als je N verschillende kleuren nodig hebt, kun je gewoon de eerste N-nummers nemen, ze omdraaien, en je krijgt zoveel mogelijk verre punten (waarbij N de macht van twee is) terwijl je tegelijkertijd behoudt dat elk voorvoegsel van de reeks een veel.

Dit was een belangrijk doel in mijn gebruik, omdat ik een diagram had waarin kleuren werden gesorteerd op gebied dat door deze kleur werd bedekt. Ik wilde dat de grootste gebieden van de kaart een groot contrast hadden, en ik vond het prima dat sommige kleine gebieden kleuren hadden die vergelijkbaar waren met die van de top 10, omdat het voor de lezer duidelijk was welke welke is door alleen maar het gebied te observeren.


Antwoord 10

We hebben alleen een reeks RGB-tripletten nodig met de maximale afstand tussen deze drietallen.

We kunnen een eenvoudige lineaire helling definiëren en vervolgens de grootte van die helling wijzigen om het gewenste aantal kleuren te krijgen.

In 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

voer hier de afbeeldingsbeschrijving in

voer hier de afbeeldingsbeschrijving in

voer hier de afbeeldingsbeschrijving in


Antwoord 11

Als N groot genoeg is, krijg je kleuren die op elkaar lijken. Er zijn er maar zo veel in de wereld.

Waarom verdeel je ze niet gewoon gelijkmatig over het spectrum, zoals:

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

Als je de reeks door elkaar wilt halen, zodat vergelijkbare kleuren niet naast elkaar staan, kun je de resulterende lijst misschien door elkaar schudden.

Bedenk ik dit niet?


Antwoord 12

Dit is triviaal in MATLAB (er is een hsv-commando):

cmap = hsv(number_of_colors)

Antwoord 13

Ik heb een pakket geschreven voor R genaamd qualpalrdat speciaal hiervoor is ontworpen doel. Ik raad je aan om het vignette bekijken om erachter te komen hoe het werkt, maar ik zal proberen de belangrijkste punten samen te vatten.

qualpalr neemt een specificatie van kleuren in de HSL-kleurruimte(die eerder werd beschreven in deze draad), projecteert deze naar de DIN99d-kleurruimte (die perceptueel uniform is) en vindt de ndie de minimale afstand tussen alle twee maximaliseert.

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

voer hier de afbeeldingsbeschrijving in


Antwoord 14

Ik denk dat dit eenvoudige recursieve algoritme het geaccepteerde antwoord aanvult om duidelijke kleurtoonwaarden te genereren. Ik heb het gemaakt voor hsv, maar kan ook voor andere kleurruimten worden gebruikt.

Het genereert tinten in cycli, zo gescheiden mogelijk van elkaar in elke cyclus.

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

Ik kon dit soort algoritme hier niet vinden. Ik hoop dat het helpt, het is mijn eerste post hier.


Antwoord 15

Behoorlijk netjes met seabornvoor Python-gebruikers:

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

voer hier de afbeeldingsbeschrijving in
het geeft een lijst met RGB-tupels terug:

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

Antwoord 16

Deze OpenCV-functie gebruikt het HSV-kleurmodel om ngelijkmatig verdeelde kleuren rond de 0<=H<=360º te genereren met een maximum van S=1,0 en V=1,0. De functie geeft de BGR-kleuren weer in 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;
}

Antwoord 17

Janus’ antwoord, maar makkelijker te lezen. Ik heb ook het kleurenschema iets aangepast en aangegeven waar je het zelf kunt aanpassen

Ik heb er een fragment van gemaakt dat direct in een jupyter-notitieblok kan worden geplakt.

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

kleuren

Other episodes