Algoritmo para generar aleatoriamente una paleta de colores estéticamente agradable [cerrado]

StackOverflow https://stackoverflow.com/questions/43044

  •  09-06-2019
  •  | 
  •  

Pregunta

Estoy buscando un algoritmo simple para generar una gran cantidad de colores aleatorios y estéticamente agradables.Así que nada de locos colores neón, colores que recuerden a las heces, etc.

Encontré soluciones a este problema, pero se basan en paletas de colores alternativas a RGB.Prefiero usar RGB directo que mapear de un lado a otro.Estas otras soluciones también pueden generar como máximo sólo 32 colores aleatorios agradables.

Cualquier idea sería genial.

¿Fue útil?

Solución

Podrías promediar los valores RGB de colores aleatorios con los de un color constante:

(ejemplo en Java)

public Color generateRandomColor(Color mix) {
    Random random = new Random();
    int red = random.nextInt(256);
    int green = random.nextInt(256);
    int blue = random.nextInt(256);

    // mix the color
    if (mix != null) {
        red = (red + mix.getRed()) / 2;
        green = (green + mix.getGreen()) / 2;
        blue = (blue + mix.getBlue()) / 2;
    }

    Color color = new Color(red, green, blue);
    return color;
}


La mezcla de colores aleatorios con blanco (255, 255, 255) crea pasteles neutros al aumentar la luminosidad y mantener el tono del color original.Estos pasteles generados aleatoriamente suelen combinar bien, especialmente en grandes cantidades.

Aquí hay algunos colores pastel generados usando el método anterior:

First


También puedes mezclar el color aleatorio con un pastel constante, lo que da como resultado un conjunto teñido de colores neutros.Por ejemplo, usar un azul claro crea colores como estos:

Second


Yendo más allá, podrías agregar heurísticas a tu generador que tengan en cuenta colores complementarios o niveles de sombreado, pero todo depende de la impresión que quieras lograr con tus colores aleatorios.

Algunos recursos adicionales:

Otros consejos

Yo usaría una rueda de colores y, dada una posición aleatoria, podría agregar el ángulo dorado (137,5 grados)

http://en.wikipedia.org/wiki/Golden_angle

para conseguir colores diferentes cada vez que no se superpongan.

Al ajustar el brillo de la rueda de colores también se pueden obtener diferentes combinaciones de colores brillantes/oscuros.

Encontré esta publicación de blog que explica muy bien el problema y la solución utilizando la proporción áurea.

http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/

ACTUALIZAR: Acabo de encontrar este otro enfoque:

Se llama método RYB (rojo, amarillo, azul) y se describe en este documento:

http://tresreyes.tk/mirror/ryb_TR.pdf

como "Composición de colores inspirada en pintura".

El algoritmo genera los colores y cada nuevo color se elige para maximizar su distancia euclidiana a los previamente seleccionados.

Aquí puede encontrar una buena implementación en javascript:

http://afriggeri.github.com/RYB/

ACTUALIZACIÓN 2:

Sciences Po Medialb acaba de lanzar una herramienta llamada "I want Hue" que genera paletas de colores para científicos de datos.Usando diferentes espacios de color y generando las paletas usando agrupamiento de k-medias o vectores de fuerza (gráficos de repulsión). Los resultados de esos métodos son muy buenos, muestran la teoría y una implementación en su página web.

http://tools.medialab.sciences-po.fr/iwanthue/index.php

En javascript:

function pastelColors(){
    var r = (Math.round(Math.random()* 127) + 127).toString(16);
    var g = (Math.round(Math.random()* 127) + 127).toString(16);
    var b = (Math.round(Math.random()* 127) + 127).toString(16);
    return '#' + r + g + b;
}

Vi la idea aquí: http://blog.functionalfun.net/2008/07/random-pastel-color-generator.html

Convertir a otra paleta es una forma muy superior de hacerlo.Hay una razón por la que hacen eso:otras paletas son "perceptuales", es decir, juntan colores aparentemente similares y al ajustar una variable cambia el color de una manera predecible.Nada de eso es cierto para RGB, donde no existe una relación obvia entre colores que "van bien juntos".

Una respuesta que no debe pasarse por alto, porque es sencilla y presenta ventajas, es la muestra de fotografías y pinturas de la vida real.Muestre tantos píxeles aleatorios como desee, colores aleatorios en miniaturas de fotografías de arte moderno, Cezanne, Van Gogh, Monnet, fotos...la ventaja es que puedes conseguir colores por temática y que sean colores orgánicos.simplemente coloque de 20 a 30 fotografías en una carpeta y tome una muestra aleatoria de una fotografía cada vez.

La conversión a valores HSV es un algoritmo de código muy extendido para una paleta de base psicológica.hsv es más fácil de aleatorizar.

En php:

function pastelColors() {
    $r = dechex(round(((float) rand() / (float) getrandmax()) * 127) + 127);
    $g = dechex(round(((float) rand() / (float) getrandmax()) * 127) + 127);
    $b = dechex(round(((float) rand() / (float) getrandmax()) * 127) + 127);

    return "#" . $r . $g . $b;
}

fuente: https://stackoverflow.com/a/12266311/2875783

He tenido éxito usando TríadaMezcla y CIE94 para evitar colores similares.La siguiente imagen utiliza colores de entrada rojo, amarillo y blanco.Ver aquí.

TriadMixing + CIE94

Aquí hay un generador de color rápido y sucio en C# (usando el 'enfoque RYB' descrito en este artículo).Es una reescritura de javascript.

Usar:

List<Color> ColorPalette = ColorGenerator.Generate(30).ToList();

Los dos primeros colores tienden a ser el blanco y un tono de negro.A menudo me los salto así (usando Linq):

List<Color> ColorsPalette = ColorGenerator
            .Generate(30)
            .Skip(2) // skip white and black
            .ToList(); 

Implementación:

public static class ColorGenerator
{

    // RYB color space
    private static class RYB
    {
        private static readonly double[] White = { 1, 1, 1 };
        private static readonly double[] Red = { 1, 0, 0 };
        private static readonly double[] Yellow = { 1, 1, 0 };
        private static readonly double[] Blue = { 0.163, 0.373, 0.6 };
        private static readonly double[] Violet = { 0.5, 0, 0.5 };
        private static readonly double[] Green = { 0, 0.66, 0.2 };
        private static readonly double[] Orange = { 1, 0.5, 0 };
        private static readonly double[] Black = { 0.2, 0.094, 0.0 };

        public static double[] ToRgb(double r, double y, double b)
        {
            var rgb = new double[3];
            for (int i = 0; i < 3; i++)
            {
                rgb[i] = White[i]  * (1.0 - r) * (1.0 - b) * (1.0 - y) +
                         Red[i]    * r         * (1.0 - b) * (1.0 - y) +
                         Blue[i]   * (1.0 - r) * b         * (1.0 - y) +
                         Violet[i] * r         * b         * (1.0 - y) +
                         Yellow[i] * (1.0 - r) * (1.0 - b) *        y +
                         Orange[i] * r         * (1.0 - b) *        y +
                         Green[i]  * (1.0 - r) * b         *        y +
                         Black[i]  * r         * b         *        y;
            }

            return rgb;
        }
    }

    private class Points : IEnumerable<double[]>
    {
        private readonly int pointsCount;
        private double[] picked;
        private int pickedCount;

        private readonly List<double[]> points = new List<double[]>();

        public Points(int count)
        {
            pointsCount = count;
        }

        private void Generate()
        {
            points.Clear();
            var numBase = (int)Math.Ceiling(Math.Pow(pointsCount, 1.0 / 3.0));
            var ceil = (int)Math.Pow(numBase, 3.0);
            for (int i = 0; i < ceil; i++)
            {
                points.Add(new[]
                {
                    Math.Floor(i/(double)(numBase*numBase))/ (numBase - 1.0),
                    Math.Floor((i/(double)numBase) % numBase)/ (numBase - 1.0),
                    Math.Floor((double)(i % numBase))/ (numBase - 1.0),
                });
            }
        }

        private double Distance(double[] p1)
        {
            double distance = 0;
            for (int i = 0; i < 3; i++)
            {
                distance += Math.Pow(p1[i] - picked[i], 2.0);
            }

            return distance;
        }

        private double[] Pick()
        {
            if (picked == null)
            {
                picked = points[0];
                points.RemoveAt(0);
                pickedCount = 1;
                return picked;
            }

            var d1 = Distance(points[0]);
            int i1 = 0, i2 = 0;
            foreach (var point in points)
            {
                var d2 = Distance(point);
                if (d1 < d2)
                {
                    i1 = i2;
                    d1 = d2;
                }

                i2 += 1;
            }

            var pick = points[i1];
            points.RemoveAt(i1);

            for (int i = 0; i < 3; i++)
            {
                picked[i] = (pickedCount * picked[i] + pick[i]) / (pickedCount + 1.0);
            }

            pickedCount += 1;
            return pick;
        }

        public IEnumerator<double[]> GetEnumerator()
        {
            Generate();
            for (int i = 0; i < pointsCount; i++)
            {
                yield return Pick();
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

    public static IEnumerable<Color> Generate(int numOfColors)
    {
        var points = new Points(numOfColors);

        foreach (var point in points)
        {
            var rgb = RYB.ToRgb(point[0], point[1], point[2]);
            yield return Color.FromArgb(
                (int)Math.Floor(255 * rgb[0]),
                (int)Math.Floor(255 * rgb[1]),
                (int)Math.Floor(255 * rgb[2]));
        }
    }
}

El método de David Crow en una R de dos líneas:

GetRandomColours <- function(num.of.colours, color.to.mix=c(1,1,1)) {
  return(rgb((matrix(runif(num.of.colours*3), nrow=num.of.colours)*color.to.mix)/2))
}
function fnGetRandomColour(iDarkLuma, iLightLuma) 
{       
  for (var i=0;i<20;i++)
  {
    var sColour = ('ffffff' + Math.floor(Math.random() * 0xFFFFFF).toString(16)).substr(-6);

    var rgb = parseInt(sColour, 16);   // convert rrggbb to decimal
    var r = (rgb >> 16) & 0xff;  // extract red
    var g = (rgb >>  8) & 0xff;  // extract green
    var b = (rgb >>  0) & 0xff;  // extract blue

    var iLuma = 0.2126 * r + 0.7152 * g + 0.0722 * b; // per ITU-R BT.709


    if (iLuma > iDarkLuma && iLuma < iLightLuma) return sColour;
  }
  return sColour;
} 

Para pastel, pase números enteros oscuros/claros de mayor luma, es decir, fnGetRandomColour(120, 250)

Créditos:todos los creditos a http://paulirish.com/2009/random-hex-color-code-snippets/stackoverflow.com/questions/12043187/how-to-check-if-hex-color-is-too-black

Adaptación de JavaScript de la respuesta original de David Crow, código específico de IE y Nodejs incluido.

generateRandomComplementaryColor = function(r, g, b){
    //--- JavaScript code
    var red = Math.floor((Math.random() * 256));
    var green = Math.floor((Math.random() * 256));
    var blue = Math.floor((Math.random() * 256));
    //---

    //--- Extra check for Internet Explorers, its Math.random is not random enough.
    if(!/MSIE 9/i.test(navigator.userAgent) && !/MSIE 10/i.test(navigator.userAgent) && !/rv:11.0/i.test(navigator.userAgent)){
        red = Math.floor((('0.' + window.crypto.getRandomValues(new Uint32Array(1))[0]) * 256));
        green = Math.floor((('0.' + window.crypto.getRandomValues(new Uint32Array(1))[0]) * 256));
        blue = Math.floor((('0.' + window.crypto.getRandomValues(new Uint32Array(1))[0]) * 256));
    };
    //---

    //--- nodejs code
    /*
    crypto = Npm.require('crypto');
    red = Math.floor((parseInt(crypto.randomBytes(8).toString('hex'), 16)) * 1.0e-19 * 256);
    green = Math.floor((parseInt(crypto.randomBytes(8).toString('hex'), 16)) * 1.0e-19 * 256);
    blue = Math.floor((parseInt(crypto.randomBytes(8).toString('hex'), 16)) * 1.0e-19 * 256);
    */
    //---

    red = (red + r)/2;
    green = (green + g)/2;
    blue = (blue + b)/2;

    return 'rgb(' + Math.floor(red) + ', ' + Math.floor(green) + ', ' + Math.floor(blue) + ')';
}

Ejecute la función usando:

generateRandomComplementaryColor(240, 240, 240);

podrías tenerlos dentro de un cierto brillo.eso controlaría un poco la cantidad de colores "neón".por ejemplo, si el "brillo"

brightness = sqrt(R^2+G^2+B^2)

estuviera dentro de un cierto límite alto, tendría un color claro y descolorido.Por el contrario, si estuviera dentro de un cierto límite bajo, sería más oscuro.Esto eliminaría cualquier color loco y destacado y, si eligieras un límite muy alto o muy bajo, todos estarían bastante cerca del blanco o del negro.

Va a ser difícil conseguir lo que quieres algorítmicamente: la gente ha estado estudiando la teoría del color durante mucho tiempo y ni siquiera conocen todas las reglas.

Sin embargo, hay alguno reglas que puede utilizar para seleccionar malas combinaciones de colores (es decir, existen reglas para contrastar colores y elegir colores complementarios).

Te recomiendo que visites la sección de arte de tu biblioteca y consultes libros sobre teoría del color para comprender mejor cuál es un buen color antes de intentar crear uno; parece que es posible que ni siquiera sepas por qué ciertas combinaciones funcionan y otras no. t.

-Adán

Recomiendo encarecidamente usar una función de sombreado CG HSVtoRGB, son increíbles...te brinda un control natural del color como un pintor en lugar de un control como un monitor CRT, ¡lo cual presumiblemente no eres!

Esta es una forma de hacer 1 valor flotante.es decir.Gris, en 1000 ds de combinaciones de color, brillo y saturación, etc.:

int rand = a global color randomizer that you can control by script/ by a crossfader etc.
float h = perlin(grey,23.3*rand)
float s = perlin(grey,54,4*rand)
float v = perlin(grey,12.6*rand)

Return float4 HSVtoRGB(h,s,v);

¡El resultado es una IMPRESIONANTE ALEATORIZACIÓN DE COLORES!No es natural, pero utiliza gradientes de color naturales y luce parámetros orgánicos y controlablemente iridiscentes/pastel.

Para perlin, puede utilizar esta función, es una versión rápida en zigzag de perlin.

function  zig ( xx : float ): float{    //lfo nz -1,1
    xx= xx+32;
    var x0 = Mathf.Floor(xx);
    var x1 = x0+1;
    var v0 = (Mathf.Sin (x0*.014686)*31718.927)%1;
    var v1 = (Mathf.Sin  (x1*.014686)*31718.927)%1;
    return Mathf.Lerp( v0 , v1 , (xx)%1 )*2-1;
}

Aquí hay algo que escribí para un sitio que creé.Generará automáticamente un color de fondo plano aleatorio para cualquier div con la clase .flat-color-gen.Jquery solo es necesario para agregar CSS a la página;no es necesario para la parte principal de esto, que es la generateFlatColorWithOrder() método.

Enlace JsFiddle

(function($) {
    function generateFlatColorWithOrder(num, rr, rg, rb) {
        var colorBase = 256;
        var red = 0;
        var green = 0;
        var blue = 0;
        num = Math.round(num);
        num = num + 1;
        if (num != null) {

            red = (num*rr) % 256;
            green = (num*rg) % 256;
            blue = (num*rb) % 256;
        }
        var redString = Math.round((red + colorBase) / 2).toString();
        var greenString = Math.round((green + colorBase) / 2).toString();
        var blueString = Math.round((blue + colorBase) / 2).toString();
        return "rgb("+redString+", "+greenString+", "+blueString+")";
        //return '#' + redString + greenString + blueString;
    }

    function generateRandomFlatColor() {
        return generateFlatColorWithOrder(Math.round(Math.random()*127));
    }

    var rr = Math.round(Math.random()*1000);
    var rg = Math.round(Math.random()*1000);
    var rb = Math.round(Math.random()*1000);
    console.log("random red: "+ rr);
    console.log("random green: "+ rg);
    console.log("random blue: "+ rb);
    console.log("----------------------------------------------------");
    $('.flat-color-gen').each(function(i, obj) {
        console.log(generateFlatColorWithOrder(i));
        $(this).css("background-color",generateFlatColorWithOrder(i, rr, rg, rb).toString());
    });
})(window.jQuery);

Usar colores distintos.

Escrito en javascript.

Genera una paleta de visualmente colores distintos.

Los distintos colores son altamente configurables:

  • Elige cuántos colores hay en la paleta.
  • Restringir el tono a un rango específico
  • Restringir el croma (saturación) a un rango específico
  • Restringir la luminosidad a un rango específico
  • Configurar la calidad general de la paleta.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top