Подтвердить что ты не робот

Самый быстрый способ конвертировать 12-битное изображение в 16-битное изображение

Большинство современных CMOS-камер могут создавать 12-битные изображения. Каким будет быстрый способ преобразования массива данных изображения с 12 бит на 16 бит, чтобы обработка была возможна? Фактическая проблема заключается в заполнении каждого 12-битного числа с 4 нулями, можно предположить, что может быть принят маленький endian, также приемлемо SSE2/SSE3/SS4.

Добавлен код:

int* imagePtr = (int*)Image.data;
fixed (float* imageData = img.Data)
{
   float* imagePointer = imageData;
   for (int t = 0; t < total; t++)
      {
         int i1 = *imagePtr;
         imagePtr = (int*)((ushort*)imagePtr + 1);
         int i2 = *imagePtr;
         imagePtr = (int*)((ushort*)imagePtr + 2);
         *imagePointer = (float)(((i1 << 4) & 0x00000FF0) | ((i1 >> 8) & 0x0000000F));
         imagePointer++;
         *imagePointer = (float)((i1 >> 12) & 0x00000FFF);
         imagePointer++;
         *imagePointer = (float)(((i2 >> 4) & 0x00000FF0) | ((i2 >> 12) & 0x0000000F));
         imagePointer++;
         *imagePointer = (float)((i2 >> 20) & 0x00000FFF);
         imagePointer++;
      }
  }
4b9b3361

Ответ 1

Я не могу гарантировать быстрый, но это подход, который использует SSE. Для каждой итерации выполняется восемь преобразований на 12-16 бит, а для каждого шага выполняется два преобразования (приблизительное) (т.е. каждая итерация занимает несколько шагов).

Этот подход охватывает 12-битные целые числа вокруг 16-битных границ в регистре xmm. Ниже показано, как это делается.

  • Используется один регистр xmm (предположим xmm0). Состояние регистра представлено одной строкой букв.
  • Каждая буква представляет собой 4 бита целочисленного 12-битного числа (т.е. AAA - это все первое 12-битное слово в массиве).
  • Каждый зазор представляет собой 16-разрядную границу.
  • → 2 указывает логический сдвиг вправо одного байта.
  • Символ моркови (^) используется, чтобы выделить, какие соответствующие 12-битные целые числа разделяют 16-битную границу на каждом шаге.

:

load
AAAB BBCC CDDD EEEF FFGG GHHH JJJK KKLL
^^^

>>2
00AA ABBB CCCD DDEE EFFF GGGH HHJJ JKKK
      ^^^ ^^^    

>>2
0000 AAAB BBCC CDDD EEEF FFGG GHHH JJJK
                ^^^ ^^^    

>>2
0000 00AA ABBB CCCD DDEE EFFF GGGH HHJJ
                          ^^^ ^^^    

>>2
0000 0000 AAAB BBCC CDDD EEEF FFGG GHHH
                                    ^^^

На каждом шаге мы можем извлечь выровненные 12-битные целые числа и сохранить их в регистре xmm1. В конце, наш xmm1 будет выглядеть следующим образом. Вопросительные знаки обозначают значения, которые нам не нужны.

AAA? ?BBB CCC? ?DDD EEE? ?FFF GGG? ?HHH

Извлеките высокоограниченные целые числа (A, C, E, G) в xmm2, а затем на xmm2 выполните правильный сдвиг логического слова в 4 бита. Это преобразует выровненные целые числа с низким выровненным. Смешайте эти скорректированные целые числа обратно в xmm1. Теперь состояние xmm1:

?AAA ?BBB ?CCC ?DDD ?EEE ?FFF ?GGG ?HHH

Наконец, мы можем замаскировать целые числа (т.е. преобразовать "0" ) с 0FFFh для каждого слова.

0AAA 0BBB 0CCC 0DDD 0EEE 0FFF 0GGG 0HHH

Теперь xmm1 содержит восемь последовательных преобразованных целых чисел.

Следующая программа NASM демонстрирует этот алгоритм.

global main

segment .data
sample dw 1234, 5678, 9ABCh, 1234, 5678, 9ABCh, 1234, 5678
low12 times 8 dw 0FFFh

segment .text
main:

  movdqa xmm0, [sample]

  pblendw xmm1, xmm0, 10000000b
  psrldq xmm0, 1
  pblendw xmm1, xmm0, 01100000b
  psrldq xmm0, 1
  pblendw xmm1, xmm0, 00011000b
  psrldq xmm0, 1
  pblendw xmm1, xmm0, 00000110b
  psrldq xmm0, 1
  pblendw xmm1, xmm0, 00000001b

  pblendw xmm2, xmm1, 10101010b
  psrlw xmm2, 4

  pblendw xmm1, xmm2, 10101010b

  pand xmm1, [low12]        ; low12 could be stored in another xmm register

Ответ 2

Я попытался бы построить решение вокруг инструкции SSSE3 PSHUFB;

Учитывая A = [a0, a1, a2, a3... a7], B = [b0, b1, b2,.. b7];

 PSHUFB(A,B) = [a_b0, a_b1, a_b2, ... a_b7],

за исключением того, что байт результата будет равен нулю, если верхний бит bX равен 1.

Таким образом, если

     A  = [aa ab bb cc cd dd ee ef] == input vector

C=PSHUFB(A, [0 1 1 2 3 4 4 5]) = [aa ab ab bb cc cd cd dd]
C=PSRLW (C, [4 0 4 0])         = [0a aa ab bb 0c cc cd dd] // (>> 4)
C=PSLLW (C, 4)                 = [aa a0 bb b0 cc c0 dd d0] // << by immediate

Полное решение будет считываться в регистре 3 или 6 мм x/xмм, а выход 4/8 мм x/xмм регистрирует каждый раунд. Средние два выхода должны быть объединены из двух входных блоков, требующих дополнительного копирования и объединения регистров.