使用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成为原始的,但所有像素都不是黄色的黑色。
答案 0 :(得分: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;
}
当然这假设一个真正的黑色和一个基本的黄色可以和你一起..
如果您需要更多控制,则需要更多代码,例如
if (r1 + b1 + g1 < threshold)
对于黑色阴影,对于黄色可能:
r1 = myYellow_R;
g1 = myYellow_G;
b1 = myYellow_B;
BTW :您需要查看这些指数;我最后一次看到LockBits数组中的数据是颠倒:不是RGB
,(更不用说RBG
了)但是BGR
! (对于32bpp BGRA
!)
由于您使用的是旧方法,请确保您的像素格式正常;如果是32bpp
,您需要进行一些简单的修改。
答案 1 :(得分: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结构可能会非常慢。