简体   繁体   English

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

[英]Visual Basic - Get Bitmap pixels as array

I'm making a game in Visual Basic using .NET Framework 4. Is there something similar to this (from Java): 我正在使用.NET Framework 4在Visual Basic中制作游戏。是否有与此类似的内容(来自Java):

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

for the Bitmap? 对于位图? Thanks. 谢谢。

You're looking for the LockBits method. 您正在寻找LockBits方法。

The Bitmap class provides the LockBits and corresponding UnlockBits methods which enable you to fix a portion of the bitmap pixel data array in memory, access it directly and finally replace the bits in the bitmap with the modified data. Bitmap类提供LockBits和相应的UnlockBits方法,使您可以修复内存中位图像素数据数组的一部分,直接访问它,最后用修改后的数据替换位图中的位。 LockBits returns a BitmapData class that describes the layout and position of the data in the locked array. LockBits返回一个BitmapData类,该类描述了锁定数组中数据的布局和位置。

The BitmapData class contains the following important properties; BitmapData类包含以下重要属性;

Scan0 The address in memory of the fixed data array Scan0固定数据阵列内存中的地址

Stride The width, in bytes, of a single row of pixel data. 跨度单行像素数据的宽度(以字节为单位)。 This width is a multiple, or possibly sub-multiple, of the pixel dimensions of the image and may be padded out to include a few more bytes. 该宽度是图像像素尺寸的倍数,或者可能是数倍,并且可以填充以包括更多字节。

PixelFormat The actual pixel format of the data. PixelFormat数据的实际像素格式。 This is important for finding the right bytes 这对于找到正确的字节很重要

Width The width of the locked image 宽度锁定图像的宽度

Height The height of the locked image 高度锁定图像的高度

The relationship of Scan0 and Stride to the array in memory is shown below: Scan0Stride与内存中的数组的关系如下所示:

的BitmapData

The Stride property, as shown in the image, holds the width of one row in bytes. 如图所示, Stride属性保留一行的宽度(以字节为单位)。 The size of a row however may not be an exact multiple of the pixel size because for efficiency, the system ensures that the data is packed into rows that begin on a four byte boundary and are padded out to a multiple of four bytes. 但是,行的大小可能不是像素大小的精确倍数,因为为了提高效率,系统确保将数据打包到以四个字节为边界的行中,并填充为四个字节的倍数。 This means for example that a 24 bit per pixel image 17 pixels wide would have a stride of 52. The used data in each row would take up 3*17 = 51 bytes and the padding of 1 byte would expand each row to 52 bytes or 13*4 bytes. 例如,这意味着一个17位宽的每像素24位图像的步幅为52。每行中使用的数据将占用3 * 17 = 51字节,而1字节的填充将每行扩展为52字节或13 * 4字节 A 4BppIndexed image of 17 pixels wide would have a stride of 12. Nine of the bytes, or more properly eight and a half, would contain data and the row would be padded out with a further 3 bytes to a 4 byte boundary. 一个17像素宽的4BppIndexed图像的步幅为12。其中9个字节(或更合适的是8个半字节)将包含数据,并且该行将被另外3个字节填充到4字节边界。

The data carrying portion of the row, as has been suggested above, is laid out according to the pixel format. 如上所述,该行的数据承载部分根据像素格式进行布局。 A 24 bit per pixel image containing RGB data would have a new pixel every 3 bytes, a 32 bit per pixel RGBA every four bytes. 包含RGB数据的每像素24位图像将每3个字节有一个新像素,每像素RGBA每4个字节有32位。 Pixel formats that contain more than one pixel per byte, such as the 4 bit per pixel Indexed and 1 bit per pixel indexed, have to be processed carefully so that the pixel required is not confused with it's neigbour pixels in the same byte. 每字节包含一个以上像素的像素格式(例如,每个像素索引4位和每个像素索引1位)必须谨慎处理,以使所需像素不会与同一字节中的近邻像素混淆。

Finding the right byte. 找到正确的字节。

Because the stride is the width of a row, to index any given row or Y coordinate you can multiply the stride by the Y coordinate to get the beginning of a particular row. 因为跨步是行的宽度,所以要索引任何给定的行或Y坐标,可以将跨步乘以Y坐标以获得特定行的开始。 Finding the correct pixel within the row is possibly more difficult and depends on knowing the layout of the pixel formats. 在行中查找正确的像素可能会更加困难,并且取决于了解像素格式的布局。 The following examples show how to access a particular pixel for a given pixel format. 以下示例说明如何访问给定像素格式的特定像素。

Format32BppArgb Given X and Y coordinates, the address of the first element in the pixel is Scan0+(y * stride)+(x*4). Format32BppArgb给定X和Y坐标,像素中第一个元素的地址为Scan0 +(y * stride)+(x * 4)。 This Points to the blue byte. 这指向蓝色字节。 The following three bytes contain the green, red and alpha bytes. 接下来的三个字节包含绿色,红色和Alpha字节。

Format24BppRgb Given X and Y coordinates, the address of the first element in the pixel is Scan0+(y*Stride)+(x*3). Format24BppRgb给定X和Y坐标,像素中第一个元素的地址为Scan0 +(y * Stride)+(x * 3)。 This points to the blue byte which is followed by the green and the red. 这指向蓝色字节,然后是绿色和红色。

Format8BppIndexed Given the X and Y coordinates the address of the byte is Scan0+(y*Stride)+x. Format8BppIndexed给定X和Y坐标,字节的地址为Scan0 +(y * Stride)+ x。 This byte is the index into the image palette. 该字节是图像调色板的索引。

Format4BppIndexed Given X and Y coordinates the byte containing the pixel data is calculated as Scan0+(y*Stride)+(x/2). Format4BppIndexed给定X和Y坐标,将包含像素数据的字节计算为Scan0 +(y * Stride)+(x / 2)。 The corresponding byte contains two pixels, the upper nibble is the leftmost and the lower nibble is the rightmost of two pixels. 相应的字节包含两个像素,两个像素中最上面的半字节为最左边,最下面的半字节为最右边。 The four bits of the upper and lower nibble are used to select the colour from the 16 colour palette. 上下半字节的四位用于从16个调色板中选择颜色。

Format1BppIndexed Given the X and Y coordinates, the byte containing the pixel is calculated by Scan0+(y*Stride)+(x/8). Format1BppIndexed给定X和Y坐标,包含像素的字节由Scan0 +(y * Stride)+(x / 8)计算。 The byte contains 8 bits, each bit is one pixel with the leftmost pixel in bit 8 and the rightmost pixel in bit 0. The bits select from the two entry colour palette. 该字节包含8位,每个位是一个像素,第8位为最左边的像素,第0位为最右边的像素。这些位从两个输入调色板中选择。

For pixel formats with one or more bytes per pixel, the formula is simple and can be accomplished by looping through all Y and X values in order. 对于每个像素一个或多个字节的像素格式,公式很简单,可以通过按顺序遍历所有Y和X值来实现。 The following code sets the blue component of a 32 bit per pixel image to 255. In both cases bm is a bitmap previously created. 下面的代码将每像素32位图像的蓝色分量设置为255。在两种情况下,bm都是先前创建的位图。 In c# a pointer in an unsafe block would be used: 在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;
    }
  }

In VB this operation would be treated a little differently because VB has no knowledge of pointers and requires the use of the marshal class to access unmanaged data. 在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 

*Code and article by Bob Powell, taken from the Internet Archive * Bob Powell的代码和文章,摘自Internet存档

Not sure why you might need this but GetPixel and SetPixel work just fine to edit or retrieve a pixel's color. 不知道为什么您可能需要这样做,但是GetPixel和SetPixel可以正常工作以编辑或检索像素的颜色。

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

Hope this helped! 希望这对您有所帮助!
~Nic 〜尼克

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM