Программно осветить цвет
Мотивация
Я хотел бы найти способ сделать произвольный цвет и осветлить его несколькими оттенками, чтобы я мог программно создать хороший градиент от одного цвета до более легкой версии. Градиент будет использоваться в качестве фона в пользовательском интерфейсе.
Возможность 1
Очевидно, я могу просто разделить значения RGB и увеличить их индивидуально на определенную сумму. Это действительно то, что я хочу?
Возможность 2
Моя вторая мысль заключалась в том, чтобы преобразовать RGB в HSV/HSB/HSL (Hue, Saturation, Value/Brightness/Lightness), немного увеличить яркость, немного уменьшить насыщенность и затем преобразовать ее в RGB. Будет ли это иметь желаемый эффект вообще?
Ответы
Ответ 1
Я бы выбрал второй вариант. Вообще говоря, пространство RGB не очень хорошо подходит для манипулирования цветами (создание перехода от одного цвета к другому, осветление/затемнение цвета и т.д.). Ниже приведены два сайта, которые я нашел с быстрым поиском для преобразования из/в RGB в/из HSL:
Ответ 2
Как сказал Клин, вы хотите размножаться, чтобы сделать вещи ярче, но это работает только до тех пор, пока один из цветов не станет насыщенным (т.е. достигает 255 или больше). В этот момент вы можете просто привязать значения до 255, но вы будете тонко менять оттенок, когда вы становитесь легче. Чтобы сохранить оттенок, вы хотите сохранить соотношение (средний-самый низкий)/(самый высокий-самый низкий).
Вот две функции в Python. Первый реализует наивный подход, который просто зажимает значения RGB до 255, если они перейдут. Второй перераспределяет избыточные значения, чтобы сохранить оттенок неповрежденным.
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.
Для сравнения здесь один и тот же градиент в цветовых пространствах HLS и HSV, реализованный модулем Python colorsys
. Был изменен только компонент L
, а зажатие выполнялось по полученным значениям RGB. Результаты аналогичны, но требуют преобразования цветового пространства для каждого пикселя.
Ответ 3
В С#:
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) );
}
Я использовал это повсюду.
Ответ 4
Класс ControlPaint в пространстве имен System.Windows.Forms имеет статические методы Light and Dark:
public static Color Dark(Color baseColor, float percOfDarkDark);
Эти методы используют частную реализацию HLSColor. Я хочу, чтобы эта структура была общедоступной и в System.Drawing.
Кроме того, вы можете использовать GetHue, GetSaturation, GetBrightness на Color struct для получения компонентов HSB. К сожалению, я не нашел обратного преобразования.
Ответ 5
Преобразуйте его в RGB и линейно интерполируйте между исходным цветом и целевым цветом (часто белый). Итак, если вы хотите 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;
}
Ответ 6
Чтобы получить более светлую или более темную версию данного цвета, вы должны изменить его яркость. Вы можете сделать это легко даже без преобразования цвета в 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);
Если вам нужна дополнительная информация, прочитайте полную статью в своем блоге.
Ответ 7
Очень похожий вопрос с полезными ответами был задан ранее:
Как определить более темный или более светлый вариант цвета данного цвета?
Короткий ответ: умножьте значения RGB на константу, если вам просто нужно "достаточно хорошо", перевести на HSV, если вам нужна точность.
Ответ 8
Я использовал Andrew answer и Mark answer, чтобы сделать this (начиная с 1/2013 нет ввода диапазона для 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) }
}
Ответ 9
Преобразование в HS (LVB), увеличение яркости и последующее преобразование обратно в RGB - это единственный способ надежно осветить цвет, не влияя на значения оттенка и насыщенности (то есть только осветить цвет, не меняя его каким-либо другим способом).
Ответ 10
Я сделал это в обоих направлениях - вы получите намного лучшие результаты с возможностью 2.
Любой простой алгоритм, который вы создаете для возможности 1, вероятно, будет работать только для ограниченного диапазона начальных насыщений.
Вы бы хотели посмотреть в Пояс 1, если (1) вы можете ограничить используемые цвета и яркости, и (2) вы много выполняете вычисления в рендеринге.
Для создания фона для пользовательского интерфейса не потребуется очень много вычислений затенения, поэтому я предлагаю параметр 2. 2.
-Аль.
Ответ 11
ЕСЛИ вы хотите произвести угасание градиента, я бы предложил следующую оптимизацию: вместо того, чтобы делать RGB- > HSB- > RGB для каждого отдельного цвета, вы должны только рассчитать целевой цвет. Как только вы узнаете целевой RGB, вы можете просто вычислить промежуточные значения в пространстве RGB без необходимости конвертировать туда и обратно. Независимо от того, вычисляете ли вы линейный переход использования, какая-то кривая зависит от вас.
Ответ 12
Способ 1: Преобразование RGB в HSL, настройка HSL, преобразование обратно в RGB.
Способ 2: Lerp значения цвета RGB - http://en.wikipedia.org/wiki/Lerp_(computing)
См. мой ответ на этот похожий вопрос для реализации С# метода 2.
Ответ 13
Притворись, что альфа смешана с белым:
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)
Ответ 14
Я не нашел этот вопрос до тех пор, пока он не стал связанным с моим вопросом вопросом.
Однако, используя понимание этих замечательных ответов. Для этого я собрал приятную двухстрочную функцию:
Программно осветить или затемнить шестицветный (или цвета rgb и blend)
Его версия метода 1. Но с учетом насыщения. Как сказал Кейт в своем ответе выше; используйте Лерпа, чтобы, похоже, решить ту же проблему, о которой упоминал Марк, но без перераспределения. Результаты shadeColor2
должны быть намного ближе к правильному пути с HSL, но без накладных расходов.
Ответ 15
Сначала я бы попробовал номер # 1, но # 2 звучит неплохо. Попытайтесь сделать это сами и посмотрите, удовлетворены ли вы результатами, похоже, вам понадобится 10 минут, чтобы опрокинуть тест.
Ответ 16
Технически я не думаю, что это правильно, но я считаю, что вам нужен вариант варианта № 2. Проблема в том, что принятый RGB 990000 и "облегчение" он действительно просто добавит на красный канал (Value, Brightness, Lightness), пока вы не попадете в FF. После этого (сплошной красный), он будет снимать насыщенность до полного беления.
Преобразования становятся раздражающими, тем более, что вы не можете напрямую обращаться к RGB и Lab, но я думаю, что вы действительно хотите отделить значения цветности и яркости и просто изменить яркость, чтобы действительно достичь того, чего вы хотите.
Ответ 17
Вы найдете код для преобразования между цветовыми пространствами в рубиновой библиотеке цветных инструментов
Ответ 18
У меня есть сообщение в блоге, в котором показано, как это сделать в Delphi. Его довольно просто, потому что функции ColorRGBToHSL и ColorHLSToRGB являются частью стандартной библиотеки.
Ответ 19
Вот пример освещения RGB-цвета в 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))
Ответ 20
Немного поздно для вечеринки, но если вы используете javascript
или nodejs
, вы можете использовать библиотеку tinycolor и управлять цветом так, как вы хотите:
tinycolor("red").lighten().desaturate().toHexString() // "#f53d3d"