【问题标题】:Fast Bitmap modifying using BitmapData and pointers in C#在 C# 中使用 BitmapData 和指针快速修改位图
【发布时间】:2015-02-04 14:09:36
【问题描述】:

我正在从某个相机捕获数据(原始数据数组)。

然后我根据调色板将此数据映射到 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 毫秒。

是否有可能让它更快?也许我只能锁定/解锁内存中的数据一次,但我不确定。

【问题讨论】:

标签: c# performance bitmapdata lockbits


【解决方案1】:

您可以将它们设为循环计数器,而不是为每个像素计算 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);
}

【讨论】:

  • 谢谢!完美运行,尤其是两个循环将计算时间减少了一半。两个指针的解决方案在这种情况下没有明显的效果,但至少更优雅。
  • @Majak 太棒了!很高兴有帮助。我认为并行化不会有多大帮助,因为这个操作非常受内存限制,而且无论你的 CPU 有多少个内核,它仍然只有一个地址总线和一个数据总线。但如果您尝试并行化,请告诉我们您观察到的情况。
  • 由于难以同步,我放弃了并行化的想法,这对我来说太过分了,因为我没有这方面的经验。但是,我又做了一个修改,我现在使用已经初始化的“宽度,高度”值,而不是从 Bitmap 类中获取它,此时,我得到了 0 毫秒的时间!我以为这个时间测错了,但是我的相机现在是在 60 fps 模式下工作,所以时间消耗似乎真的接近于零。
【解决方案2】:

尝试运行代码并行:改变

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;
    }
  });

【讨论】:

    猜你喜欢
    • 2010-12-06
    • 2019-11-05
    • 1970-01-01
    • 2020-06-05
    • 1970-01-01
    • 2012-11-23
    • 2021-04-09
    • 2014-12-23
    • 1970-01-01
    相关资源
    最近更新 更多