2

Если у вас есть экземпляр System.Drawing.Bitmap, содержащий изображение в оттенках серого, есть ли встроенный способ «окрашивать» его с помощью другого цвета?«Colourizing» растровое изображение в .NET.

Например, если у вас была черно-белая (серая) картина кружки для кофе, и вы хотели программным образом создать отдельные изображения красных, зеленых и фиолетовых версий.

ответ

5

У меня нет примера кода, но это способ сделать это. Преобразуйте каждый пиксель из RGB в HSV и измените компонент Hue и Saturation на каждый пиксель. Цветовой оттенок управляет цветом. Значение должно оставаться неизменным. Результатом будет битмап с той же легкостью и темнотой, но с другим цветом.

Редактировать: вот пример. Обратите внимание на обновление оттенка и насыщенности.

 public static Color ColorFromAhsb(int a, float h, float s, float b) 
    { 

     if (0 > a || 255 < a) 
     { 
      throw new Exception("a"); 
     } 
     if (0f > h || 360f < h) 
     { 
      throw new Exception("h"); 
     } 
     if (0f > s || 1f < s) 
     { 
      throw new Exception("s"); 
     } 
     if (0f > b || 1f < b) 
     { 
      throw new Exception("b"); 
     } 

     if (0 == s) 
     { 
      return Color.FromArgb(a, Convert.ToInt32(b * 255), 
       Convert.ToInt32(b * 255), Convert.ToInt32(b * 255)); 
     } 

     float fMax, fMid, fMin; 
     int iSextant, iMax, iMid, iMin; 

     if (0.5 < b) 
     { 
      fMax = b - (b * s) + s; 
      fMin = b + (b * s) - s; 
     } 
     else 
     { 
      fMax = b + (b * s); 
      fMin = b - (b * s); 
     } 

     iSextant = (int)Math.Floor(h/60f); 
     if (300f <= h) 
     { 
      h -= 360f; 
     } 
     h /= 60f; 
     h -= 2f * (float)Math.Floor(((iSextant + 1f) % 6f)/2f); 
     if (0 == iSextant % 2) 
     { 
      fMid = h * (fMax - fMin) + fMin; 
     } 
     else 
     { 
      fMid = fMin - h * (fMax - fMin); 
     } 

     iMax = Convert.ToInt32(fMax * 255); 
     iMid = Convert.ToInt32(fMid * 255); 
     iMin = Convert.ToInt32(fMin * 255); 

     switch (iSextant) 
     { 
      case 1: 
       return Color.FromArgb(a, iMid, iMax, iMin); 
      case 2: 
       return Color.FromArgb(a, iMin, iMax, iMid); 
      case 3: 
       return Color.FromArgb(a, iMin, iMid, iMax); 
      case 4: 
       return Color.FromArgb(a, iMid, iMin, iMax); 
      case 5: 
       return Color.FromArgb(a, iMax, iMin, iMid); 
      default: 
       return Color.FromArgb(a, iMax, iMid, iMin); 
     } 

    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     var bmp = new Bitmap("c:\\bw.bmp"); 

     foreach (int y in Enumerable.Range(0, bmp.Height)) 
     { 
      foreach (int x in Enumerable.Range(0,bmp.Width)) 
      { 
       var p = bmp.GetPixel(x, y); 
       var h = p.GetHue(); 

       var c = ColorFromAhsb(p.A, p.GetHue() + 200, p.GetSaturation() + 0.5f, p.GetBrightness()); 
       bmp.SetPixel(x, y, c);      
      } 
     } 
     pictureBox1.Image = bmp; 
     //bmp.Dispose(); 

    } 
+0

Спасибо. Это немного улучшилось. Каково значение «p.GetSaturation() + 0.5f»? Кажется, что 0,5 кажется бесполезным, если «цветной» цвет сам по себе является оттенком серого (выход красноватый), но в противном случае требуется. – xyz

+0

@frou - В растровом изображении, которое я использовал Saturation, было 0. Если насыщенность равна нулю, изменение оттенка не изменяет цвет. Я просто добавил произвольное значение 0.5 к нулевому значению. Насыщение должно быть любым значением больше нуля и меньше или равно 1. – Steve

1

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

Update: смотри пример на http://www.codeproject.com/KB/cs/Merge_Images_in_C_.aspx

+0

Как вы это делаете? Вам нужно было бы указать «модулировать», а не аддитивный тип смешивания слоев, не так ли? – xyz

1

См here

Я использовал это в прошлом. Вы хотите посмотреть конкретно на ToSepia. Возможно, вам придется немного разобрать это, но это сработало для меня.

1

я неуверен встроенный в пути, но, если вы представляете каждый цвет, как поплавок, а не байт (255 становится 1 - полная интенсивность), умножая каждый канал с желаемым цветом должен дать эффект вы говорите.

(1,1,1) "white" * (1,0,0) "red" = (1,0,0) "red" 

(0.5,0.5, 0.5) "grey" * (0,1,0) "green" = (0,0.5,0) "dark green" 

Необходимо нанести это на пиксель.

+0

Спасибо. Подход «HSV» дает мне приятные результаты - я не совсем понимаю, почему :) – xyz

2

Если это 8-битное изображение, вы можете просто использовать другую палитру (Image.Palette). Это по существу таблица поиска, которая присваивает значение цвета каждому возможному значению байтового пикселя. Гораздо быстрее, чем изменение всех пикселей в цикле.

Смежные вопросы