Algoritma untuk secara acak menghasilkan palet warna yang menyenangkan secara estetika [ditutup]

301

Saya mencari algoritma sederhana untuk menghasilkan sejumlah besar warna acak yang menyenangkan secara estetika. Jadi tidak ada warna neon gila, warna yang mengingatkan pada feses, dll.

Saya telah menemukan solusi untuk masalah ini tetapi mereka bergantung pada palet warna alternatif daripada RGB. Saya lebih suka menggunakan RGB langsung daripada memetakan bolak-balik. Solusi lain ini juga paling banyak hanya dapat menghasilkan 32 atau lebih warna acak yang menyenangkan.

Ide apa pun akan bagus.

Brian Gianforcaro
sumber
2
Saya akan membuat situs web yang menghasilkan warna acak pada setiap kunjungan. Miliki suara "batu warna ini" / "warna ini menyebalkan". Kemudian urutkan berdasarkan rasio suara.
Nosredna
Anda bisa melihat HSL dan HSV.
Jim Keener
48
"warna yang mengingatkan kita pada kotoran" Aku menyukainya
lol
Itu bukan algoritma.
Matt The Ninja
Saya akan menambahkan komentar sejak pertanyaan ditutup. Saya belum mencobanya, tetapi akan menarik untuk mencoba cara fraktal atau prosedural, dengan menggunakan algoritma atau varian Midpoint Displacement ( lighthouse3d.com/opengl/terrain/index.php?mpd2 ) atau Perlin Noise, tetapi alih-alih ketinggian untuk mencampur komponen rgb warna.
alfoks

Jawaban:

426

Anda dapat meratakan nilai RGB warna acak dengan nilai warna konstan:

(contoh di Jawa)

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


Mencampur warna acak dengan putih (255, 255, 255) menciptakan pastel netral dengan meningkatkan kecerahan sambil menjaga rona warna asli. Pastel yang dihasilkan secara acak ini biasanya cocok satu sama lain, terutama dalam jumlah besar.

Berikut adalah beberapa warna pastel yang dihasilkan menggunakan metode di atas:

Pertama


Anda juga bisa mencampur warna acak dengan pastel konstan, yang menghasilkan serangkaian warna netral. Misalnya, menggunakan biru muda menghasilkan warna seperti ini:

Kedua


Lebih jauh, Anda bisa menambahkan heuristik ke generator Anda yang memperhitungkan warna komplementer atau tingkat naungan, tetapi semuanya tergantung pada kesan yang ingin Anda capai dengan warna acak Anda.

Beberapa sumber tambahan:

David Crow
sumber
3
Satu-satunya peringatan tampaknya adalah hilangnya kemampuan membedakan. Dengan mengambil rata-rata merah hijau dan biru dengan satu warna seperti putih, secara alami semua warna bergerak lebih dekat ke putih dan mengurangi perbedaan di antara mereka. Sebagai contoh jika Anda melihat screenshot pertama: Ketika hijau itu bersebelahan, pasti saya bisa membedakannya, tetapi bagaimana jika mereka tidak berdekatan dalam beberapa grafik yang diproduksi? Bisa jadi bermasalah.
Zelphir Kaltstahl
Saat membuat komponen warna acak, coba batasi batas atas dengan sesuatu yang kurang, seperti 200.
Nickolodeon
87

Saya akan menggunakan roda warna dan diberi posisi acak Anda bisa menambahkan sudut emas (137,5 derajat)

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

untuk mendapatkan warna yang berbeda setiap kali tidak tumpang tindih.

Menyesuaikan kecerahan untuk roda warna Anda bisa mendapatkan kombinasi warna cerah / gelap yang berbeda.

Saya telah menemukan posting blog ini yang menjelaskan dengan sangat baik masalah dan solusi menggunakan rasio emas.

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

UPDATE: Saya baru saja menemukan pendekatan lain ini:

Ini disebut metode RYB (merah, kuning, biru) dan dijelaskan dalam makalah ini:

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

sebagai "Pengomposisi Warna Terinspirasi Cat".

Algoritma menghasilkan warna dan setiap warna baru dipilih untuk memaksimalkan jarak euclidian ke yang sebelumnya dipilih.

Di sini Anda dapat menemukan implementasi yang baik dalam javascript:

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

PEMBARUAN 2:

The Sciences Po Medialb baru saja merilis alat yang disebut "I want Hue" yang menghasilkan palet warna untuk ilmuwan data. Menggunakan ruang warna yang berbeda dan menghasilkan palet dengan menggunakan k-means clustering atau vektor gaya (grafik tolakan). Hasil dari metode tersebut sangat baik, mereka menunjukkan teori dan implementasi di halaman web mereka.

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

Fgblanch
sumber
iWantHue adalah jawabannya. Pergi kesana. Terkesima.
Irongaze.com
23

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

Lihat idenya di sini: http://blog.functionalfun.net/2008/07/random-pastel-colour-generator.html

motobói
sumber
Tidak sepenuhnya benar: Anda perlu nol-padding untuk nomor satu digit juga ... Omong-omong , di sini adalah biola yang berfungsi untuk para pengunjung: jsfiddle.net/RedDevil/LLYBQ ----- Gores itu ... Saya tidak perhatikan bit +127 ... Tapi kemudian ini tidak akan menghasilkan nuansa gelap.
kumarharsh
2
Gagasan orisinalnya adalah untuk menghasilkan warna-warna yang menyenangkan secara sewenang-wenang. Nuansa gelap sepertinya tidak menyenangkan bagi saya;)
motobói
11

Mengubah ke palet lain adalah cara yang jauh lebih unggul untuk melakukan ini. Ada alasan mereka melakukan itu: palet lain adalah 'perseptual' - yaitu, mereka menempatkan warna yang serupa berdekatan, dan menyesuaikan satu variabel mengubah warna dengan cara yang dapat diprediksi. Tidak ada yang benar untuk RGB, di mana tidak ada hubungan yang jelas antara warna yang "cocok bersama".

Nick Johnson
sumber
6

Saya sudah sukses menggunakan TriadMixing dan CIE94 untuk menghindari warna serupa. Gambar berikut menggunakan warna input merah, kuning, dan putih. Lihat di sini .

TriadMixing + CIE94

Moriarty
sumber
5

Sebuah jawaban yang tidak boleh diabaikan, karena sederhana dan memberikan keuntungan, adalah pengambilan sampel foto dan lukisan kehidupan nyata. sampel sebanyak piksel acak yang Anda inginkan warna acak pada thumbnail gambar seni modern, cezanne, van gogh, monnet, foto ... keuntungannya adalah Anda bisa mendapatkan warna berdasarkan tema dan itu adalah warna organik. cukup masukkan 20 - 30 foto di folder dan sampel acak foto acak setiap kali.

Konversi ke nilai HSV adalah algoritma kode luas untuk palet berbasis psikologis. hsv lebih mudah untuk diacak.

com. dimengerti
sumber
1
mkweb.bcgsc.ca/color_summarizer/?analyze Berikut ini adalah alat online yang dapat menganalisis foto kehidupan nyata dan mengembalikan kepada Anda Grapher dari nilai-nilai RGB mengatakan dapat merasakan apa yang dimiliki foto kehidupan nyata dalam grafik mereka .... situs web yang sangat berguna, yang sangat penting jika Anda mencoba merancang algoritma avant-garde untuk warna acak
com.prehensible
4

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

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

Petr Bugyik
sumber
3

Berikut ini adalah penghasil warna yang cepat dan kotor di C # (menggunakan 'pendekatan RYB' yang dijelaskan dalam artikel ini ). Ini adalah penulisan ulang dari JavaScript .

Menggunakan:

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

Dua warna pertama cenderung berwarna putih dan hitam. Saya sering melewati mereka seperti ini (menggunakan Linq):

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

Penerapan:

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]));
        }
    }
}
m1ch4ls
sumber
Saya telah menghapus jawaban Java tetapi jika diperlukan, versi Java dapat dilihat di Intisari ini: gist.github.com/lotsabackscatter/3f6a658fd7209e010dad
Dylan Watson
3

Metode David Crow dalam R two-liner:

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

Untuk pastel, masukkan bilangan bulat gelap / terang luma yang lebih tinggi - yaitu fnGetRandomColour (120, 250)

Kredit: semua kredit ke http://paulirish.com/2009/random-hex-color-code-snippets/ stackoverflow.com/questions/12043187/how-to-check-if-hex-color-is-too-black

ChilledFlame
sumber
1

Adaptasi JavaScript atas jawaban asli David Crow, termasuk kode spesifik IE dan Nodejs.

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

Jalankan fungsi menggunakan:

generateRandomComplementaryColor(240, 240, 240);
Skeptis
sumber
1

Gunakan warna berbeda .

Ditulis dalam javascript.

Ini menghasilkan palet warna yang berbeda secara visual .

warna-berbeda sangat dapat dikonfigurasi:

  • Pilih berapa banyak warna dalam palet
  • Batasi rona ke rentang tertentu
  • Batasi kroma (saturasi) ke rentang tertentu
  • Batasi cahaya ke rentang tertentu
  • Konfigurasikan kualitas umum palet
InternalFX
sumber
0

Anda bisa memilikinya dalam kecerahan tertentu. yang akan mengontrol jumlah warna "neon" sedikit. misalnya, jika "kecerahan"

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

berada dalam batas tinggi tertentu, itu akan memiliki warna terang yang luntur. Sebaliknya, jika berada dalam batas bawah tertentu, itu akan menjadi lebih gelap. Ini akan menghilangkan warna-warna gila dan menonjol dan jika Anda memilih batas yang benar-benar tinggi atau sangat rendah, semuanya akan mendekati warna putih atau hitam.

helloandre
sumber
0

Akan sulit untuk mendapatkan apa yang Anda inginkan secara algoritmik - orang telah mempelajari teori warna sejak lama, dan mereka bahkan tidak tahu semua aturannya.

Namun, ada beberapa aturan yang dapat Anda gunakan untuk menyisihkan kombinasi warna yang buruk (yaitu, ada aturan untuk bentrok warna, dan memilih warna komplementer).

Saya sarankan Anda mengunjungi bagian seni perpustakaan Anda dan memeriksa buku-buku tentang teori warna untuk mendapatkan pemahaman yang lebih baik tentang warna apa yang baik sebelum Anda mencoba membuatnya - sepertinya Anda bahkan tidak tahu mengapa kombinasi tertentu bekerja dan yang lain tidak. t.

-Adam

Adam Davis
sumber
0

Saya sangat merekomendasikan menggunakan fungsi CG HSVtoRGB shader, mereka luar biasa ... itu memberi Anda kontrol warna alami seperti seorang pelukis, bukan kontrol seperti monitor crt, yang mungkin bukan Anda!

Ini adalah cara untuk membuat 1 nilai float. yaitu abu-abu, menjadi 1000 ds kombinasi warna dan kecerahan dan saturasi dll:

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

hasilnya adalah RANDOMISASI WARNA MENGAGUMKAN! itu tidak alami tetapi menggunakan gradien warna alami dan terlihat organik dan dapat diatur parameter irridescent / pastel.

Untuk perlin, Anda dapat menggunakan fungsi ini, ini adalah versi cepat zig zag dari 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;
}
com. dimengerti
sumber
0

Ini adalah sesuatu yang saya tulis untuk situs yang saya buat. Ini akan secara otomatis menghasilkan warna latar belakang datar acak untuk setiap div dengan kelas .flat-color-gen. Jquery hanya diperlukan untuk tujuan menambahkan css ke halaman; itu tidak diperlukan untuk bagian utama ini, yaitu generateFlatColorWithOrder()metode.

JsFiddle Link

(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);
Efraim
sumber