Быстрый способ скопировать память с переводом - ARGB в BGR - PullRequest
65 голосов
/ 24 июля 2011

Обзор

У меня есть буфер изображения, который мне нужно преобразовать в другой формат. Исходный буфер изображения состоит из четырех каналов, 8 бит на канал, альфа, красный, зеленый и синий. Буфер назначения состоит из трех каналов, 8 бит на канал, синий, зеленый и красный.

Итак, метод грубой силы:

// Assume a 32 x 32 pixel image
#define IMAGESIZE (32*32)

typedef struct{ UInt8 Alpha; UInt8 Red; UInt8 Green; UInt8 Blue; } ARGB;
typedef struct{ UInt8 Blue; UInt8 Green; UInt8 Red; } BGR;

ARGB orig[IMAGESIZE];
BGR  dest[IMAGESIZE];

for(x = 0; x < IMAGESIZE; x++)
{
     dest[x].Red = orig[x].Red;
     dest[x].Green = orig[x].Green;
     dest[x].Blue = orig[x].Blue;
}

Однако мне нужна большая скорость, чем обеспечивается циклом и трехбайтовыми копиями. Я надеюсь, что есть несколько хитростей, которые я могу использовать, чтобы уменьшить количество операций чтения и записи в память, учитывая, что я работаю на 32-битной машине.

Дополнительная информация

Каждое изображение кратно минимум 4 пикселям. Таким образом, мы могли бы адресовать 16 байтов ARGB и перемещать их в 12 байтов RGB на цикл. Возможно, этот факт можно использовать для ускорения процесса, особенно когда он хорошо укладывается в 32-битные границы.

У меня есть доступ к OpenCL - и хотя для этого требуется переместить весь буфер в память GPU, а затем переместить результат обратно, тот факт, что OpenCL может работать одновременно на многих частях изображения, и тот факт, что большой блок памяти ходы на самом деле довольно эффективны, может сделать это исследование полезным.

Несмотря на то, что я привел приведенный выше пример небольших буферов, я действительно перемещаю HD-видео (1920x1080) и иногда более крупные, в основном меньшие, буферы вокруг, поэтому, хотя ситуация 32x32 может быть тривиальной, копирование 8,3 МБ байта данных изображения Байт действительно, очень плохо.

Работа на процессорах Intel (Core 2 и выше) и, следовательно, есть команды потоковой передачи и обработки данных, о которых я знаю, но я не знаю - возможно, указатели на то, где искать специализированные инструкции по обработке данных, были бы хорошими.

Это относится к приложению OS X, и я использую XCode 4. Если сборка безболезненна и очевидный путь, я в порядке, двигаясь по этому пути, но не сделав этого в этой настройке, прежде чем я опасаюсь затрачивать на это слишком много времени.

Псевдокод в порядке - я не ищу полного решения, просто алгоритм и объяснение любой хитрости, которая может быть не сразу понятна.

Ответы [ 11 ]

3 голосов
/ 24 июля 2011
typedef struct{ UInt8 Alpha; UInt8 Red; UInt8 Green; UInt8 Blue; } ARGB;
typedef struct{ UInt8 Blue; UInt8 Green; UInt8 Red; } BGR;

Помимо встроенных сборок или компиляторов, я мог бы попытаться сделать следующее, в то время как очень тщательно проверяет конечное поведение , так как некоторые из них (в случае с объединениями), вероятно, являются реализацией компиляторазависимый:

union uARGB
{
   struct ARGB argb;
   UInt32 x;
};
union uBGRA
{
   struct 
   {
     BGR bgr;
     UInt8 Alpha;
   } bgra;
   UInt32 x;
};

, а затем для ядра вашего кода, с любым подходящим циклом:

inline void argb2bgr(BGR* pbgr, ARGB* pargb)
{
    uARGB* puargb = (uARGB*)pargb;
    uBGRA ubgra;
    ubgra.x = __byte_reverse_32(pargb->x);
    *pbgr = ubgra.bgra.bgr;
}

, где __byte_reverse_32() предполагает существование встроенного компилятора, который обращает байты32-битное слово.

Чтобы подвести итог базового подхода:

  • просмотреть структуру ARGB как 32-разрядное целое число
  • обратить 32-разрядное целое число в обратном порядке
  • просмотретьобратное 32-разрядное целое число как структура (BGR)
  • позволяет компилятору копировать (BGR) часть структуры (BGR) A
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...