動機
任意の色を取り、いくつかの色合いを明るくする方法を見つけたいので、1つの色から明るいバージョンへのニースグラデーションをプログラムで作成できます。グラデーションは、UIの背景として使用されます。
可能性1
もちろん、RGB値を分割して、特定の量だけ個別に増やすことができます。これは実際に私が欲しいものですか?
可能性2
2番目の考えは、RGBをHSV/HSB/HSL(色相、彩度、明度/明度/明度)に変換し、明るさを少し上げ、彩度を少し下げてから、RGBに戻すことでした。これは一般に望ましい効果をもたらしますか?
私は2番目のオプションに行きます。一般的に、RGBスペースは、色の操作(ある色から別の色への遷移の作成、色の明るく/暗くなど)を行うのにはあまり良くありません。以下は、RGBからHSLへ/からHSLに変換するクイック検索で見つけた2つのサイトです。
ウェッジが言った のように、あなたは物事を明るくするために乗算したいが、それは色の1つが飽和するまでしか機能しない(つまり、255以上にヒットする)。その時点で、値を255に固定することができますが、明るくなるにつれて微妙に色相を変更します。色相を維持するために、(中低)/(最高低)の比率を維持する必要があります。
Pythonの2つの関数を次に示します。 1つ目は、RGB値が255を超えた場合にクランプする単純なアプローチを実装します。 2番目は過剰な値を再分配して、色相をそのままにします。
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)
RGB値(224,128,0)で始まり、1.0、1.1、1.2などを2.0まで乗算するグラデーションを作成しました。上半分はclamp_rgb
を使用した結果で、下半分はredistribute_rgb
を使用した結果です。オーバーフローを再分配すると、RGBカラースペースを離れることなく、はるかに優れた結果が得られることが簡単にわかると思います。
比較のため、Pythonの colorsys
モジュールで実装されているHLSおよびHSV色空間の同じグラデーションを示します。 L
コンポーネントのみが変更され、結果のRGB値に対してクランプが実行されました。結果は似ていますが、ピクセルごとに色空間の変換が必要です。
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) );
}
私はこれをあちこちで使いました。
System.Windows.Forms名前空間のControlPaintクラスには、静的メソッドLightおよびDarkがあります。
public static Color Dark(Color baseColor, float percOfDarkDark);
これらのメソッドは、HLSColorのプライベート実装を使用します。この構造体がパブリックでSystem.Drawingにあったことを願っています。
別の方法として、Color構造体でGetHue、GetSaturation、GetBrightnessを使用してHSBコンポーネントを取得できます。残念ながら、逆変換は見つかりませんでした。
RGBに変換し、元の色とターゲット色(多くの場合白)の間を線形補間します。したがって、2つの色の間に16の色合いが必要な場合は、次のようにします。
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;
}
特定の色の明るいバージョンまたは暗いバージョンを取得するには、その明るさを変更する必要があります。これは、色をHSLまたはHSB色に変換しなくても簡単に実行できます。たとえば、色を明るくするには、次のコードを使用できます。
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);
さらに詳細が必要な場合は、 ブログで記事全体を読んでください 。
有用な回答を含む非常に類似した質問が以前に尋ねられました: 特定の色の暗い色または明るい色のバリエーションをどのように判断しますか?
簡単な答え:「十分な」だけが必要な場合はRGB値に定数を掛け、精度が必要な場合はHSVに変換します。
Andrewの回答とMarkの回答を使用して、 this (2013年1月現在、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) }
}
HS(LVB)に変換し、輝度を上げてからRGBに戻すことが、色相と彩度の値に影響を与えずに確実に色を明るくする唯一の方法です(つまり、色を変更せずに色を明るくするだけです)。
これを両方の方法で行いました。Possibility2を使用すると、はるかに優れた結果が得られます。
可能性1のために構築する単純なアルゴリズムは、限られた範囲の開始彩度に対してのみうまく機能するでしょう。
(1)使用する色と明るさを制限できる場合、および(2)レンダリングで計算を多く実行している場合は、Poss 1を調べてください。
UIの背景を生成するために、多くのシェーディング計算は必要ないので、Poss 2をお勧めします。
-Al。
パーティーに少し遅れましたが、javascript
またはnodejs
を使用する場合は、 tinycolor library を使用して、希望どおりに色を操作できます。
tinycolor("red").lighten().desaturate().toHexString() // "#f53d3d"
元の質問に関連する質問になるまで、この質問は見つかりませんでした。
ただし、これらの優れた答えからの洞察を使用します。このために、ニースの2ライナー関数をつなぎ合わせました。
16進数の色(またはRGB、ブレンド色)をプログラムで明るくまたは暗くする
方法1のバージョン。ただし、飽和状態を考慮します。キースが上記の答えで言ったように。 Lerpを使用して、Markが言及したのと同じ問題を解決したようですが、再配布はしません。の結果 shadeColor2
は、HSLで正しい方法を実行することにはるかに近いはずですが、オーバーヘッドはありません。
方法1:RGBをHSLに変換し、HSLを調整し、RGBに戻します。
方法2:LerpRGBカラー値- http://en.wikipedia.org/wiki/Lerp_(computing)
方法2のC#実装については、 この同様の質問に対する私の答え を参照してください。
白にアルファブレンドしたと仮定します。
oneMinus = 1.0 - amount
r = amount + oneMinus * r
g = amount + oneMinus * g
b = amount + oneMinus * b
amount
は0〜1で、0は元の色を返し、1は白を返します。
無効なものを表示するために明るくする場合は、背景色を何でもブレンドすることができます。
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)
はブレンドされる色であり、amount
は0〜1で、0は(r, g, b)
を返し、1は(dest.r, dest.g, dest.b)
を返します
グラデーションフェードアウトを作成する場合は、次の最適化をお勧めします。個々の色ごとにRGB-> HSB-> RGBを実行するのではなく、ターゲットカラーのみを計算する必要があります。ターゲットRGBがわかれば、RGB空間で中間値を計算するだけで、前後に変換する必要はありません。使用の線形遷移を計算するかどうかは、ある種の曲線です。
私は最初にナンバー1を試したでしょうが、ナンバー2はかなり良い音です。自分で試してみて、結果に満足しているかどうかを確認してください。テストの準備に10分ほどかかるようです。
技術的には、どちらも正しいとは思いませんが、オプション#2のバリエーションが必要だと思います。 RGB 990000を使用して「明るくする」という問題は、FFに到達するまで、実際には赤チャネル(値、明るさ、明るさ)に追加されるだけです。その後(赤一色)、彩度を降ろして、白一色になります。
特にRGBとLabを直接やり取りすることはできないため、変換は煩わしいものになりますが、クロミナンスと輝度の値を分離し、輝度を変更して必要なものを実現したいと思うと思います。
PythonでRGBカラーを明るくする例を次に示します。
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))
Delphiでこれを行う方法を示す ブログ投稿 があります。 ColorRGBToHSL関数とColorHLSToRGB関数は標準ライブラリの一部であるため、非常に簡単です。
color-tools Ruby library に色空間間で変換するコードがあります