C#LockBitmap - xy坐标到像素字节转换

时间:2016-03-22 09:18:09

标签: c# bitmap theory lockbits

我正在尝试学习用于图像处理的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;
}
  1. 什么是cCount,为什么总是Depth / 8
  2. int i = ((y * Width) + x) * cCount,这是从(x,y)坐标转换为Pixels[i]的固定公式吗?为什么?

2 个答案:

答案 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)

  1. 并非总是如此,请查看this.这可能是您的优秀实施。

    它可以是8,16,24,32等,因为颜色信息需要8个(或16个等)字节。

  2. 发布来源的示例代码:

     // 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);
    
    1. 因为位图在内存中存储为数组。

      (y *宽度)是尺寸,+ x)是尺寸中的像素,* cCount是每像素的步长。 (每个像素在内存中都需要cCount字节。)

    2. 可以把它想象成你把所有像素放在一条直线上,然后从左下角开始,向左上方开始,从左下角到第2行最上面的第二行结束,然后继续直到它到达右上角。