Search code examples
c#performancebitmapdatalockbits

Fast Bitmap modifying using BitmapData and pointers in C#


I am capturing data from some camera (array of RAW data).

Then I'm mapping this data to RGB values according to color palette.

I need to map it as fast as possible, so I use BitmapDdata and edit pixels in unsafe piece of code using pointers.

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

And I'm doing this for every incoming frame. It works fine, but it still takes something like 30ms for each frame for 320x240 pixels.

Is it possible to make it even more faster? Maybe I couldlock/unlock data in memory only once, but I'm not sure about this.


Solution

  • Instead of calculating x and y for each pixel, you could make them loop counters, like this:

    for( y = 0;  y < bmp.Height;  y++ )
        for( x = 0;  x < bmp.Width;  x++ )
    

    Better yet, ditch x and y altogether and just keep incrementing the ptr pointer instead of recalculating an offset from the ptr pointer three times per pixel.

    Try this (warning: I have not checked it.)

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