13

大多数现代 CMOS 相机可以产生 12 位的拜耳图像。将12 位图像数据数组转换为 16 位以便进行处理的最快方法是什么?实际问题是用 4 个零填充每个 12 位数字,可以假设小端,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++;
      }
  }
4

2 回答 2

3

我不能保证最快,但这是一种使用SSE的方法。每次迭代完成 8 次 12-16 位转换,每步完成两次转换(大约)(即,每次迭代需要多个步骤)。

这种方法跨越 xmm 寄存器中 16 位边界周围的 12 位整数。下面显示了这是如何完成的。

  • 正在使用一个 xmm 寄存器(假设 xmm0)。寄存器的状态由一行字母表示。
  • 每个字母代表一个 12 位整数的 4 位(即,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

最后,我们可以在每个单词上使用 0FFFh 来屏蔽整数(即,将 ? 转换为 0)。

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
于 2013-03-18T03:00:24.250 回答
1

我会尝试围绕 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,则结果字节将为 0。

因此,如果

     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 个 mmx / xmm 寄存器并每轮输出 4/8 mmx/xmm 寄存器。中间的两个输出必须从两个输入块组合,需要一些额外的寄存器复制和组合。

于 2013-03-18T07:33:37.493 回答