Быстрая обработка данных в C# .NET: RRGGBB to Bitmap / C# Video / Image Processing

Я получаю данные изображения с камеры, которая поступает в виде массива ushorts из неуправляемой библиотеки 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;
    }

Если я синхронизирую эту операцию (исходные данные с растровым изображением), она занимает ~ 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 секунды. Хороший момент в преобразовании байтов, который имел большое значение.

Тогда зачем использовать теги C++? Вы привлекаете только взоры сварливых людей вроде меня, которые быстро нажимают кнопку «против».

user4581301 28.11.2018 02:05

сначала почему var scalar = Math.Pow(2, -(bitDepth - 8)); называется х * у раз? и почему именно if (Xlevel < 0) { Xlevel= 0; }? Xlevel не может быть <0

Selvin 28.11.2018 02:06

Найдите unsafe для C#

Tony J 28.11.2018 02:09
даже больше ... результаты почти такие же ... угадайте, что быстрее ... в любом случае вы не получите 12 Гц при создании растровых изображений ... если вы хотите показать это, вам лучше использовать графический процессор напрямую с этим буфером
Selvin 28.11.2018 02:58

Вы на x86?

Hadi Brais 28.11.2018 03:21

Может ли bitDepth быть меньше 8? Может ли data содержать значения больше 255? Как Rlevel, Glevel, Blevel могут быть отрицательными? Можете ли вы использовать byte вместо ushort? Также, как сказал Селвин, кажется, что вы можете вывести расчет scalar за пределы цикла.

Hadi Brais 28.11.2018 03:30

Вы можете легко распараллелить внешний цикл.

Hadi Brais 28.11.2018 04:47

Всем привет, спасибо за комментарии. Я отредактировал и отвечаю всем вам: я помечаю C++, потому что у меня есть возможность манипулировать данными в неуправляемой области. Или, может быть, кто-то знаком, скажем, с OpenCV и знает, что это поможет мне. Да, скаляр не должен входить в цикл (переместил его). Я проверю небезопасно. GPU напрямую? Как? Может быть, OpenCV или Aforge.NET или что-то подобное? Да, x86. Bitdepth> = 8. Я удалил другие вещи, не относящиеся к этому вопросу (уровни не должны быть отрицательными, это было для отладки). Да, распараллелить внешний цикл. Можете ли вы указать мне пример? Спасибо.

Alex Martin 28.11.2018 16:55

Похоже, что параллельный и небезопасный маршрут может быть хорошим, я постараюсь реализовать это и опубликовать ответ.

Alex Martin 28.11.2018 17:00

Итак, теперь вы можете обрабатывать 25 кадров в секунду, верно? На сколько логических / физических ядер? Вы хотите, чтобы это было быстрее? Использование графического процессора может быть хорошим вариантом, если вы не хотите, чтобы ваша программа занимала слишком много времени процессора.

Hadi Brais 29.11.2018 02:32

Теперь я бегаю так быстро, как драйвер камеры может выталкивать изображения. Можете ли вы указать мне на ресурс, который может помочь мне в использовании графического процессора? Мне нужно выполнить дополнительную обработку изображений.

Alex Martin 29.11.2018 17:02
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
11
111
0

Другие вопросы по теме