Как определить более темный или более светлый вариант цвета данного цвета? - PullRequest
41 голосов
/ 19 сентября 2008

Учитывая исходный цвет любого оттенка системой или пользователем, я бы хотел простой алгоритм, который я мог бы использовать для разработки более светлых или более темных вариантов выбранного цвета. Аналогичен эффектам, используемым в Windows Live Messenger для стилизации пользовательского интерфейса.

Язык - C # с .net 3.5.

Ответ на комментарий: Цветовой формат (Альфа) RGB. Со значениями в байтах или числах с плавающей запятой.

Отмечая ответ: Для контекста моего использования (несколько простых эффектов пользовательского интерфейса) ответ, который я отмечаю как принятый, на самом деле является наиболее простым для этого контекста. Однако я также отдал голоса за более сложные и точные ответы. Любой, кто выполняет более сложные операции с цветом и найдет эту нить в будущем, обязательно должен это проверить. Спасибо ТАК. :)

Ответы [ 13 ]

46 голосов
/ 22 апреля 2010

В XNA есть Color.Lerp статический метод , который делает это как разницу между двумя цветами.

Lerp - это математическая операция между двумя числами с плавающей запятой, которая изменяет значение первого на коэффициент разности между ними.

Вот метод расширения, чтобы сделать это для float:

public static float Lerp( this float start, float end, float amount)
{
    float difference = end - start;
    float adjusted = difference * amount;
    return start + adjusted;
}

Итак, простая операция переноса между двумя цветами с использованием RGB будет:

public static Color Lerp(this Color colour, Color to, float amount)
{
    // start colours as lerp-able floats
    float sr = colour.R, sg = colour.G, sb = colour.B;

    // end colours as lerp-able floats
    float er = to.R, eg = to.G, eb = to.B;

    // lerp the colours to get the difference
    byte r = (byte) sr.Lerp(er, amount),
         g = (byte) sg.Lerp(eg, amount),
         b = (byte) sb.Lerp(eb, amount);

    // return the new colour
    return Color.FromArgb(r, g, b);
}

Примером применения этого будет что-то вроде:

// make red 50% lighter:
Color.Red.Lerp( Color.White, 0.5f );

// make red 75% darker:
Color.Red.Lerp( Color.Black, 0.75f );

// make white 10% bluer:
Color.White.Lerp( Color.Blue, 0.1f );
28 голосов
/ 19 сентября 2008

Просто умножьте значения RGB на величину, на которую вы хотите изменить уровень. Если один из цветов уже имеет максимальное значение, вы не сможете сделать его ярче (в любом случае, используя математику HSV).

Это дает точно такой же результат с гораздо меньшим количеством математических операций, чем переключение на HSV и затем изменение V. Это дает тот же результат, что и переключение на HSL, а затем изменение L, если вы не хотите начинать терять насыщенность.

20 голосов
/ 19 сентября 2008

HSV (Оттенок / Насыщенность / Значение), также называемый HSL (Оттенок / Насыщенность / Яркость), представляет собой просто другое представление цвета.

Использование этого представления облегчает настройку яркости. Так что конвертируйте из RGB в HSV, сделайте ярче «V», а затем вернитесь обратно в RGB.

Ниже приведен код C для преобразования

void RGBToHSV(unsigned char cr, unsigned char cg, unsigned char cb,double *ph,double *ps,double *pv)
{
double r,g,b;
double max, min, delta;

/* convert RGB to [0,1] */

r = (double)cr/255.0f;
g = (double)cg/255.0f;
b = (double)cb/255.0f;

max = MAXx(r,(MAXx(g,b)));
min = MINx(r,(MINx(g,b)));

pv[0] = max;

/* Calculate saturation */

if (max != 0.0)
    ps[0] = (max-min)/max;
else
    ps[0] = 0.0; 

if (ps[0] == 0.0)
{
    ph[0] = 0.0f;   //UNDEFINED;
    return;
}
/* chromatic case: Saturation is not 0, so determine hue */
delta = max-min;

if (r==max)
{
    ph[0] = (g-b)/delta;
}
else if (g==max)
{
    ph[0] = 2.0 + (b-r)/delta;
}
else if (b==max)
{
    ph[0] = 4.0 + (r-g)/delta;
}
ph[0] = ph[0] * 60.0;
if (ph[0] < 0.0)
    ph[0] += 360.0;
}

void HSVToRGB(double h,double s,double v,unsigned char *pr,unsigned char *pg,unsigned char *pb)
{
int i;
double f, p, q, t;
double r,g,b;

if( s == 0 )
{
    // achromatic (grey)
    r = g = b = v;
}
else
{
    h /= 60;            // sector 0 to 5
    i = (int)floor( h );
    f = h - i;          // factorial part of h
    p = v * ( 1 - s );
    q = v * ( 1 - s * f );
    t = v * ( 1 - s * ( 1 - f ) );
    switch( i )
    {
    case 0:
        r = v;
        g = t;
        b = p;
    break;
    case 1:
        r = q;
        g = v;
        b = p;
    break;
    case 2:
        r = p;
        g = v;
        b = t;
    break;
    case 3:
        r = p;
        g = q;
        b = v;
    break;
    case 4:
        r = t;
        g = p;
        b = v;
    break;
    default:        // case 5:
        r = v;
        g = p;
        b = q;
    break;
    }
}
r*=255;
g*=255;
b*=255;

pr[0]=(unsigned char)r;
pg[0]=(unsigned char)g;
pb[0]=(unsigned char)b;
}
14 голосов
/ 19 сентября 2008

Рич Ньюман обсуждает цвет HSL в отношении .NET System.Drawing.Color в своем блоге и даже предоставляет класс HSLColor , который сделает всю работу за вас. Преобразуйте ваш System.Drawing.Color в HSLColor, добавьте / вычтите значения из значения Luminosity и верните обратно в System.Drawing.Color для использования в вашем приложении.

10 голосов
/ 19 сентября 2008

Вы можете преобразовать свой цвет в цветовое пространство HSL, манипулировать им там и преобразовать обратно в выбранное цветовое пространство (скорее всего, это RGB)

Более светлые цвета имеют более высокое значение L, тем темнее - более низкое.

Вот соответствующие вещи и все уравнения:

http://en.wikipedia.org/wiki/HSL_color_space

Другой метод - просто интерполировать ваш цвет белым или черным. Это также немного обесцветит цвет, но его будет дешевле вычислить.

9 голосов
/ 18 октября 2008

Я использовал ControlPaint.Dark () и .Light () в System.Windows.Forms.

4 голосов
/ 19 сентября 2008

Я предполагаю, что вы используете RGB с байтовыми значениями (от 0 до 255), поскольку это очень распространено везде.

Для более яркого, усредните значения RGB с RGB белого цвета. Или, чтобы иметь некоторый контроль над тем, насколько ярче, смешайте их в некоторой пропорции. Пусть f изменяется от 0,0 до 1,0, затем:

Rnew = (1-f)*R + f*255
Gnew = (1-f)*G + f*255
Bnew = (1-f)*B + f*255

Для более темных используйте RGB черного - что, будучи всеми нулями, облегчает математику.

Я опускаю детали, такие как преобразование результата обратно в байты, что, вероятно, вы захотите сделать.

3 голосов
/ 19 сентября 2008

Если вы используете цвета RGB, я бы преобразовал эти параметры цвета в HSL (оттенок, насыщенность, яркость), изменил параметр яркости и затем преобразовал бы обратно в RGB. Поищите в Google, и вы найдете множество примеров кода о том, как выполнять эти преобразования цветового представления (RGB в HSL и наоборот).

Вот что я быстро нашел: http://bytes.com/forum/thread250450.html

0 голосов
/ 02 декабря 2008

Этот сайт отмечает, что вы можете использовать класс ControlPaint в пространстве имен BCL C # System.Windows.Forms.

0 голосов
/ 19 сентября 2008

Идея преобразования в HSV или другое цветовое пространство кажется хорошей и может быть необходимой для точной цветопередачи, но для обычных целей ошибка работы в RGB может быть недостаточной. Кроме того, может быть трудно иметь дело с граничными случаями: RGB - это пространство в форме куба, а HSV - нет. Если вы работаете со значениями байтов, между пробелами могут отображаться многие-к-одному и один-ко-многим. Это может или не может быть проблемой в зависимости от приложения. YMMV

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...