Algorithme de génération de palette de couleurs



Vous cherchez une belle palette de couleurs pour le site? Rétroéclairage RVB récemment installé à la maison, ou vous voulez peindre la pièce dans de nouvelles couleurs? Ou vous avez acheté un clavier avec rétroéclairage couleur et vous souhaitez l'utiliser au maximum? Quelle que soit la situation dans laquelle vous vous trouvez, vous êtes sûr de toujours ajuster les schémas de couleurs.

En tant que programmeur, j'ai rapidement écrit quelques lignes de code pour générer des palettes de couleurs aléatoires. Sentant immédiatement qu'une telle approche pourrait ne pas donner les meilleurs résultats, en quelques minutes j'ai implémenté le bouton «recharger» de la palette. Il m'a semblé que pour avoir un bon plan, il fallait juste un peu de chance et de patience.

J'avais tort. La génération aléatoire de palettes de couleurs craint. De temps en temps, une belle couleur coexiste avec une nuance laide et sale de brun ou de jaune. Les collections de couleurs sont toujours soit trop sombres, soit trop claires et à faible contraste, ou les ensembles sont constitués de couleurs très similaires. Il fallait trouver une solution différente.

Espaces colorimétriques


Commençons par la théorie. Aujourd'hui, les espaces colorimétriques sont largement utilisés pour classer les couleurs:

sRGB


RVB signifie Red Green Blue . Voici comment fonctionnent les écrans: ils émettent de la lumière dans trois canaux de couleurs, qui sont mélangés dans différentes proportions pour produire toutes sortes de couleurs. La valeur dans chaque canal varie de 0 à 255. R:0, G:0, B:0 (ou # 000000 en expression hexadécimale) est noir et R:255, G:255, B:255 (ou #ffffff ) - blanc.

Laboratoire Cie


L'espace colorimétrique du CIE Lab est plus large que sRGB et comprend toutes les couleurs perçues par l'homme. Il a été créé dans l'attente de l'universalité de la perception. En d'autres termes, la distance entre les couleurs correspond à la différence subjective: si les valeurs des deux couleurs sont proches l'une de l'autre, elles se ressemblent. D'un autre côté, deux couleurs très éloignées l'une de l'autre sont également perçues comme complètement différentes. Dans CIE Lab, plus d'espace est alloué pour les couleurs saturées que pour l'obscurité et la lumière. Soit dit en passant, pour l'œil humain, le vert très foncé est presque impossible à distinguer du noir. De plus, cet espace colorimétrique est tridimensionnel: L signifie légèreté (de 0,0 à 1,0), a et b (d'environ -1,0 à 1,0) sont des canaux de couleur.

HCL


Si RVB décrit comment l'affichage affiche les couleurs et le laboratoire CIE comment nous les percevons, alors HCL est l'espace colorimétrique qui décrit le mieux notre façon de penser les couleurs. Il est également tridimensionnel, H signifie teinte (0 à 360 degrés), signifie chroma et L signifie luminance (les deux sont mesurés de 0,0 à 1,0).

Je recommande d'utiliser CIE Lab pour les calculs et HCL pour représenter les palettes à l'utilisateur. Si vous le souhaitez, vous pouvez convertir les valeurs de ces espaces en RVB.

Décomposition de l'espace colorimétrique


Comme je devais obtenir un ensemble de couleurs uniques et individuelles, nous jetons d'abord celles qui se ressemblent beaucoup. L'espace colorimétrique sera tridimensionnel et l'algorithme de regroupement k-means est parfait pour séparer de tels ensembles de données de faible dimension. Il essaie de décomposer les données (dans notre cas, l'espace colorimétrique) en k zones distinctes. Et puis la palette est assemblée à partir des points centraux des grappes dans ces zones. Le gif montre un affichage bidimensionnel de l'algorithme dans l'espace tridimensionnel du laboratoire CIE.

Écrire un code


En utilisant la méthode k-means implémentée sur Go, le problème est résolu en quelques lignes de code. Préparez d'abord les valeurs de couleur dans l'espace CIE Lab:

 var d clusters.Observations for l := 0.2; l <= 0.8; l += 0.05 { for a := -1.0; a < 1.0; a += 0.1 { for b := -1.0; b < 1.0; b += 0.1 { d = append(d, clusters.Coordinates{l, a, b}) } } } 

J'ai déjà pris quelques paramètres et imposé certaines restrictions sur les couleurs générées. Dans cet exemple, nous allons jeter les couleurs trop sombres (luminosité <0,2) et trop claires (luminosité> 0,8).

Développez l'espace colorimétrique nouvellement créé:

 km := kmeans.New() clusters, _ := km.Partition(d, 8) 

La fonction de Partition renvoie des tranches de huit grappes. Chaque cluster a un point central, qui est une couleur distincte dans un espace donné. Ses coordonnées peuvent facilement être converties en une valeur RVB hexadécimale:

 col := colorful.Lab(c.Center[0], c.Center[1], c.Center[2]) col.Clamped().Hex() 

N'oubliez pas qu'un laboratoire CIE est plus large que RVB, ce qui signifie que certaines valeurs de laboratoire ne peuvent pas être converties en RVB. Ces valeurs peuvent être converties en utilisant Clamped aux couleurs les plus proches dans l'espace RVB.

Code complet


 package main import ( "github.com/muesli/kmeans" "github.com/muesli/clusters" colorful "github.com/lucasb-eyer/go-colorful" ) func main() { // Create data points in the CIE L*a*b* color space // l for lightness, a & b for color channels var d clusters.Observations for l := 0.2; l <= 0.8; l += 0.05 { for a := -1.0; a <= 1.0; a += 0.1 { for b := -1.0; b <= 1.0; b += 0.1 { d = append(d, clusters.Coordinates{l, a, b}) } } } // Partition the color space into 8 clusters km := kmeans.New() clusters, _ := km.Partition(d, 8) for _, c := range clusters { col := colorful.Lab(c.Center[0], c.Center[1], c.Center[2]) fmt.Println("Color as Hex:", col.Clamped().Hex()) } } 

Un ensemble de huit (pas si) couleurs aléatoires générées par ce code:



Définissez votre propre espace colorimétrique


Ajoutez plus de contrôle sur la génération des couleurs. Nous pouvons facilement gérer les données utilisées pour d'autres calculs, sélectionnant ainsi l'espace colorimétrique pour répondre à nos besoins. Générez une palette pastel:

 func pastel(c colorful.Color) bool { _, s, v := col.Hsv() return 0.2 <= s && s <= 0.4 && 0.7 <= v && v <= 1.0 } for l := 0.0; l <= 1.0; l += 0.05 { for a := -1.0; a <= 1.0; a += 0.1 { for b := -1.0; b <= 1.0; b += 0.1 { col := colorful.Lab(l, a, b) if col.IsValid() && pastel(col) { d = append(d, clusters.Coordinates{l, a, b}) } } } } 

Un autre espace colorimétrique est le HSV , les lettres du nom signifient la teinte, la saturation et la luminosité. Dans cet espace, les couleurs pastel ont généralement une luminosité élevée et une faible saturation.

Voici ce qui s'est passé:



Vous pouvez également filtrer les couleurs par leur saturation (chrominance) et leur luminosité pour obtenir un ensemble de tons «chauds»:

 func warm(col colorful.Color) bool { _, c, l := col.Hcl() return 0.1 <= c && c <= 0.4 && 0.2 <= l && l <= 0.5 } 

Résultat:



Forfait Gamut


Je travaille sur une bibliothèque appelée gamut , qui rassemblera toutes les pièces décrites ici dans un package pratique sur Go, qui vous permet de générer et de gérer des palettes de couleurs et des thèmes. Vous pouvez déjà l'essayer, mais il fonctionne toujours.

Source: https://habr.com/ru/post/fr414455/


All Articles