Быстрая обработка данных в C # .NET: от RRGGBB до Bitmap / C # Video / Image Processing - PullRequest
0 голосов
/ 28 ноября 2018

Я получаю данные изображения с камеры, которая поступает в виде массива слов от неуправляемой библиотеки DLL.

Мне удалось перенести данные в управляемую страну со скоростью, которая довольно хороша.

// cpp .NET
static void imageCallback(unsigned short * rawData, unsigned int length) {

    array<unsigned short>^ imageData = gcnew array<unsigned short>(length);

    unsigned int headLength = 512; // header length in shorts

    pin_ptr<unsigned short> imageDataStart = &imageData[0];
    memcpy(imageDataStart, rawData + headLength, length);

    callBackDelegate(imageData);
}

Данные упорядочены в виде шортов "RGBRGBRGB ...." для каждого цветового канала..

Управляемый массив затем отправляется на C # через делегата.Затем мне нужно преобразовать необработанные данные и вставить их в (8-битное) растровое изображение с помощью обычных методов, например, так:

    public static Bitmap RGBDataToBitmap(ushort[] data, int Width, int Height, int bitDepth)
    {
        Bitmap bmp = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);

        var rawdata = bmp.LockBits(new Rectangle(Point.Empty, bmp.Size), ImageLockMode.ReadWrite, bmp.PixelFormat);
        var pixelSize = rawdata.PixelFormat == PixelFormat.Format32bppArgb ? 4 : 3; // only works with 32 or 24 pixel-size bitmap!
        var padding = rawdata.Stride - (rawdata.Width * pixelSize);
        var bytes = new byte[rawdata.Height * rawdata.Stride];

        var index = 0;
        var pixel = 0;

        // scale to 8 bits
        var scalar = Math.Pow(2, -(bitDepth - 8));

        for (var y = 0; y < Height; y++)
        {
            for (var x = 0; x < Width; x++)
            {

                int Rlevel = (int)Math.Round(data[pixel + 0] * scalar);
                int Glevel = (int)Math.Round(data[pixel + 1] * scalar);
                int Blevel = (int)Math.Round(data[pixel + 2] * scalar);

                pixel += 3;

                bytes[index + 3] = 255; // A component 
                bytes[index + 2] = Convert.ToByte(Blevel); // B component
                bytes[index + 1] = Convert.ToByte(Glevel); // G component
                bytes[index + 0] = Convert.ToByte(Rlevel); // R component

                index += pixelSize;
            }

            index += padding;
        }

        // copy back the bytes from array to the bitmap
        System.Runtime.InteropServices.Marshal.Copy(bytes, 0, rawdata.Scan0, bytes.Length);

        bmp.UnlockBits(rawdata);

        return bmp;
    }

Если я синхронизирую эту операцию (от rawdata до растрового изображения), это займет ~ 0,5 секунды.,Кадры поступают со скоростью ~ 12 раз в секунду, так что это слишком медленно.

Кто-нибудь видит, как я могу ускорить эту операцию в C #?Или у кого-нибудь есть рекомендации по другому методу?

Цель состоит в том, чтобы получить живое видеоизображение на C #.

Спасибо!

РЕДАКТИРОВАТЬ:

В соответствии с приведенными ниже советами, если я изменю цикл for следующим образом:

        // scale to 8 bits
        var bitminus8 = bitDepth - 8;
        var scalar = Math.Pow(2, -(bitminus8));

        Parallel.For(0, Height, y =>
        {
            var index = y * Width;

            for (var x = 0; x < Width; x++)
            {
                var idx = index + x;

                byte Rlevel = (byte)(data[idx * 3 + 0] >> bitminus8);
                byte Glevel = (byte)(data[idx * 3 + 1] >> bitminus8);
                byte Blevel = (byte)(data[idx * 3 + 2] >> bitminus8);

                bytes[idx * 4 + 3] = 255; // A component 
                bytes[idx * 4 + 2] = Blevel; // B component
                bytes[idx * 4 + 1] = Glevel; // G component
                bytes[idx * 4 + 0] = Rlevel; // R component

            }
        });

Это идет от 0,5 секундыдо 0,04 секунды.Приятно немного о преобразовании байтов, которое имело большое значение.

...