Visual Basic - 获取位图像素作为数组

Boo*_*dog 0 .net vb.net pixels

我正在使用 .NET Framework 4 在 Visual Basic 中制作游戏。是否有类似的东西(来自 Java):

private int[] pixels = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData();
Run Code Online (Sandbox Code Playgroud)

对于位图?谢谢。

Chr*_*way 5

你正在寻找LockBits方法。

Bitmap类提供了LockBits与对应的UnlockBits方法,使你在存储器以固定的位图像素数据阵列的一部分,访问它直接与最终替换的位与所述修改后的数据位图。LockBits返回一个BitmapData描述锁定数组中数据的布局和位置的类。

BitmapData类包含下列重要属性;

Scan0固定数据数组在内存中的地址

跨度单行像素数据的宽度(以字节为单位)。此宽度是图像像素尺寸的倍数或可能的约数,并且可以填充以包含更多字节。

PixelFormat 数据的实际像素格式。这对于找到正确的字节很重要

Width锁定图像的宽度

Height锁定图像的高度

Scan0Stride与内存中数组的关系如下图所示:

位图数据

步幅属性,如图像中所示,保持一个行的以字节为单位的宽度。然而,行的大小可能不是像素大小的精确倍数,因为为了效率,系统确保将数据打包到以四字节边界开始的行中,并填充为四字节的倍数。这意味着,例如,17 像素宽的每像素 24 位图像的步幅为 52。每行中使用的数据将占用 3*17 = 51 字节,1 字节的填充会将每行扩展到 52 字节或13*4 字节。17 个像素宽的 4BppIndexed 图像的步幅为 12。其中 9 个字节,或者更准确地说是 8 个半字节,将包含数据,并且该行将用另外 3 个字节填充到 4 个字节的边界。

如上所述,该行的数据承载部分是根据像素格式布置的。包含 RGB 数据的每像素 24 位图像每 3 个字节会有一个新像素,每 4 个字节每像素 32 位 RGBA。每字节包含一个以上像素的像素格式,例如每像素索引 4 位和每像素索引 1 位,必须仔细处理,以便所需的像素不会与同一字节中的相邻像素混淆。

找到正确的字节。

因为跨距是一行的宽度,要索引任何给定的行或 Y 坐标,您可以将跨距乘以 Y 坐标以获得特定行的开头。在行中找到正确的像素可能更困难,这取决于了解像素格式的布局。以下示例显示了如何访问给定像素格式的特定像素。

Format32BppArgb给定X和Y坐标,像素中第一个元素的地址为Scan0+(y * stride)+(x*4)。这指向蓝色字节。以下三个字节包含绿色、红色和 alpha 字节。

Format24BppRgb给定X和Y坐标,像素中第一个元素的地址为Scan0+(y*Stride)+(x*3)。这指向蓝色字节,其后是绿色和红色。

Format8BppIndexed给定 X 和 Y 坐标,字节的地址是 Scan0+(y*Stride)+x。该字节是图像调色板的索引。

Format4BppIndexed给定 X 和 Y 坐标,包含像素数据的字节计算为 Scan0+(y*Stride)+(x/2)。对应的字节包含两个像素,上半字节是最左边的,下半字节是最右边的两个像素。上下半字节的四位用于从 16 色调色板中选择颜色。

Format1BppIndexed给定 X 和 Y 坐标,包含像素的字节由 Scan0+(y*Stride)+(x/8) 计算。该字节包含 8 位,每一位是一个像素,最左边的像素位于第 8 位,最右边的像素位于第 0 位。这些位从两个入口调色板中选择。

对于每个像素有一个或多个字节的像素格式,公式很简单,可以通过按顺序循环遍历所有 Y 和 X 值来完成。以下代码将每像素 32 位图像的蓝色分量设置为 255。在这两种情况下,bm 都是先前创建的位图。在 c# 中,unsafe将使用块中的指针:

  BitmapData bmd=bm.LockBits(new Rectangle(0, 0, 10, 10), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat);
  int PixelSize=4;

  for(int y=0; y<bmd.Height; y++)
  {
    byte* row=(byte *)bmd.Scan0+(y*bmd.Stride);
    for(int x=0; x<bmd.Width; x++)
    {
      row[x*PixelSize]=255;
    }
  }
Run Code Online (Sandbox Code Playgroud)

在 VB 中,此操作的处理方式略有不同,因为 VB 不了解指针并且需要使用 marshal 类来访问非托管数据。

  Dim x As Integer
  Dim y As Integer
  Dim PixelSize As Integer = 4
  Dim bmd As BitmapData = bm.LockBits(new Rectangle(0, 0, 10, 10), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat)

  For y = 0 To bmd.Height - 1
    For x = 0 To bmd.Width - 1
      Marshal.WriteByte(bmd.Scan0, (bmd.Stride * y) + (4 * x) , 255)
    Next
  Next 
Run Code Online (Sandbox Code Playgroud)

*鲍勃鲍威尔的代码和文章,取自互联网档案馆