C# 获取像素';使用C语言的单色图像的颜色#
正如主题所说,我有一个C# 获取像素';使用C语言的单色图像的颜色#,c#,image,image-processing,monochrome,C#,Image,Image Processing,Monochrome,正如主题所说,我有一个.bmp图像,我需要编写一个能够获得图像任何像素颜色的代码。这是一个1bpp(索引)图像,因此颜色将为黑色或白色。以下是我目前拥有的代码: //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
.bmp
图像,我需要编写一个能够获得图像任何像素颜色的代码。这是一个1bpp(索引)图像,因此颜色将为黑色或白色。以下是我目前拥有的代码:
//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]);
}
但我如何才能使它适用于1bpp图像?如果我只从指针读取一个字节,它总是有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;
}
首先,如果您需要在一次操作中读取单个像素,那么
GetPixel
在性能上是等效的。昂贵的操作是锁定位,也就是说,您应该保留BitmapData
,以便执行所有需要的读取操作,并且只在最后关闭它,但请记住关闭它
像素格式似乎有些混乱,但我们假设它是正确的1bpp。然后每个像素将占用一位,一个字节中将有8个像素的数据。因此,您的索引计算是不正确的。字节的位置将位于
x/8
,然后您需要获取位x%8
好的,明白了!您需要从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
即使像素为黑色,值是否为255?当您只需要一个像素操作时,锁定位没有意义。您只需使用bmp的GetPixel方法,而不锁定任何位或任何内容。如果您实际需要多个像素,则应锁定包含所有所需像素的整个区域,并使用Scan0的索引逻辑访问这些像素。但是,对于单个像素的get/set,您应该,使用GetPixel/SetPixel,因为单次使用速度更快。顺便说一下,锁定1x1矩形可能会有问题,因此您可以尝试锁定2x2,即使您只使用该矩形的第一个像素(如果这样做,请记住处理bmp的右下边缘)。您的图像是每像素1比特还是每像素1字节?因为你说的是24bpp,然后是1bpp,但似乎1bpp实际上意味着8bpp,或者不是?谢谢你的回答!我已经提到,图像是1bpp索引的。这有关系吗?我只是被这个事实弄糊涂了,因为如果所有的位都表示像素的颜色,那么索引存储在哪里?或者我理解错了什么?索引只是意味着颜色值是颜色表的索引。但是由于1位只剩下2种可能,所以可以安全地假设这两种颜色是黑色和白色。实际上,托盘上可以有任意两种颜色,不一定是黑色/白色。它可以是蓝色/红色、绿色/黄色等。。。Bitmap.Pallete.Entries保存位图的Pallete颜色。工作正常!谢谢。让我问你,你是如何找到计算面具的方法的?