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

Visual Basic - Get Bitmap pixels as array

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

private int[] pixels = ((DataBufferInt) bufferedImage.getRaster().getDataBuffer()).getData();

对于位图?谢谢

不确定您为什么需要这个,但 GetPixel 和 SetPixel 可以很好地编辑或检索像素的颜色。

Bitmap.GetPixel(X, Y) ' Returns a color.
Bitmap.SetPixel(X, Y, Color)

希望这对您有所帮助!
~尼克

您正在寻找 LockBits 方法。

Bitmapclass提供了LockBits和对应的UnlockBits方法,可以将位图像素数据数组的一部分固定在内存中,直接访问最后用修改后的数据替换位图中的位。 LockBits returns 描述锁定数组中数据的布局和位置的 BitmapData class。

BitmapData class 包含以下重要属性;

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

步长 单行像素数据的宽度,以字节为单位。此宽度是图像像素尺寸的倍数或约数,可以填充以包含更多字节。

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

宽度锁定图片的宽度

高度锁定图片的高度

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

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

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

找到正确的字节。

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

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

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

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

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

Format1BppIndexed给定X和Y坐标,通过Scan0+(y*Stride)+(x/8)计算包含像素的字节。该字节包含 8 位,每一位是一个像素,最左边的像素位于第 8 位,最右边的像素位于第 0 位。来自两个条目调色板的位 select。

对于每个像素一个或多个字节的像素格式,公式很简单,可以通过按顺序遍历所有 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;
    }
  }

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

  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 

*Bob Powell 的代码和文章,摘自 Internet Archive