Уверен, что каждому читателю блога приходилось много раз смешивать краски и что-то где-то рисовать. По крайней мере, все мы ходили на уроки рисования в школе. Смешивание различных цветов дает новые цвета, которые, в свою очередь можно снова смешивать и в пределе получить, скажем, чёрный цвет — когда все краски замешаны в одну непонятную массу. Но это все в, скажем так, реальном мире. А как дела обстоят с цветами в мире программ? Цель работы на сегодня — «научить» нашу программу смешивать краски в нужных пропорциях и получать тот цвет, который Вы бы получили, смешав настоящие краски, а не пиксели на мониторе.
Работая с цветами в Delphi (да и не только с Delphi), мы уже привыкли, что для работы с цветом у нас есть модель RGB (Red, Green, Blue) в который все цвета получаются путем смешивания трех основных. Самый простой алгоритм смешивания двух RGB-цветов в равных пропорциях — это:
var R,G,B:byte; begin R:=(R1+R2) div 2; G:=(G1+G2) div 2; B:=(B1+B2) div 2; end;
Просто, удобно, лаконично. А теперь вернемся к нашей задаче. Как показать художнику, с кисточкой в одной руке и палитрой в другой, какой цвет он получит, если возьмет и смешает в своей палитре две краски? Попробуйте сейчас, используя приведенный выше код сложить два цвета: синий (0, 0, 255) и желтый (255, 255, 0). Что получится? Получится некое подобие серого цвета. Что-то типа такого:
А теперь попробуйте сделать то же самое, НО по-старинке, без компьютера, без RGB и прочих технических штук — возьмите два карандаша/маркера и почиркайте ими на белом листе бумаги. Что получилось?
Должно получиться что-то типа такого:
Как так получилось? Магии никакой нет, приведенный выше код, если и дает ошибку в определении нового цвета, то явно не такую, чтобы вместо зеленого получился серый цвет. И тут мы вплотную приблизились к тому, чтобы рассмотреть теоретическую часть задачи. Скажу сразу — глубоко в физику процесса я лезть не буду (тем более, что глубоко я в теории цвета никогда не копался) — расскажу кратко и ровно столько, чтобы хватило для решения задачи.
Цветовые модели
Как я сказал выше, мы все привыкли и, если не прекрасно, то хотя бы в общих чертах, представляем, что представляет из себя RGB.
RGB — это аддитивная модель цветового пространства.
Аддитивное смешение цветов — метод синтеза цвета, основанный на сложении аддитивных цветов, то есть цветов непосредственно излучающих объектов.
Любой цвет на «излучающим объекте», например, мониторе получается путем сложения трех составляющих — красных, зеленых и синих точек. Сложили три основных цвета — получили черный, обнулили три составляющих цвета — получили чистый белый.
В RGB можно получить огромное количество всяких разных цветов, поэтому RGB нашла широкое применение в современной технике. Круг, изображенный на первой картинке этой статьи и есть своеобразное представление цветового пространства RGB.
Кроме RGB существует и другая цветовая модель —RYB:
RYB — цветовая модель субтрактивного синтеза, основанная на составлении цвета из красного (Red), жёлтого (Yellow) и голубого (Blue). Эта сложившаяся исторически система предшествовала становлению современной науки о цвете. Она не вписывается в современные представления о пиках восприятия спектра видимого света в трехстимульной модели зрения, однако применяется для представления цвета в изобразительном искусстве.
Субтрактивный синтез цвета — получение цвета путём вычитания из белого света отдельных спектральных составляющих.
Смотрим на модель RYB и видим:
Синий + Желтый = Зеленый
Обратите внимание, что любой цвет в RYB определяется тремя числами в диапазоне от 0 до 1.
- 1,0,0 — красный цвет
- 0,1,0 — желтый
- 0,0,1 — голубой
Вот та цветовая модель с которой нам сегодня предстоит научиться работать. Конечно, кроме этих двух, существует ещё ряд цветовых моделей, например, HSL, XYZ, L*a*b, CMYK (то же, кстати, субтрактивная модель, как и RYB) и т.д. Сейчас рассматривать мы их не будем, но, вполне возможно, что позже я покажу как эти модели можно использовать в Delphi. А пока обратимся к нашей модели RYB и прикинем как мы можем её использовать в Delphi.
Сложение цветов в RYB
Итак, теперь мы знаем, что из себя представляет модель RYB. Есть три основных цвета (Primary Colors) Red, Yellow и Blue. Согласно RYB эти цвета нельзя получить путем смешивания.
Смешивая в равных пропорциях два любых основных цвета мы получим так называемые secondary colors.
Смешивая 2 части primary color с 1 частью secondary color мы получим tertiary Colors.
В итоге primary, secondary и tertitary colors образуют так называемое цветовое колесо, которое можно представить, например, так:
Как смешиваются цвета в RYB? Очень просто. К примеру нам надо смешать две части красного цвета и одну часть желтого.
Запишем цвет в RYB как:
type TRYBColor = record R: single; Y: single; B: single; end; [...] var Color1, Color2: TRYBColor;
а количество (или вес) в общей массе как
weight1, weight2: single
Тогда чтобы смешать два цвета и получить результат нам достаточно выполнить вот такой код:
var NewRYB: TRYBColor; K: single; begin NewRYB.R:=Color1.R*Weight1+Color2.R*Weight2; NewRYB.Y:=Color1.Y*Weight1+Color2.Y*Weight2; NewRYB.B:=Color1.B*Weight1+Color2.B*Weight2; K:=MaxValue([NewRYB.R,NewRYB.Y,NewRYB.B]); NewRYB.R:=NewRYB.R/K; NewRYB.Y:=NewRYB.Y/K; NewRYB.B:=NewRYB.B/K; end;
Ну, или, если представить себе каждый цвет как вектор в трехмерном пространстве, то в Delphi процедуру сложения двух RYB-цветов можно сделать ещё короче:
var Color1, Color2, NewColor: TVector3D; begin NewColor:=Color1.Scale(Weight1)+Color2.Scale(Weight2); Vector3:=Vector3.Scale(1/MaxValue([NewColor.X,NewColor.Y,NewColor.Z])); end;
В результате получим какой-то новый цвет в RYB. Как его теперь показать пользователю? Естественно, тут мы выше головы не прыгнем и нам надо будет как-то конвертировать RYB в RGB. Поиски в сети на предмет конвертеров из RYB в RGB наткнулся вот на такой замечательный кубик:
Используя этот кубик, ребята вот с этого сайта собрали простенький калькулятор на JavaScript, который переводит любой цвет из RYB в RGB. Ну, а раз у нас есть скрипт, то не вижу смысла изобретать свой велосипед — просто переведем этот скрипт на рельсы Delphi:
function RYBToARGB(RYBColor: TRYBColor):TAlphaColor; function CubicInt(t,a,b: single): single; var Weight: single; begin Weight:=t*t*(3-2*t); Result:=A+Weight*(B-A); end; function GetRValue: integer; var x0, x1, x2, x3, y0, y1: single; begin x0:=CubicInt(RYBColor.B,1,0.163); x1:= cubicInt(RYBColor.B, 1.0, 0.0); x2:= cubicInt(RYBColor.B, 1.0, 0.5); x3:= cubicInt(RYBColor.B, 1.0, 0.2); y0:= cubicInt(RYBColor.Y, x0, x1); y1:= cubicInt(RYBColor.Y, x2, x3); Result:=ceil(255 * cubicInt(RYBColor.R, y0, y1)); end; function GetGValue:integer; var x0, x1, x2, x3, y0, y1: single; begin x0:=cubicInt(RYBColor.B, 1.0, 0.373); x1:=cubicInt(RYBColor.B, 1.0, 0.66); x2:=cubicInt(RYBColor.B, 0.0, 0.0); x3:=cubicInt(RYBColor.B, 0.5, 0.094); y0:=cubicInt(RYBColor.Y, x0, x1); y1:=cubicInt(RYBColor.Y, x2, x3); Result:=ceil(255 * cubicInt(RYBColor.R, y0, y1)); end; function GetBValue:integer; var x0, x1, x2, x3, y0, y1: single; begin x0:= cubicInt(RYBColor.B, 1.0, 0.6); x1:= cubicInt(RYBColor.B, 0.0, 0.2); x2:= cubicInt(RYBColor.B, 0.0, 0.5); x3:= cubicInt(RYBColor.B, 0.0, 0.0); y0:= cubicInt(RYBColor.Y, x0, x1); y1:= cubicInt(RYBColor.Y, x2, x3); result:=ceil(255*cubicInt(RYBColor.R, y0, y1)); end; begin Result:=MakeColor(GetRValue, GetGValue, GetBValue) end;
Имея в руках две функции — сложения RYB-цветов и конвертирования из RYB в ARGB мы можем проверить нашу работу и нарисовать собственное цветовое колесо RYB.
Приложение «Цветовое колесо RYB»
Чтобы продемонстрировать работу с RYB я написал небольшую программку, которая, используя приведенные выше методы, смешивает выбранные краски и показывает значения RGB и RYB полученной смеси. Ниже небольшой видео-ролик, демонстрирующий работу программы:
[youtube_sc url=»https://www.youtube.com/watch?v=w-Bc-lqYw7c»]Конечно, RYB обладает своими недостатками, но, тем не менее, эта цветовая модель нашла свое применение в изобразительном искусстве.
Пока разбирался с задачей смешения цветов перебрал практически все известные цветовые модели, поэтому, думаю, что тема работы с цветами в блоге WebDelphi ещё не закончена и, вполне возможно, что «Цветовое колесо RYB» немного разрастется.
На этом все. Всем удачи и до новых встреч на страницах блога WebDelphi.ru.
Что в данном случае значит Вес(количество цвета)?
а количество (или вес) в общей массе как
weight1, weight2: single
Чисто физическое понятие и не более. Есть 3 банки — с красной, желтой и синей краской. Берем и смешиваем 1 кг синей, 0,5 кг желтой и 0,1 кг красной краски. Что получим? Вот числа в предыдущем предложении и есть ВЕС цвета
Это получается weight это (R + Y + B)?
Спасибо огромное за ответ
Это получается weight это (R + Y + B)?
Владислав (Vlad), я очень туго программирую. Я просто восхищен этой программкой — просто, легко и удобно. Но очень хотелось бы разместить такую же программку, как на видео, у себя на сайте. Может на каком-то сайте это реализовано? Все что я нашел в сети, это модель усреднения. И при сложении синего с желтым получается серый. Это, конечно же не то. Хотел написать в личку, не найду Ваш e-mail.
Я программирую сейчас только в Delphi :)
e-mail: vlad383@mail.ru