Программно осветлить цвет
мотивация
Я хотел бы найти способ взять произвольный цвет и осветлить его на несколько оттенков, чтобы я мог программно создать хороший градиент от одного цвета до более светлой версии. Градиент будет использоваться в качестве фона в пользовательском интерфейсе.
возможность 1
очевидно, что я могу просто разделить значения RGB и увеличить их по отдельности на определенную сумму. Это на самом деле то, что я хочешь?
вариант 2
моя вторая мысль состояла в том, чтобы преобразовать RGB в HSV/HSB/HSL (оттенок, насыщенность, значение/яркость/легкость), немного увеличить яркость, немного уменьшить насыщенность, а затем преобразовать ее обратно в RGB. Будет ли это иметь желаемый эффект в целом?
20 ответов:
Я бы пошел на второй вариант. Вообще говоря, пространство RGB не очень хорошо подходит для выполнения цветовых манипуляций (создание перехода от одного цвета к другому, осветление / затемнение цвета и т. д.). Ниже приведены два сайта, которые я нашел с помощью быстрого поиска для преобразования из / в RGB в / из HSL:
- из раздела "Основы компьютерной графики"
- какой-то исходный код на C# - должно быть легко адаптироваться к другим программам языки.
как Клин сказал, вы хотите умножить, чтобы сделать вещи ярче, но это работает только до тех пор, пока один из цветов не станет насыщенным (т. е. попадает 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's
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) ); }я использовал это повсюду.
класс ControlPaint в системе.Окна.Пространство имен форм имеет статические методы Light и Dark:
public static Color Dark(Color baseColor, float percOfDarkDark);эти методы используют частную реализацию HLSColor. Я хочу, чтобы эта структура была публичной и в системе.Рисунок.
кроме того, вы можете использовать GetHue, GetSaturation, GetBrightness на Color struct для получения компонентов HSB. К сожалению, я не нашел обратного преобразования.
преобразуйте его в 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; }
чтобы получить более светлую или более темную версию данного цвета, вы должны изменить его яркость. Вы можете сделать это легко даже без преобразования вашего цвета в цвет 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, если вам нужна точность.
я использовал ответ Эндрю и ответ Марка, чтобы сделать этой (по состоянию на 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) } }
преобразование в HS (LVB), увеличение яркости и затем преобразование обратно в RGB-это единственный способ надежно осветлить цвет, не влияя на значения оттенка и насыщенности (т. е. только осветлить цвет, не изменяя его каким-либо другим способом).
Я сделал это в обоих направлениях - вы получите гораздо лучшие результаты с возможностью 2.
любой простой алгоритм, который вы строите для возможности 1, вероятно, будет хорошо работать только для ограниченного диапазона начальных насыщений.
вы хотели бы посмотреть в Poss 1, если (1) Вы можете ограничить используемые цвета и яркости, и (2) вы выполняете расчет много в рендеринге.
генерация фона для пользовательского интерфейса не потребуется очень много затенения расчеты, поэтому я предлагаю Poss 2.
- Al.
Если вы хотите создать градиентное затухание, я бы предложил следующую оптимизацию: вместо того, чтобы делать RGB->HSB->RGB для каждого отдельного цвета, вы должны рассчитать только целевой цвет. После того, как вы знаете целевой RGB, вы можете просто рассчитать промежуточные значения в пространстве RGB без необходимости конвертировать туда и обратно. Если вы вычисляете линейный переход использования какой-то кривой зависит от вас.
метод 1: преобразование RGB в HSL, настройка HSL, преобразование обратно в RGB.
Способ 2: Lerp значения цвета RGB -http://en.wikipedia.org/wiki/Lerp_ (вычислительная техника)
посмотреть мой ответ на этот же вопрос для реализации метода 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, с нулевым возвратом(r, g, b)и 1 возврат(dest.r, dest.g, dest.b)
Я не нашел этот вопрос, пока он не стал связанным вопросом с моим первоначальным вопросом.
однако, используя понимание из этих великих ответов. Я собрал вместе хорошую функцию с двумя вкладышами для этого:
программно осветлить или затемнить шестнадцатеричный цвет (или rgb, и смешать цвета)
его версия метода 1. Но с учетом избыточной насыщенности. Как сказал Кит в своем ответе выше; используйте Lerp, чтобы прилично решить то же самое проблема Марк упомянул, но без перераспределения. Результаты
shadeColor2должно быть гораздо ближе к тому, чтобы сделать это правильно с HSL, но без накладных расходов.
Я бы попробовал номер #1 сначала, но #2 звучит довольно хорошо. Попробуйте сделать это самостоятельно и посмотреть, если вы удовлетворены результатами, это звучит так, как будто это займет у вас, возможно, 10 минут, чтобы на скорую руку тест.
технически, я не думаю, что это правильно, но я считаю, что вы хотите вариант варианта № 2. Проблема в том, что взятый RGB 990000 и "осветление" он действительно просто добавит на красный канал (значение, яркость, легкость), пока вы не доберетесь до FF. После этого (сплошной красный), он будет снимать насыщенность чтобы пройти весь путь до сплошного белого.
преобразования раздражают, тем более, что вы не можете идти прямо в и из RGB и Lab, но я думаю, что вы действительно хотите разделить значения цветности и яркости и просто изменить яркость, чтобы действительно достичь того, что вы хотите.
вы найдете код для преобразования между цветовыми пространствами в color-tools ruby library
У меня есть блоге это показывает, как это сделать в Delphi. Его довольно просто, потому что функции ColorRGBToHSL и ColorHLSToRGB являются частью стандартной библиотеки.
вот пример осветления цвета 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))
немного опоздал на вечеринку, но если вы используете
javascriptилиnodejs, вы можете использовать библиотека tinycolor, и манипулировать цветом так, как вы хотите:tinycolor("red").lighten().desaturate().toHexString() // "#f53d3d"



Comments