我正在尝试学习用于图像处理的LockBitmap类,我遇到了下面发布的代码。基本上它返回x-y坐标的颜色。
当然,此方法仅在我执行source.LockBits()
和Marshal.Copy()
/ unsafe context
后才有效。
public Color GetPixel(int x, int y, Bitmap source)
{
int Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);
int Width = source.Width;
int Height = source.Height;
Color clr = Color.Empty;
// Get color components count
int cCount = Depth / 8;
int PixelCounts = Width * Height;
byte[] Pixels = new byte[cCount * PixelCounts];
// Get start index of the specified pixel
int i = ((y * Width) + x) * cCount;
byte b = Pixels[i];
byte g = Pixels[i + 1];
byte r = Pixels[i + 2];
byte a = Pixels[i + 3]; // a
clr = Color.FromArgb(a, r, g, b);
return clr;
}
cCount
,为什么总是Depth / 8
?int i = ((y * Width) + x) * cCount
,这是从(x,y)坐标转换为Pixels[i]
的固定公式吗?为什么?答案 0 :(得分:1)
首先,cCount
是一个像素的字节数(bytes per pixel
),Depth
是一个像素的位数(bits per pixel
)。除以8是为了将比特转换为字节。 (虽然Depth / 8
效率低下,但请改用(int)Math.Ceiling(Depth / 8d)
要回答第二个问题,像素是逐行排列的。由于每行都是width
像素,因此每行的大小为width * cCount
个字节。如果你想获得第二行的位置,你可以使用((2-1) * width) * cCount
。如果要获取该行中第四个像素的位置,可以使用((2-1) * width + (4-1)) * cCount
。因此,要使用坐标(x, y)
获取像素的位置,您将使用公式(y * width + x) * cCount
。
答案 1 :(得分:0)
并非总是如此,请查看this.这可能是您的优秀实施。
它可以是8,16,24,32等,因为颜色信息需要8个(或16个等)字节。
发布来源的示例代码:
// Get start index of the specified pixel
int i = ((y * Width) + x) * cCount;
if (i > Pixels.Length - cCount)
throw new IndexOutOfRangeException();
if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha
{
byte b = Pixels[i];
byte g = Pixels[i + 1];
byte r = Pixels[i + 2];
byte a = Pixels[i + 3]; // a
clr = Color.FromArgb(a, r, g, b);
}
if (Depth == 24) // For 24 bpp get Red, Green and Blue
{
byte b = Pixels[i];
byte g = Pixels[i + 1];
byte r = Pixels[i + 2];
clr = Color.FromArgb(r, g, b);
}
if (Depth == 8)
// For 8 bpp get color value (Red, Green and Blue values are the same)
{
byte c = Pixels[i];
clr = Color.FromArgb(c, c, c);
因为位图在内存中存储为数组。
(y *宽度)是尺寸,+ x)是尺寸中的像素,* cCount是每像素的步长。 (每个像素在内存中都需要cCount字节。)
可以把它想象成你把所有像素放在一条直线上,然后从左下角开始,向左上方开始,从左下角到第2行最上面的第二行结束,然后继续直到它到达右上角。