プログラムで色を明るくする
-
02-07-2019 - |
質問
モチベーション
任意の色を使用して、それをいくつかの色合いで明るくする方法を見つけて、プログラムで 1 つの色から明るいバージョンへの素敵なグラデーションを作成できるようにしたいと考えています。グラデーションは UI の背景として使用されます。
可能性1
明らかに、RGB 値を分割し、一定量ずつ個別に増やすことができます。これは本当に私が望んでいることなのでしょうか?
可能性2
次に考えたのは、RGB を HSV/HSB/HSL (色相、彩度、明度/明るさ/明度) に変換し、明るさを少し上げ、彩度を少し下げてから、RGB に変換し直すことでした。これは一般的に望ましい効果をもたらしますか?
解決
2番目のオプションに進みます。一般的に、RGBスペースは、色の操作(ある色から別の色への遷移の作成、色の明るく/暗くなど)を行うのにはあまり良くありません。以下は、RGBからHSLへ/から変換するクイック検索で見つけた2つのサイトです。
- 「コンピューターグラフィックスの基礎」
- C#のソースコード-他のプログラミング言語に簡単に適応できる。
他のヒント
ウェッジが言ったように、あなたは物事を明るくするために掛け合わせたいが、色の1つが飽和する(つまり、255以上に達する)まで動作します。その時点で、値を255に固定することができますが、明るくなるにつれて微妙に色相を変更します。色相を保持するには、(中低)/(最高低)の比率を維持する必要があります。
Pythonには2つの関数があります。最初の方法は、RGB値が超過した場合に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
モジュール。 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の回答を使用して、これを作成しました(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。
グラデーションフェードアウトを作成する場合は、次の最適化をお勧めします。個々の色ごとにRGB-&gt; HSB-&gt; RGBを行うのではなく、ターゲットカラーのみを計算する必要があります。ターゲットRGBがわかれば、RGB空間で中間値を計算するだけで、前後に変換する必要はありません。使用の線形遷移を計算するかどうかは、ある種の曲線です。
方法1:RGBをHSLに変換し、HSLを調整し、RGBに戻します。
方法2:RGBカラー値を Lerp - http: //en.wikipedia.org/wiki/Lerp_(computing)
アルファブレンドを白にしたふりをする:
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までで、ゼロは(r、g、 b)
および1が(dest.r、dest.g、dest.b)
この質問は、元の質問に関連する質問になるまで見つかりませんでした。
ただし、これらのすばらしい答えから得られた洞察を使用してください。このために、2ライナー関数を作成しました:
プログラムで16進数の色を明るくまたは暗くする(またはrgb、およびブレンド色)
これは、方法1のバージョンです。ただし、飽和状態を考慮しています。キースが上記の答えで言ったように。 Lerpを使用して、Markが言及したのと同じ問題を解決したようですが、再配布はしません。 shadeColor2
の結果は、HSLを使用した正しい方法に非常に近いはずですが、オーバーヘッドはありません。
パーティーに少し遅れましたが、 javascript
または nodejs
を使用する場合は、 tinycolorライブラリを使用して、希望する方法で色を操作します。
tinycolor("red").lighten().desaturate().toHexString() // "#f53d3d"
最初に#1を試してみましたが、#2はかなりいい音がします。自分で試してみて、結果に満足しているかどうかを確認してください。テストの準備に10分ほどかかるようです。
技術的には、どちらも正しいとは思いませんが、オプション#2のバリエーションが必要だと思います。問題は、RGB 990000と「ライトニング」を使用したことです。 FFに到達するまで、実際には単にレッドチャネル(値、明るさ、明るさ)に追加されます。その後(赤一色)、彩度を下げて白一色になります。
特にRGBとLabを直接やり取りすることはできないため、変換は煩わしくなりますが、クロミナンスと輝度の値を分離し、輝度を変更するだけで目的の結果を得ることができます。
色空間間で変換するコードは次のとおりです。 カラーツール Ruby ライブラリ
ブログ投稿これは、Delphiでこれを行う方法を示しています。 ColorRGBToHSL関数とColorHLSToRGB関数は標準ライブラリの一部であるため、非常に簡単です。
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))