将12bit图像转换为16bit图像的最快方法

时间:2013-03-15 23:46:30

标签: image performance optimization image-processing

大多数现代CMOS相机都可以产生12bit的Bayered图像。 什么是最快方式将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++;
      }
  }

2 个答案:

答案 0 :(得分:2)

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

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

  • 正在使用一个xmm寄存器(假设为xmm0)。寄存器的状态由一行字母表示。
  • 每个字母代表一个12位整数的4位(即,AAA是数组中的第一个12位字)。
  • 每个间隙代表一个16位边界。
  • &gt;&gt; 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

答案 1 :(得分: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。

因此,如果

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