iT邦幫忙

0

隨機產生數個顏色的演算法,顏色不能重複&相近&不能是藍色、紫色、黑色

目前在撰寫產生顏色的演算法上遇到困難,想請教一下這邊的大大有沒有什麼想法?

現在 input: properties 是個陣列,陣列內又有 property 物件,陣列的長度 n 代表需要產生 n 個顏色
期待的 output 是 n 個顏色,但有些限制

這些顏色不但不能一樣、相近色系(肉眼要可以明顯看出差異)
也不能是藍色、紫色及它們的相近色,也不能是黑色及接近黑色的深色

現在我的程式碼如下:

const getRandomColor = (properties) => {
    const addColorProperties = [];
    const initColor = Math.floor(Math.random() * 170);

    properties.forEach((property, i) => {
        const hue = Math.round((initColor + i * (170 / properties.length)) % 170);
        let saturation = Math.floor(Math.random() * (100 - 20) + 20);
        let lightness = Math.floor(Math.random() * (85 - 20) + 20);

        addColorProperties.push({ ...property, color: `hsl(${hue}, ${saturation}%, ${lightness}%)` });
    });
    return addColorProperties;
}

想法就是從 hsl 這邊產生顏色,hue 從 0~170 取值,因為 170 以上就是藍色紫色的範圍了
saturation, lightness 隨機產生
https://ithelp.ithome.com.tw/upload/images/20210811/20116883rSXIFv4Sz7.png
https://www.w3schools.com/colors/colors_hsl.asp

這有明顯的缺點是若要產生的顏色越多越容易顏色相近...
若有更好、可以改良的地方希望大家可以告訴我,感恩!!

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
1
japhenchen
iT邦超人 1 級 ‧ 2021-08-11 16:02:47
最佳解答

不要用亂數,因為RGB的範圍真的很大,R、G、B一個值就有有一個位元組就從0~255,三個乘起來就有一千多萬組,問題是眼睛沒辦法分辨這麼細的值(還沒算上色盲人士),要是一個不小心,random到鄰近值,那兩色差別,你怎麼辦?

最簡單的方式,用色差很大的List<Color>做表,每次取一個值,用過就抓下一個(用List.Count取餘數抓值),人多的話就把這個表色開設大一點

    //我瞎寫的
    List<Color> ColorArray = new List<Color>{
        Color.FromArgb(255,255,0,0),
        Color.FromArgb(255,0,255,0),
        Color.FromArgb(255,0,0,255),
        Color.FromArgb(255,50,0,0),
        Color.FromArgb(255,0,50,0),
        Color.FromArgb(255,0,0,50),
        //.................
    };
    
    for(int i = 0 ;i = People.Count-1 ;i++){
        var thisGuyColor = ColorArray[i % ColorArray.Count] ; 
        // .. 然後你就懂了
    }
看更多先前的回應...收起先前的回應...

哪些色你們不用,那就不要加進去就得了!

或是random一個0~15的值,讓色階數減少16倍
一樣跑Color.FromRGB()
丟進List<Color>裡
用過的不要加~~(用Contains檢查是否已存在)

Random rnd;
List<Color> arrColor = new List<Color>();
for (int i = 0; i < 100; i++)
{
    while (true)
    {
        rnd = new Random(Guid.NewGuid().GetHashCode());
        int R = (rnd.Next(16)+1)*16-1;
        rnd = new Random(Guid.NewGuid().GetHashCode());
        int G = (rnd.Next(16)+1)*16-1;
        rnd = new Random(Guid.NewGuid().GetHashCode());
        int B = (rnd.Next(16)+1)*16-1;
        Color newColor = Color.FromArgb(255, R, G, B);
        if (!arrColor.Contains(newColor))
        {
            arrColor.Add(newColor);
            break; // 沒那麼倒霉連續都一樣而逃不出去吧?如果花生,那可以去簽威力彩了
        }
    }
}
harry xie iT邦研究生 1 級 ‧ 2021-08-11 17:38:42 檢舉

好,謝謝大大詳細的回答

實際上之前也有考慮到需要配色的 properties 數量可能會超過會預先生成的一系列色票,所以才沒這麼做

不過我會再問看看要不要重新採用這個方式,感謝!

1
海綿寶寶
iT邦大神 1 級 ‧ 2021-08-11 14:57:09

隨機產生數個顏色的演算法,顏色不能重複&相近
肉眼要可以明顯看出差異

關鍵在於「定義」什麼是肉眼可以明顯看出差異
然後才是如何寫程式

如果用我的老花眼做例子
什麼 S,L 我根本看不出差別
H 的值是 0-360 ,理論上有 361 種顏色
但是我的老花眼
最多只能看出7種顏色的差別
/images/emoticon/emoticon06.gif

harry xie iT邦研究生 1 級 ‧ 2021-08-11 15:09:10 檢舉

嗯嗯,這個定義也是我該跟同事討論的
感謝~

0
淺水員
iT邦大師 6 級 ‧ 2021-08-11 18:33:26

使用 HSL 亂數產生顏色時要有一個觀念
HSL 類似以 L 為對稱軸的雙圓錐體
所以要做得比較完美的話,不能單純取亂數
還要考慮:

  1. L 越遠離中間(50%)時,顏色的變化越少
  2. S 越接近(0%)時,顏色的變化也越少

雙圓錐體模型可參考:HSI顏色模型

也許可以定義雙圓錐上的直線距離作為顏色差異的參考
應該會得到比較好的結果

harry xie iT邦研究生 1 級 ‧ 2021-08-11 18:48:26 檢舉

哇~這個我原本不知道的說,感謝!

淺水員 iT邦大師 6 級 ‧ 2021-08-13 15:05:59 檢舉

模擬一下 RGB 換算成 HSL 後
畫在柱狀坐標系後會呈現的樣子
https://jsbin.com/tigifanaxa/1/edit?html,js,output
HSL 中的 4096 色

我要發表回答

立即登入回答