2014-09-22 79 views
2

使用GetPixel和SetPixel很容易,但速度很慢,所以我试图使用LockBits。如何使用LockBits为黄色的位图中的黑色像素以黄色着色?

我有这样的方法我也很久以前就两幅图像之间的比较:

public static Bitmap FastComparison(Bitmap bmp1,Bitmap bmp2) 
    { 
     tolerancenumeric = 15; 
     int tolerance = tolerancenumeric * tolerancenumeric + 
         tolerancenumeric * tolerancenumeric + 
         tolerancenumeric * tolerancenumeric; //dr * dr + dg * dg + db * db; 
     bmp3 = new Bitmap(512,512); 
     PixelFormat pxf = PixelFormat.Format24bppRgb; 
     Rectangle rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height); 
     BitmapData bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadWrite, pxf); 
     BitmapData bmpData2 = bmp2.LockBits(rect, ImageLockMode.ReadWrite, pxf); 
     BitmapData bmpData3 = bmp3.LockBits(rect, ImageLockMode.ReadWrite, pxf); 

     IntPtr ptr1 = bmpData1.Scan0; 
     IntPtr ptr2 = bmpData2.Scan0; 
     IntPtr ptr3 = bmpData3.Scan0; 

     int numBytes = bmpData1.Stride * bmp1.Height; 
     byte[] rgbValues1 = new byte[numBytes]; 
     Marshal.Copy(ptr1, rgbValues1, 0, numBytes); 
     bmp1.UnlockBits(bmpData1); 

     byte[] rgbValues2 = new byte[numBytes]; 
     Marshal.Copy(ptr2, rgbValues2, 0, numBytes); 
     bmp2.UnlockBits(bmpData2); 


     for (int counter = 0; counter < rgbValues1.Length; counter += 3) 
     { 
      int dr, dg, db; 
      dr = (int)rgbValues2[counter] - (int)rgbValues1[counter]; 
      dg = (int)rgbValues2[counter + 1] - (int)rgbValues1[counter + 1]; 
      db = (int)rgbValues2[counter + 2] - (int)rgbValues1[counter + 2]; 
      int error = dr * dr + dg * dg + db * db; 

      int y, x; 
      y = (counter/3)/512; 
      x = (counter - y * 512 * 3)/3; 
      if ((x == 479) && (y == 474)) 
      { 
      Byte r1, g1, b1, r2, g2, b2; 
      r1 = rgbValues1[counter]; 
      b1 = rgbValues1[counter+1]; 
      g1 = rgbValues1[counter+2]; 
      r2 = rgbValues2[counter]; 
      b2 = rgbValues2[counter+1]; 
      g2 = rgbValues2[counter+2]; 
      } 

      if (error < tolerance) 
      { 
      rgbValues1[counter] = 0; 
      rgbValues1[counter + 1] = 0; 
      rgbValues1[counter + 2] = 0; 
      } 
     } 
     Marshal.Copy(rgbValues1, 0, ptr3, numBytes); 
     bmp3.UnlockBits(bmpData3); 
     return bmp3; 
     } 

但现在我还需要使用LockBits但有一个图像和颜色不黑黄色的所有像素。

我开始新的方法:

public Bitmap ChangeColors(Bitmap bmp1) 
     { 
      bmpColors = new Bitmap(512, 512); 
      PixelFormat pxf = PixelFormat.Format24bppRgb; 
      Rectangle rect = new Rectangle(0, 0, bmp1.Width, bmp1.Height); 
      BitmapData bmpData1 = bmp1.LockBits(rect, ImageLockMode.ReadWrite, pxf); 

      IntPtr ptr1 = bmpData1.Scan0; 

      int numBytes = bmpData1.Stride * bmp1.Height; 
      byte[] rgbValues1 = new byte[numBytes]; 
      Marshal.Copy(ptr1, rgbValues1, 0, numBytes); 
      bmp1.UnlockBits(bmpData1); 

      for (int counter = 0; counter < rgbValues1.Length; counter += 3) 
      { 
       int y, x; 
       y = (counter/3)/512; 
       x = (counter - y * 512 * 3)/3; 

       Byte r1, g1, b1; 
       r1 = rgbValues1[counter]; 
       b1 = rgbValues1[counter + 1]; 
       g1 = rgbValues1[counter + 2]; 
      } 

      return bmpColors; 
     } 

,但不知道如何使它这样的位图bmpColors将原来的一个,但与不是黑黄色的所有像素。

+1

我很困惑。您的标题讨论了GetPixel的性能(非常糟糕),但您似乎没有在代码中使用GetPixel。 – 2014-09-22 14:34:31

+0

更改了标题。我想要的是知道如何使用LockBits来做到这一点。为所有没有黄色的黑色像素着色。如果像素为黑色,则将其保留为黑色,否则以黄色将其着色 – 2014-09-22 14:38:09

+0

听起来像是彩色矩阵的工作。 http://msdn.microsoft.com/en-us/library/6tf7sa87(v=vs.110).aspx – asawyer 2014-09-22 14:39:23

回答

3

如何简单地测试字节并相应地设置它们?

Byte r1, g1, b1; 
r1 = rgbValues1[counter];   // should be + 2 !! 
b1 = rgbValues1[counter + 1];  // should be + 0 !! 
g1 = rgbValues1[counter + 2];  // should be + 1 !! 

if (r1 + b1 + g1 == 0) 
{ 
    r1 = 255; 
    g1 = 255; 
} 

当然这是假设一个真正的黑色和黄色的基本都OK与你..

如果您需要更多的控制,你需要一点更像

if (r1 + b1 + g1 < threshold) 

的阴影码黑色的,并为黄色可能:

r1 = myYellow_R; 
    g1 = myYellow_G; 
    b1 = myYellow_B; 

BTW:你需要检查这些指标;我最后一次查看LockBits数组中的数据是反转:不是RGB,(更不用说RBG,因为你有它),但BGR! (对于32bpp BGRA!)

由于您使用的是旧方法,因此请确保您的像素格式正常;如果是32bpp,则需要进行一些简单的修改。

0

下应与联合国索引8种字节的颜色,格式工作,这是你使用的是什么:

public static class BitmapHelper 
{ 
    //http://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/Advanced/PixelFormat.cs 
    //http://msdn.microsoft.com/en-us/magazine/cc534995.aspx#id0070035 
    private static void GetPixelFormatData(this PixelFormat pixelFormat, out byte bitsPerPixel, out byte bitsPerChannel, out bool hasAlpha, out bool premultiplyAlpha) 
    { 
     switch (pixelFormat) 
     { 
      //Specifies that the format is 24 bits per pixel; 8 bits each are used for the red, green, and blue components. 
      case PixelFormat.Format24bppRgb: 
       ///  Specifies that pixel format is 24 bits per pixel. The 
       ///  color information specifies 16777216 shades of color of which 8 bits are red, 8 
       ///  bits are green and 8 bits are blue. 
       bitsPerPixel = 24; 
       bitsPerChannel = 8; 
       hasAlpha = false; 
       premultiplyAlpha = false; 
       break; 

      //Specifies that the format is 32 bits per pixel; 8 bits each are used for the alpha, red, green, and blue components. 
      case PixelFormat.Format32bppArgb: 
       bitsPerPixel = 32; 
       bitsPerChannel = 8; 
       hasAlpha = true; 
       premultiplyAlpha = false; 
       break; 

      //Specifies that the format is 32 bits per pixel; 8 bits each are used for the alpha, red, green, and blue components. The red, green, and blue components are premultiplied, according to the alpha component. 
      case PixelFormat.Format32bppPArgb: 
       bitsPerPixel = 32; 
       bitsPerChannel = 8; 
       hasAlpha = true; 
       premultiplyAlpha = true; 
       break; 

      //Specifies that the format is 32 bits per pixel; 8 bits each are used for the red, green, and blue components. The remaining 8 bits are not used. 
      case PixelFormat.Format32bppRgb: 
       bitsPerPixel = 32; 
       bitsPerChannel = 8; 
       hasAlpha = false; 
       premultiplyAlpha = false; 
       break; 

      //Specifies that the format is 48 bits per pixel; 16 bits each are used for the red, green, and blue components. 
      case PixelFormat.Format48bppRgb: 
       bitsPerPixel = 48; 
       bitsPerChannel = 16; 
       hasAlpha = false; 
       premultiplyAlpha = false; 
       break; 

      //Specifies that the format is 64 bits per pixel; 16 bits each are used for the alpha, red, green, and blue components. 
      case PixelFormat.Format64bppArgb: 
       bitsPerPixel = 64; 
       bitsPerChannel = 16; 
       hasAlpha = true; 
       premultiplyAlpha = false; 
       break; 

      //Specifies that the format is 64 bits per pixel; 16 bits each are used for the alpha, red, green, and blue components. The red, green, and blue components are premultiplied according to the alpha component. 
      case PixelFormat.Format64bppPArgb: 
       bitsPerPixel = 64; 
       bitsPerChannel = 16; 
       hasAlpha = true; 
       premultiplyAlpha = true; 
       break; 

      default: 
       throw new ArgumentException("Unsupported Pixel Format " + pixelFormat.ToString()); 
     } 
    } 

    // Derived by experimentation. 
    const int BlueIndex = 0; 
    const int GreenIndex = 1; 
    const int RedIndex = 2; 
    const int AlphaIndex = 3; 

    public delegate bool TransformColorFunc(ref byte r, ref byte g, ref byte b, ref byte a); 

    public static void PaintSafe(Bitmap bmp, TransformColorFunc filter) 
    { 
     BitmapData bData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat); 
     try 
     { 
      byte bitsPerPixel; 
      byte bitsPerChannel; 
      bool hasAlpha; 
      bool premultiplyAlpha; 
      bmp.PixelFormat.GetPixelFormatData(out bitsPerPixel, out bitsPerChannel, out hasAlpha, out premultiplyAlpha); 
      if (bitsPerChannel != 8) 
       throw new ArgumentException(); 
      if ((bitsPerPixel % 8) != 0) 
       throw new ArgumentException(); 
      if ((!hasAlpha && bitsPerPixel < 24) || (hasAlpha && bitsPerPixel < 32)) 
       throw new ArgumentException(); 

      int size = bData.Stride * bData.Height; 
      byte[] data = new byte[size]; 

      System.Runtime.InteropServices.Marshal.Copy(bData.Scan0, data, 0, size); 
      for (int iPixel = 0; iPixel < size; iPixel += bitsPerPixel/8) 
      { 
       // Format is b, g, r, [a if present.] 
       byte b = data[iPixel + BlueIndex]; 
       byte g = data[iPixel + GreenIndex]; 
       byte r = data[iPixel + RedIndex]; 
       byte a; 
       if (hasAlpha) 
        a = data[iPixel + AlphaIndex]; 
       else 
        a = 255; 
       if (filter(ref r, ref g, ref b, ref a)) 
       { 
        // Format is b, g, r, [a if present.] 
        data[iPixel + BlueIndex] = b; 
        data[iPixel + GreenIndex] = g; 
        data[iPixel + RedIndex] = r; 
        if (hasAlpha) 
         data[iPixel + AlphaIndex] = a; 
       } 
      } 
      System.Runtime.InteropServices.Marshal.Copy(data, 0, bData.Scan0, data.Length); 
     } 
     finally 
     { 
      bmp.UnlockBits(bData); 
     } 
    } 
} 

然后调用它像:

static bool TransformNonBlackToYellow(ref byte r, ref byte g, ref byte b, ref byte a) 
    { 
     if (r != 0 || g != 0 || b != 0) 
     { 
      r = 255; 
      g = 255; 
      b = 0; 
      a = 255; 
      return true; 
     } 
     return false; 
    } 

    BitmapHelper.PaintSafe(bitmap, TransformNonBlackToYellow); 

注意,我没有我的过滤器函数采用Color,因为从Argb值构造Color结构可能会很奇怪。

+0

@James Aharon - 简化了我的答案。 – dbc 2014-09-22 17:21:51

相关问题