如何使用LockBits将黄色位图中的非黑色像素着色?

使用GetPixel和SetPixel很容易但很慢,所以我正在尝试使用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将是原始的,但所有像素都不是黄色的黑色。

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

 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; } 

当然,这假设一个真正的黑色和一个基本的黄色与你好。

如果你需要更多的控制,你需要更多的代码

 if (r1 + b1 + g1 < threshold) 

对于黑色阴影,对于黄色可能:

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

顺便说一句 :你需要查看这些指数; 我最后一次看到LockBits数组中的数据是相反的 :不是RGB ,(更不用说RBG了)但是BGR ! (对于32bpp BGRA !)

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

以下应适用于具有未索引的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); 

注意我没有我的filter函数采用Color,因为从Argb值构造Color结构可能非常慢。