Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Алгоритмы > Изменение яркотсти цвета


Автор: masterik 22.1.2008, 17:15
Доброго времени суток,


Очень срочно нужен алгоритм изменения яркости цвета в RGB пространстве... или на крайний случай в HSL/HSB пространстве.
Например имеется цвет RGB (255, 255, 128) - отсюда мне нужно получить два цвета: немного темнее и светлее имеюшегося...

Был бы рад увидеть не только формулу или кусок кода, но и парочку комментариев или ссылочку для прочтения...


Заранее очень благодарен за любую помощь

Автор: Earnest 24.1.2008, 13:24
Цитата(masterik @  22.1.2008,  18:15 Найти цитируемый пост)
отсюда мне нужно получить два цвета: немного темнее и светлее имеюшегося

Тогда тебе нужно не яркость менять, а интенсивность вроде. Пересчитываешь в HSL (или другое пространство, где оттенок в отдельную компоненту выделен), увеличиваешь или уменьшаешь компоненту, отвечающую зи интенсивность (или за светлоту), пересчитываешь обратно.
Для "немного светлее\темнее" у меня формул нет, есть именно для яркости\контрастности\интесивности (через YUV). Надо?
Вот еще здесь посмотри: http://www.easyrgb.com/math.php

Автор: _Y_ 25.1.2008, 16:55
Earnest, а мне тоже интересны формулы для яркости\контрастности\интесивности  smile 

Автор: dereyly 26.1.2008, 04:10
можно возвести в степень или умножить =)
вроде степень увеличивает яркость, а умножение осветляет
Ну если неравномерная освещенность то нужно гистограмму(ы) анализировать выделять пики и растягивать (как то так)


Автор: masterik 31.1.2008, 13:43
Цитата(Earnest @ 24.1.2008,  13:24)
Для "немного светлее\темнее" у меня формул нет, есть именно для яркости\контрастности\интесивности (через YUV). Надо?

Было бы интересно!

Нашел неплохие примеры конвертации между пространствами:
http://www.codeproject.com/KB/recipes/colorspace1.aspx
http://www.codeproject.com/KB/miscctrl/colorwheelv1.aspx


А нет формулы, чтобы прямо в RGB выполнить эту задачу, чтобы не терять время на переходы между пространствами?

Автор: Sardar 31.1.2008, 16:18
Если для человеческого глаза, то по идее (r, g, b) +- ([0.30, 0.59, 0.11] * (сколько нужно отнять/добавить)), отнимет именно от якрости, коэффициенты задают чувствительность человеческого глаза к исходной компоненте.

Автор: TeAnton 2.2.2008, 19:06
Если нужно быстро, и не нужен особо точный результат, можно просто каждый компонент RGB умножить на коэффициент. Коэффициент больше 1 осветляет, коэффициент меньше 1 затемняет. Дешево и сердито. Не забудь потом обработать переполнение через 255.

Автор: masterik 4.2.2008, 15:41
Цитата(Sardar @ 31.1.2008,  16:18)
Если для человеческого глаза, то по идее (r, g, b) +- ([0.30, 0.59, 0.11] * (сколько нужно отнять/добавить)), отнимет именно от якрости, коэффициенты задают чувствительность человеческого глаза к исходной компоненте.

Спасибо, вот что у меня вышло:
Код

private Color SomeFunc(Color cc, double delta)
{
     int R = (int)System.Math.Min(System.Math.Max((double)cc.R + 0.30 * delta, 0.0), 255.0);
     int G = (int)System.Math.Min(System.Math.Max((double)cc.G + 0.59 * delta, 0.0), 255.0);
     int B = (int)System.Math.Min(System.Math.Max((double)cc.B + 0.11 * delta, 0.0), 255.0);
     return Color.FromArgb(R, G, B);
}


Правильно ли я понял, то что вы предложили?
Я получаю немного странные результаты... в каком диапозоне должен лежать коэффициент?
RGB компоненты должны быть в диапозоне [0,1] или [0,255]?

Автор: Earnest 5.2.2008, 10:46
Цитата(_Y_ @  25.1.2008,  17:55 Найти цитируемый пост)
Earnest, а мне тоже интересны формулы для яркости\контрастности\интесивности 

Извините, давно не заглядывала. Вот формулы пересчета и коррекции яркости\контраста.
Все весьма несложно и работает вполне быстро.
Код

// Телевизионные пространства YUV, YIQ(NTSC)
// При построении модели пространства YIQ учитывалась особенность человеческого зрения:
// глаз человека в большей степени реагирует на яркостную составляющую и в меньшей степени
// на цветовые характеристики. При этом человеческий глаз по-разному воспринимает разные
// части спектра. На основании этого была предложена следующая схема пересчета из RGB в
// YIQ:
//      Y     0.299    0.587    0.114    R
//      I  =  0.596   -0.274   -0.322 *  G
//      Q     0.211   -0.522    0.311    B
// Обратный пересчет из YIQ в RGB осуществляется по формулам:
//      R     1    0.956    0.623    Y
//      G  =  1   -0.272   -0.648 *  I
//      B     1   -1.105    0.705    Q
// YUV:
//      Y = 0.299R + 0.587G + 0.114B;
//      U = (B - Y)/2.03;
//      V = (R – Y)/1.44.
// Обратный пересчет из YUV в RGB осуществляется по формулам:
//      R = Y + 1,44V;
//      G = Y – 0,37 – 0,73V;
//      B = Y + 2,03U.

    // изменения яркости, контраста, интенсивности
    struct CDelta
    {
        CDelta (int B = 0, int C = 0, int I = 0):
            m_B (B), m_C (C), m_I (I) {}
        int m_B, m_C, m_I;
    };


    struct CYuv
    {
        CYuv (CRgb rgb);
        operator CRgb() const;
        void Correct (const CDelta&);

        int m_Y, m_U, m_V;    
    };

    // используются те же самые формулы (только коэффициенты приведены к целому виду)
    inline CYuv::CYuv (CRgb clr)
    {
        // Y = 0.299R + 0.587G + 0.114B;
        m_Y = (30*clr.m_r + 59*clr.m_g + 11*clr.m_b)/100;
        // U = (B - Y)/2.03;
        m_U = (clr.m_b - m_Y) >> 1;
        // V = (R – Y)/1.44.
        m_V = (clr.m_r - m_Y)*25/36;
    }

    inline BYTE _Byte (int c)
    {
        return c < 0 ? 0 : c > 255 ? 255 : BYTE(c);
    }

    inline CYuv::operator CRgb () const
    {
        // R = Y + 1,44V;
        int R = (36*m_V/25 + m_Y);
        // B = Y + 2,03U.
        int B = (m_U << 1) + m_Y;
        // G = Y – 0,37 – 0,73V; ???
        int G = (100*m_Y - 11*B - 30*R)/59;

        return CRgb (_Byte(R), _Byte(G), _Byte(B));
    }
    
    inline void CYuv::Correct (const CDelta& delta)
    {
        static const int BaseY = 127;
        
      // BRIGHTNESS 
       m_Y += delta.m_B;
      
      // CONTRAST
      m_Y = (m_Y - BaseY) * delta.m_C/100 + BaseY;
      m_U = m_U * delta.m_C/100;
      m_V = m_V * delta.m_C/100;
      
      // INTENSITY
      m_U = m_U * delta.m_I/100;
      m_V = m_V * delta.m_I/100;
    }



Автор: masterik 5.2.2008, 12:41
Sardar, Earnest, 

Большое вам спасибо за помощь!
Объеденив два ваших решения, которые очень схожи, получил нужный мне результат!

Так как пишу для PocketPC, где нет FPU, поэтому все вычисления с целыми числами!

Код

private Color _CorrectLightness(Color cc, int delta)
{
      int R = System.Math.Min(System.Math.Max(cc.R + delta * 30 / 100, 0), 255);
      int G = System.Math.Min(System.Math.Max(cc.G + delta * 59 / 100, 0), 255);
      int B = System.Math.Min(System.Math.Max(cc.B + delta * 11 / 100, 0), 255);
      return Color.FromArgb(R, G, B);
}

private void CalculateColors(Color orig_color)
{
     // Методом тыка получил то что мне нужно :)
     // Все же если цвет слишком светлый или темный
     // получаюься странные результаты...
     Color shadow = _CorrectLightness(orig_color, -80);
     Color dark = _CorrectLightness(orig_color, -40);
     Color normal = orig_color;
     Color light = _CorrectLightness(orig_color, 40);
     Color highlight = _CorrectLightness(orig_color, 80);

     // ......
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)