Быстрое изменение растрового изображения с использованием BitmapData и указателей в 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);
}
И я делаю это для каждого входящего кадра. Он работает нормально, но все равно занимает около 30 мс для каждого кадра 320x240 пикселей.
Можно ли сделать это еще быстрее? Может быть, я мог заблокировать / разблокировать данные в памяти только один раз, но я не уверен в этом.
2 ответа
Вместо того, чтобы вычислять x и y для каждого пикселя, вы можете сделать их счетчиками циклов, например так:
for( y = 0; y < bmp.Height; y++ )
for( x = 0; x < bmp.Width; x++ )
А еще лучше, угробить х и у в целом и просто увеличивать 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);
}
Попробуйте запустить код параллельно: изменить
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;
}
});