2013-06-20 5 views
13

Java에서 이미지 작업 중입니다. 100 개가 넘는 이미지 (.png) 형식을 모두 설계했으며 모두 Trasparent 및 Black Color Drawing입니다.C# .NET에서 이미지의 픽셀 색상을 변경하는 방법

문제는 이제 드로잉 (Black -to)의 색을 변경하라는 요청을 받았습니다.

Google에서 이미지를 비트 맵 (픽셀)으로 변경하는 코드를 검색했지만 정확한 픽셀과 일치시키고 투명 모드 인 경우 특수하게 바꾸려면 어떻게해야하는지 짐작하지 않습니다. 다음은

 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

다음은 Pixels을 사용한 해결책입니다.

소스 코드를 첨부하면 정확한 결과를 얻고 결과를 얻을 수 있습니다.

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

그럼 모든 색상을 새로운 색상으로 바꿀 것입니다. (선택된 색상뿐만 아니라) 그라데이션이있는 경우 알파를 확인하면 최적의 결과를 얻을 수 있지만 OP를 만족하면 ... –

+1

잘이 코드는 단일 색상의 이미지. – DareDevil

15

우리의 당신의 코드를 확인 할 수 perfromance에 대해 이야기하기 전에 :

  1. 당신은 Color.Black 비교하지 않지만 당신이 originalColorColor.Black을 할당 :
    var originalColor = scrBitmap.GetPixel(i, j); 
    if (originalColor = Color.Black) 
        newBitmap.SetPixel(i, j, Color.Red); 
    

    가 여기에 두 가지 오류가 있습니다.
  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; 
} 

비교시 알파 채널을 고려해야합니다 (예 : 50 % 투명한 녹색, 예 : 30 % 투명한 녹색과 같은 색). 당신은 대체 픽셀은 원본 이미지의 원시 사본을 만들 수 있습니다 작은 것을 알고있는 경우 (컨텍스트를 만들 Graphics.FromImage를 사용하여 마지막으로

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

을하고 그것으로 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

내가 당신에게 다른 해결책을 줄 것이다.

간단하고 간단합니다. 변환 시간은 62ms입니다.

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

특정 색상에 대한 색상 매트릭스를 어떻게 만들 수 있습니까? 녹색, 파랑 등? –

관련 문제