2009-09-30 78 views
2

如果您有一個包含灰度圖像的System.Drawing.Bitmap實例,是否有內置的方法可以將其與另一種顏色的影響「相比較」?在「.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 2009-10-01 10:34:47

+0

@frou - 在我使用飽和度的位圖中爲0.如果飽和度爲零,修改色相不會改變顏色。我只是給零值添加了一個任意的0.5。飽和度應該大於零且小於或等於1的任何值。 – Steve 2009-10-01 13:43:29

1

我會創建一個原始圖像的副本,並把它們放在頂部所需顏色的單獨半透明圖像上。

更新:見例如在http://www.codeproject.com/KB/cs/Merge_Images_in_C_.aspx

+0

你是怎麼做到的?你將不得不指定一個「調製」而不是疊加類型的圖層混合,對吧? – xyz 2009-09-30 15:28:25

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 2009-10-01 09:43:16

2

如果是8位圖像,則可以使用不同的調色板(Image.Palette)。這本質上是一個查找表,它爲每個可能的像素字節值賦予一個Color值。比改變循環中的所有像素快得多。