正如主题所说,我有一张.bmp
图像,我需要写一个代码,它将能够获得图像中任何像素的颜色。这是一个1ppp(索引)图像,因此颜色将是黑色或白色。这是我目前拥有的代码:
//This method locks the bits of line of pixels
private BitmapData LockLine(Bitmap bmp, int y)
{
Rectangle lineRect = new Rectangle(0, y, bmp.Width, 1);
BitmapData line = bmp.LockBits(lineRect,
ImageLockMode.ReadWrite,
bmp.PixelFormat);
return line;
}
//This method takes the BitmapData of a line of pixels
//and returns the color of one which has the needed x coordinate
private Color GetPixelColor(BitmapData data, int x)
{
//I am not sure if this line is correct
IntPtr pPixel = data.Scan0 + x;
//The following code works for the 24bpp image:
byte[] rgbValues = new byte[3];
System.Runtime.InteropServices.Marshal.Copy(pPixel, rgbValues, 0, 3);
return Color.FromArgb(rgbValues[2], rgbValues[1], rgbValues[0]);
}
但是,我如何使它适用于1pp的图像?如果我只从指针中读取一个字节,它总是有255
值,所以我认为我做错了什么
请不要建议使用System.Drawing.Bitmap.GetPixel
方法,因为它工作速度太慢,我希望代码工作得尽可能快。提前谢谢。
编辑:以下是运行良好的代码,以防有人需要:
private Color GetPixelColor(BitmapData data, int x)
{
int byteIndex = x / 8;
int bitIndex = x % 8;
IntPtr pFirstPixel = data.Scan0+byteIndex;
byte[] color = new byte[1];
System.Runtime.InteropServices.Marshal.Copy(pFirstPixel, color, 0, 1);
BitArray bits = new BitArray(color);
return bits.Get(bitIndex) ? Color.Black : Color.White;
}
好的,明白了!您需要从BitmapData读取位,并将掩码应用于您想要提取颜色的位:
var bm = new Bitmap...
//lock all image bits
var bitmapData = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
// this will return the pixel index in the color pallete
// since is 1bpp it will return 0 or 1
int pixelColorIndex = GetIndexedPixel(50, 30, bitmapData);
// read the color from pallete
Color pixelColor = bm.Pallete.Entries[pixelColorIndex];
这是一种方法:
// x, y relative to the locked area
private int GetIndexedPixel(int x, int y, BitmapData bitmapData)
{
var index = y * bitmapData.Stride + (x >> 3);
var chunk = Marshal.ReadByte(bitmapData.Scan0, index);
var mask = (byte)(0x80 >> (x & 0x7));
return (chunk & mask) == mask ? 1 : 0;
}
像素位置分两轮计算:
1) 找到"x"中像素所在的字节(x/8):每个字节包含8个像素,找到字节除以x/8向下取整:58>>3=7,像素在当前行的字节7上(步长)
2) 查找当前字节上的位(x%8):执行x & 0x7
以仅获得最左边的3个位(x/8)
示例:
x = 58
// x / 8 - the pixel is on byte 7
byte = 58 >> 3 = 58 / 8 = 7
// x % 8 - byte 7, bit 2
bitPosition = 58 & 0x7 = 2
// the pixels are read from left to right, so we start with 0x80 and then shift right.
mask = 0x80 >> bitPosition = 1000 0000b >> 2 = 0010 0000b
首先,如果您需要在一次操作中读取单个像素,那么GetPixel
的性能将相当。代价高昂的操作是锁定位,即您应该抓住BitmapData
进行所需的所有读取,并且只在最后关闭它,但请记住关闭它!
您的像素格式似乎有些混乱,但让我们假设它是正确的1bpp。然后每个像素将占据一个比特,并且在一个字节中将有8个像素的数据。因此,您的索引计算是不正确的。字节的位置将在x/8
中,然后您需要取位x%8
。