2013-06-20 107 views
13

我正在使用Java中的圖像,我設計了超過100多種圖像(.png)格式,它們都是透明和黑色繪圖。如何在C#.NET中更改圖像的像素顏色

問題是,現在我被要求改變繪圖的顏色(黑色到)。

我搜索了許多谷歌代碼,改變了圖像的位圖(像素),但我不知道我必須做什麼才能匹配確切的像素,並在透明模式下特別替換圖像。 下面是.NET中

 Bitmap newBitmap = new Bitmap(scrBitmap.Width, scrBitmap.Height); 
     for (int i = 0; i < scrBitmap.Width; i++) 
     { 
      for (int j = 0; j < scrBitmap.Height; j++) 
      {      
       originalColor = scrBitmap.GetPixel(i, j); 
       if(originalColor = Color.Black) 
        newBitmap.SetPixel(i, j, Color.Red); 
      } 
     }    
     return newBitmap; 

但它不匹配,在所有的代碼(C#),我調試它,整個文件中,沒有出現紅色,綠色,顏色的藍參數(originalColor)的值變量。

有人可以幫忙嗎?

回答

24

這是我用像素完成的解決方案。

附加源代碼,以便可以嘗試確切並獲得結果。

我有128x128(寬x高)的示例圖像。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Drawing; 
using System.IO; 
//using System.Globalization; 

namespace colorchange 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       Bitmap bmp = null; 
       //The Source Directory in debug\bin\Big\ 
       string[] files = Directory.GetFiles("Big\\"); 
       foreach (string filename in files) 
       { 
       bmp = (Bitmap)Image.FromFile(filename);      
       bmp = ChangeColor(bmp); 
       string[] spliter = filename.Split('\\'); 
       //Destination Directory debug\bin\BigGreen\ 
       bmp.Save("BigGreen\\" + spliter[1]); 
       }             
      } 
      catch (System.Exception ex) 
      { 
       Console.WriteLine(ex.ToString()); 
      }    
     }   
     public static Bitmap ChangeColor(Bitmap scrBitmap) 
     { 
      //You can change your new color here. Red,Green,LawnGreen any.. 
      Color newColor = Color.Red; 
      Color actualColor;    
      //make an empty bitmap the same size as scrBitmap 
      Bitmap newBitmap = new Bitmap(scrBitmap.Width, scrBitmap.Height); 
      for (int i = 0; i < scrBitmap.Width; i++) 
      { 
      for (int j = 0; j < scrBitmap.Height; j++) 
      { 
       //get the pixel from the scrBitmap image 
       actualColor = scrBitmap.GetPixel(i, j); 
       // > 150 because.. Images edges can be of low pixel colr. if we set all pixel color to new then there will be no smoothness left. 
       if (actualColor.A > 150) 
        newBitmap.SetPixel(i, j, newColor); 
       else 
        newBitmap.SetPixel(i, j, actualColor); 
      } 
      }    
      return newBitmap; 
     } 
    } 
} 

//下面是樣本圖像和不同的結果通過將不同顏色 enter image description here

代碼的修改,將不勝感激。

+1

這是最好的答覆,我相信我的要求滿足,感謝DareDevil –

+3

那麼這將取代每個顏色到新的(不只是一個選定的),並檢查alpha將產生次優結果,如果有梯度,但如果它滿足OP ... :) –

+1

以及此代碼適用於單一顏色的圖像。 – DareDevil

15

才談得perfromance讓我們來檢查你的代碼:

var originalColor = scrBitmap.GetPixel(i, j); 
if (originalColor = Color.Black) 
    newBitmap.SetPixel(i, j, Color.Red); 

在這裏有兩個誤區:

  1. 你不比較Color.Black但你分配Color.BlackoriginalColor
  2. 您不處理透明度。

要檢查的透明度,你應該比較不Color對象,但R,G,B值,讓我們更改爲:

var originalColor = scrBitmap.GetPixel(i, j); 
if (originalColor.R == 0 && originalColor.G == 0 && originalColor.B == 0) 
    newBitmap.SetPixel(i, j, Color.FromArgb(originalColor.A, Color.Red)); 

現在你會看到它的工作原理,但它需要一個很長時間處理每個圖像:GetPixelSetPixel是相當緩慢(主要是因爲他們檢查並計算每個電話的一切)。直接處理位圖數據要好得多。如果你事先知道圖像格式(和它的固定每幅圖像),那麼你可以用多一點的代碼做要快得多:

static unsafe Bitmap ReplaceColor(Bitmap source, 
            Color toReplace, 
            Color replacement) 
{ 
    const int pixelSize = 4; // 32 bits per pixel 

    Bitmap target = new Bitmap(
    source.Width, 
    source.Height, 
    PixelFormat.Format32bppArgb); 

    BitmapData sourceData = null, targetData = null; 

    try 
    { 
    sourceData = source.LockBits(
     new Rectangle(0, 0, source.Width, source.Height), 
     ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 

    targetData = target.LockBits(
     new Rectangle(0, 0, target.Width, target.Height), 
     ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); 

    for (int y = 0; y < source.Height; ++y) 
    { 
     byte* sourceRow = (byte*)sourceData.Scan0 + (y * sourceData.Stride); 
     byte* targetRow = (byte*)targetData.Scan0 + (y * targetData.Stride); 

     for (int x = 0; x < source.Width; ++x) 
     { 
     byte b = sourceRow[x * pixelSize + 0]; 
     byte g = sourceRow[x * pixelSize + 1]; 
     byte r = sourceRow[x * pixelSize + 2]; 
     byte a = sourceRow[x * pixelSize + 3]; 

     if (toReplace.R == r && toReplace.G == g && toReplace.B == b) 
     { 
      r = replacement.R; 
      g = replacement.G; 
      b = replacement.B; 
     } 

     targetRow[x * pixelSize + 0] = b; 
     targetRow[x * pixelSize + 1] = g; 
     targetRow[x * pixelSize + 2] = r; 
     targetRow[x * pixelSize + 3] = a; 
     } 
    } 
    } 
    finally 
    { 
    if (sourceData != null) 
     source.UnlockBits(sourceData); 

    if (targetData != null) 
     target.UnlockBits(targetData); 
    } 

    return target; 
} 

當然,這可能是further optimized,你可能需要處理不同格式(有關其佈局的see this list of pixel formatsthis article),但認爲它是使用位圖的起點。

爲了完整起見,這是等效的顏色,不能直接訪問位圖數據。請注意,這應該很少使用,因爲它非常緩慢。

static Bitmap ReplaceColor(Bitmap source, 
          Color toReplace, 
          Color replacement) 
{ 
    var target = new Bitmap(source.Width, source.Height); 

    for (int x = 0; x < source.Width; ++x) 
    { 
     for (int y = 0; y < source.Height; ++y) 
     { 
      var color = source.GetPixel(x, y); 
      target.SetPixel(x, y, color == toReplace ? replacement : color); 
     } 
    } 

    return target; 
} 

另外請注意,這比較考慮alpha通道(例如50%透明綠色,與30%透明綠色不同)。要忽略阿爾法你可以使用這樣的事情:

if (color.R == toReplace.R && color.G == toReplace.G && color.B == toReplace.B) 

最後,如果你知道像素替換是一點,你就可以創建原始圖像的原始拷貝(使用Graphics.FromImage創建上下文,並吸引到它source位圖),這樣你只有在有替換時纔會撥打SetPixel()。 IMO在這裏的任何優化都是無用的:如果你需要性能使用第一個解決方案...

+0

着急,我做了所有和它刪除了== –

+1

@BibiTahira什麼刪除了? –

+0

當我與我的像素顏色與系統顏色 –

4

有效替換顏色的一種方法是使用重映射表。在以下示例中,圖像在圖片框內繪製。在Paint事件,顏色Color.Black改爲Color.Blue:

private void pictureBox_Paint(object sender, PaintEventArgs e) 
    { 
     Graphics g = e.Graphics; 
     using (Bitmap bmp = new Bitmap("myImage.png")) 
     { 

      // Set the image attribute's color mappings 
      ColorMap[] colorMap = new ColorMap[1]; 
      colorMap[0] = new ColorMap(); 
      colorMap[0].OldColor = Color.Black; 
      colorMap[0].NewColor = Color.Blue; 
      ImageAttributes attr = new ImageAttributes(); 
      attr.SetRemapTable(colorMap); 
      // Draw using the color map 
      Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); 
      g.DrawImage(bmp, rect, 0, 0, rect.Width, rect.Height, GraphicsUnit.Pixel, attr); 
     } 
    } 

的更多信息:http://msdn.microsoft.com/en-us/library/4b4dc1kz%28v=vs.110%29.aspx

1

我會給你一個解決方案,因爲這不會計算每個像素。

它簡短而簡單。轉換時間爲62毫秒:

public Bitmap Color(Bitmap original) 
     { 
      //create a blank bitmap the same size as original 
      Bitmap newBitmap = new Bitmap(original.Width, original.Height); 

      //get a graphics object from the new Image 
      Graphics g = Graphics.FromImage(newBitmap); 

      //create the color you want ColorMatrix 
      //now is set to red, but with different values 
      //you can get anything you want. 
      ColorMatrix colorMatrix = new ColorMatrix(
       new float[][] 
       { 

        new float[] {1f, .0f, .0f, 0, 0}, 
        new float[] {1f, .0f, .0f, 0, 0}, 
        new float[] {1f, .0f, .0f, 0, 0}, 
        new float[] {0, 0, 0, 1, 0}, 
        new float[] {0, 0, 0, 0, 1} 
       }); 

      //create some image attributes 
      ImageAttributes attributes = new ImageAttributes(); 

      //set the color matrix attribute 
      attributes.SetColorMatrix(colorMatrix); 

      //draw original image on the new image using the color matrix 
      g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height), 
       0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes); 

      //release sources used 
      g.Dispose(); 
      return newBitmap; 
     } 
+2

如何爲特定顏色創建顏色矩陣?如綠色,藍色等? –