Question

Motivation

J'aimerais trouver un moyen de prendre une couleur arbitraire et de l’éclaircir de quelques nuances afin de pouvoir créer par programme un joli dégradé d’une couleur à une version plus claire. Le dégradé sera utilisé comme arrière-plan dans une interface utilisateur.

Possibilité 1

Évidemment, je peux simplement séparer les valeurs RVB et les augmenter individuellement d’un certain montant. Est-ce vraiment ce que je veux?

Possibilité 2

Ma deuxième idée était de convertir le RVB en HSV / HSB / HSL (Hue, Saturation, Valeur / Luminosité / Luminosité), d’augmenter légèrement la luminosité, de diminuer légèrement la saturation, puis de le reconvertir en RVB. Cela aura-t-il l'effet souhaité en général?

Était-ce utile?

La solution

Je choisirais la deuxième option. De manière générale, l’espace RVB n’est pas vraiment adapté à la manipulation des couleurs (création d’une transition d’une couleur à l’autre, éclaircissement / assombrissement d’une couleur, etc.). Voici deux sites que j'ai trouvés avec une recherche rapide pour convertir de / en RVB vers / de HSL:

Autres conseils

Comme Wedge a déclaré , vous voulez multiplier pour rendre les choses plus lumineuses, mais cela fonctionne uniquement jusqu’à ce que l’une des couleurs soit saturée (c’est-à-dire égale à 255 ou plus). À ce stade, vous pouvez simplement fixer les valeurs à 255, mais vous modifierez subtilement la teinte à mesure que vous allégerez. Pour conserver la teinte, vous souhaitez conserver le rapport (moyen-inférieur) / (plus élevé-inférieur).

Voici deux fonctions en Python. Le premier met en œuvre l'approche naïve qui consiste à fixer les valeurs RVB à 255 si elles sont dépassées. La seconde redistribue les valeurs en excès pour conserver la teinte intacte.

def clamp_rgb(r, g, b):
    return min(255, int(r)), min(255, int(g)), min(255, int(b))

def redistribute_rgb(r, g, b):
    threshold = 255.999
    m = max(r, g, b)
    if m <= threshold:
        return int(r), int(g), int(b)
    total = r + g + b
    if total >= 3 * threshold:
        return int(threshold), int(threshold), int(threshold)
    x = (3 * threshold - total) / (3 * m - total)
    gray = threshold - x * m
    return int(gray + x * r), int(gray + x * g), int(gray + x * b)

J'ai créé un dégradé commençant par la valeur RVB (224,128,0) et multiplié par 1,0, 1,1, 1,2, etc. jusqu'à 2,0. La moitié supérieure correspond au résultat avec clamp_rgb et la moitié inférieure correspond au résultat avec redistribute_rgb . Je pense qu'il est facile de voir que la redistribution des débordements donne un bien meilleur résultat, sans avoir à quitter l'espace colorimétrique RVB.

Dégradé de luminosité avec serrage (en haut) et redistribution (en bas)

À titre de comparaison, voici le même dégradé dans les espaces colorimétriques HLS et HSV, mis en œuvre par colorsys . Seul le composant L a été modifié et un verrouillage a été effectué sur les valeurs RVB résultantes. Les résultats sont similaires, mais nécessitent des conversions d'espace colorimétrique pour chaque pixel.

Dégradé de luminosité avec HLS (en haut) et HSV (en bas)

En C #:

public static Color Lighten(Color inColor, double inAmount)
{
  return Color.FromArgb(
    inColor.A,
    (int) Math.Min(255, inColor.R + 255 * inAmount),
    (int) Math.Min(255, inColor.G + 255 * inAmount),
    (int) Math.Min(255, inColor.B + 255 * inAmount) );
}

Je l'ai utilisé partout.

La classe ControlPaint dans l'espace de noms System.Windows.Forms a des méthodes statiques Light and Dark:

public static Color Dark(Color baseColor, float percOfDarkDark);

Ces méthodes utilisent une implémentation privée de HLSColor. Je souhaite que cette structure soit publique et dans System.Drawing.

Vous pouvez également utiliser GetHue, GetSaturation, GetBrightness sur la structure Color pour obtenir les composants HSB. Malheureusement, je n'ai pas trouvé la conversion inverse.

Convertissez-le en RVB et interpolez-le linéairement entre la couleur d'origine et la couleur cible (souvent le blanc). Donc, si vous voulez 16 nuances entre deux couleurs, vous faites:


for(i = 0; i < 16; i++)
{
  colors[i].R = start.R + (i * (end.R - start.R)) / 15;
  colors[i].G = start.G + (i * (end.G - start.G)) / 15;
  colors[i].B = start.B + (i * (end.B - start.B)) / 15;
}

Pour obtenir une version plus claire ou plus sombre d’une couleur donnée, vous devez en modifier la luminosité. Vous pouvez le faire facilement, même sans convertir votre couleur en HSL ou couleur HSB. Par exemple, pour rendre une couleur plus claire, vous pouvez utiliser le code suivant:

float correctionFactor = 0.5f;
float red = (255 - color.R) * correctionFactor + color.R;
float green = (255 - color.G) * correctionFactor + color.G;
float blue = (255 - color.B) * correctionFactor + color.B;
Color lighterColor = Color.FromArgb(color.A, (int)red, (int)green, (int)blue);

Si vous souhaitez plus de détails, lisez l'histoire complète. sur mon blog .

Une question très similaire, avec des réponses utiles, a déjà été posée: Comment déterminer plus sombre ou Variante de couleur plus claire d’une couleur donnée?

Réponse courte: multipliez les valeurs RVB par une constante si vous avez simplement besoin de "assez bon", traduisez en HSV si vous avez besoin de précision.

J'ai utilisé les réponses d'Andrew et de Mark pour rendre this (à partir du 1/2013 aucune plage entrée pour ff).

function calcLightness(l, r, g, b) {
    var tmp_r = r;
    var tmp_g = g;
    var tmp_b = b;

    tmp_r = (255 - r) * l + r;
    tmp_g = (255 - g) * l + g;
    tmp_b = (255 - b) * l + b;

    if (tmp_r > 255 || tmp_g > 255 || tmp_b > 255) 
        return { r: r, g: g, b: b };
    else 
        return { r:parseInt(tmp_r), g:parseInt(tmp_g), b:parseInt(tmp_b) }
}

entrer la description de l'image ici

La conversion en HS (LVB), l’augmentation de la luminosité, puis la conversion en RVB est le seul moyen d’éclaircir la couleur de manière fiable sans affecter les valeurs de teinte et de saturation (c’est-à-dire de ne l’éclairer que de manière différente). .

Je l'ai fait dans les deux sens - vous obtenez de bien meilleurs résultats avec Possibility 2.

Tout algorithme simple que vous construisez pour la possibilité 1 ne fonctionnera probablement bien que pour une plage limitée de saturations de départ.

Vous voudrez peut-être examiner Poss 1 si (1) vous pouvez limiter les couleurs et les luminosités utilisées et (2) que vous effectuez beaucoup le calcul dans un rendu.

La génération de l'arrière-plan d'une interface utilisateur ne nécessite pas beaucoup de calculs d'ombrage. Je suggère donc Poss 2.

-Al.

SI vous voulez produire un fondu en dégradé, je suggérerais l'optimisation suivante: Plutôt que de faire RVB-> HSB-> RVB pour chaque couleur individuelle, vous ne devez calculer que la couleur cible. Une fois que vous connaissez le RVB cible, vous pouvez simplement calculer les valeurs intermédiaires dans l’espace RVB sans avoir à convertir en arrière. Que vous calculiez une transition linéaire d’utilisation, une courbe quelconque vous appartient.

Méthode 1: convertissez RVB en HSL, ajustez HSL, reconvertissez-le en RVB.

Méthode 2: Lerp les valeurs de couleur RVB - http: //fr.wikipedia.org/wiki/Lerp_(computing)

Voir ma réponse à cette question similaire pour une implémentation C # de la méthode 2.

Imaginez que votre alpha soit mélangé au blanc:

oneMinus = 1.0 - amount
r = amount + oneMinus * r
g = amount + oneMinus * g
b = amount + oneMinus * b

montant est compris entre 0 et 1, 0 renvoyant la couleur d'origine et 1 renvoyant le blanc.

Si vous souhaitez afficher quelque chose de désactivé, vous pouvez fusionner la couleur d'arrière-plan avec la couleur d'arrière-plan:

oneMinus = 1.0 - amount
r = amount * dest_r + oneMinus * r
g = amount * dest_g + oneMinus * g
b = amount * dest_b + oneMinus * b

(dest_r, dest_g, dest_b) est la couleur mélangée à et montant est compris entre 0 et 1, zéro renvoyant (r, g, b) et 1 renvoyant (dest.r, dest.g, dest.b)

Je n'ai trouvé cette question qu'après qu'elle soit devenue une question liée à ma question initiale.

Toutefois, utilisez les informations de ces excellentes réponses. J'ai assemblé une belle fonction à deux doublures pour cela:

Éclaircir ou assombrir par programme une couleur hexadécimale (ou rgb, et mélanger les couleurs)

C’est une version de la méthode 1. Mais avec sur saturation prise en compte. Comme l'a dit Keith dans sa réponse ci-dessus; utiliser Lerp pour résoudre apparemment le même problème que Mark a mentionné, mais sans redistribution. Les résultats de shadeColor2 devraient être beaucoup plus proches d'une bonne manière de procéder avec HSL, mais sans surcharge.

Un peu tard dans la soirée, mais si vous utilisez javascript ou nodejs , vous pouvez utiliser bibliothèque minuscule , et manipulez la couleur comme vous le souhaitez:

tinycolor("red").lighten().desaturate().toHexString() // "#f53d3d" 

J'aurais d'abord essayé le numéro 1, mais le numéro 2 me semble plutôt bon. Essayez de le faire vous-même et voyez si vous êtes satisfait du résultat, il semble qu'il vous faudra peut-être 10 minutes pour réaliser un test.

Techniquement, je ne pense pas que ce soit le cas, mais je pense que vous souhaitez une variante de l’option n ° 2. Le problème étant que pris RGB 990000 et "éclaircissant" cela ajouterait simplement le canal rouge (valeur, luminosité, luminosité) jusqu'à ce que vous obteniez FF. Après cela (rouge fixe), il faudrait supprimer la saturation pour atteindre le blanc.

Les conversions deviennent agaçantes, d’autant plus que vous ne pouvez pas accéder directement à RGB et Lab, mais je pense que vous voulez vraiment séparer les valeurs de chrominance et de luminance, et simplement modifier la luminosité pour obtenir vraiment ce que vous voulez. / p>

Vous trouverez le code pour convertir les espaces colorimétriques dans le color -tools bibliothèque Ruby

J'ai un article de blog cela montre comment faire cela à Delphi. C'est très simple, car les fonctions ColorRGBToHSL et ColorHLSToRGB font partie de la bibliothèque standard.

Voici un exemple d'éclaircissement d'une couleur RVB en Python:

def lighten(hex, amount):
    """ Lighten an RGB color by an amount (between 0 and 1),

    e.g. lighten('#4290e5', .5) = #C1FFFF
    """
    hex = hex.replace('#','')
    red = min(255, int(hex[0:2], 16) + 255 * amount)
    green = min(255, int(hex[2:4], 16) + 255 * amount)
    blue = min(255, int(hex[4:6], 16) + 255 * amount)
    return "#%X%X%X" % (int(red), int(green), int(blue))
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top