在 C# 中使用 BitmapData 和指针快速修改位图
Fast Bitmap modifying using BitmapData and pointers in C#
我正在从一些相机(RAW 数据数组)捕获数据。
然后我根据调色板将此数据映射到 RGB 值。
我需要尽快映射它,所以我使用 BitmapDdata
并使用指针编辑不安全代码段中的像素。
public void dataAcquired(int[] data)
{
Bitmap bmp = new Bitmap(width, height);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
for (int i = 0; i < data.Length; i++)
{
int x = i % bmp.Width;
int y = i / bmp.Width;
Rgb rgb = mapColors[data[i]];
unsafe
{
byte* ptr = (byte*)data.Scan0;
ptr[(x * 3) + y * data.Stride] = rgb.b;
ptr[(x * 3) + y * data.Stride + 1] = rgb.g;
ptr[(x * 3) + y * data.Stride + 2] = rgb.r;
}
}
bmp.UnlockBits(data);
}
我正在为每个传入的帧执行此操作。它工作正常,但对于 320x240 像素的每帧仍然需要大约 30 毫秒。
是否可以让它更快?也许我 couldlock/unlock 内存中的数据只有一次,但我不确定。
并行尝试 运行 代码 :更改
for (int i = 0; i < data.Length; i++) {
...
}
进入
Parallel.For(0, data.Length, (i) => {
int x = i % bmp.Width;
int y = i / bmp.Width;
Rgb rgb = mapColors[data[i]];
unsafe {
byte* ptr = (byte*) data.Scan0;
ptr[(x * 3) + y * data.Stride] = rgb.b;
ptr[(x * 3) + y * data.Stride + 1] = rgb.g;
ptr[(x * 3) + y * data.Stride + 2] = rgb.r;
}
});
您可以让它们循环计数器,而不是为每个像素计算 x 和 y,如下所示:
for( y = 0; y < bmp.Height; y++ )
for( x = 0; x < bmp.Width; x++ )
更好的是,完全放弃 x 和 y,只继续递增 ptr
指针,而不是每个像素三次重新计算 ptr
指针的偏移量。
试试这个(警告:我还没有检查过。)
public void dataAcquired()
{
Bitmap bmp = new Bitmap(width, height);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
int i = 0;
byte* ptr = (byte*)data.Scan0;
for( int y = 0; y < bmp.Height; y++ )
{
byte* ptr2 = ptr;
for( int x = 0; x < bmp.Width; x++ )
{
Rgb rgb = mapColors[data[i++]];
*(ptr2++) = rgb.b;
*(ptr2++) = rgb.g;
*(ptr2++) = rgb.r;
}
ptr += data.Stride;
}
}
bmp.UnlockBits(data);
}
我正在从一些相机(RAW 数据数组)捕获数据。
然后我根据调色板将此数据映射到 RGB 值。
我需要尽快映射它,所以我使用 BitmapDdata
并使用指针编辑不安全代码段中的像素。
public void dataAcquired(int[] data)
{
Bitmap bmp = new Bitmap(width, height);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
for (int i = 0; i < data.Length; i++)
{
int x = i % bmp.Width;
int y = i / bmp.Width;
Rgb rgb = mapColors[data[i]];
unsafe
{
byte* ptr = (byte*)data.Scan0;
ptr[(x * 3) + y * data.Stride] = rgb.b;
ptr[(x * 3) + y * data.Stride + 1] = rgb.g;
ptr[(x * 3) + y * data.Stride + 2] = rgb.r;
}
}
bmp.UnlockBits(data);
}
我正在为每个传入的帧执行此操作。它工作正常,但对于 320x240 像素的每帧仍然需要大约 30 毫秒。
是否可以让它更快?也许我 couldlock/unlock 内存中的数据只有一次,但我不确定。
并行尝试 运行 代码 :更改
for (int i = 0; i < data.Length; i++) {
...
}
进入
Parallel.For(0, data.Length, (i) => {
int x = i % bmp.Width;
int y = i / bmp.Width;
Rgb rgb = mapColors[data[i]];
unsafe {
byte* ptr = (byte*) data.Scan0;
ptr[(x * 3) + y * data.Stride] = rgb.b;
ptr[(x * 3) + y * data.Stride + 1] = rgb.g;
ptr[(x * 3) + y * data.Stride + 2] = rgb.r;
}
});
您可以让它们循环计数器,而不是为每个像素计算 x 和 y,如下所示:
for( y = 0; y < bmp.Height; y++ )
for( x = 0; x < bmp.Width; x++ )
更好的是,完全放弃 x 和 y,只继续递增 ptr
指针,而不是每个像素三次重新计算 ptr
指针的偏移量。
试试这个(警告:我还没有检查过。)
public void dataAcquired()
{
Bitmap bmp = new Bitmap(width, height);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
int i = 0;
byte* ptr = (byte*)data.Scan0;
for( int y = 0; y < bmp.Height; y++ )
{
byte* ptr2 = ptr;
for( int x = 0; x < bmp.Width; x++ )
{
Rgb rgb = mapColors[data[i++]];
*(ptr2++) = rgb.b;
*(ptr2++) = rgb.g;
*(ptr2++) = rgb.r;
}
ptr += data.Stride;
}
}
bmp.UnlockBits(data);
}