13

最新の CMOS カメラのほとんどは、12 ビットのベイヤー画像を生成できます。12ビットの画像データ配列を16ビットに変換して処理できるようにする最速の方法は何ですか? 実際の問題は、各 12 ビット数値を 4 つのゼロでパディングすることです。リトル エンディアンを想定できます。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 ビットへの変換が行われ、ステップごとに 2 回 (およそ) の変換が行われます (つまり、各反復には複数のステップが必要です)。

このアプローチは、xmm レジスターの 16 ビット境界で 12 ビット整数にまたがります。以下は、これがどのように行われるかを示しています。

  • 1 つの xmm レジスターが使用されています (xmm0 を想定)。レジスターの状態は、1 行の文字で表されます。
  • 各文字は 12 ビット整数の 4 ビットを表します (つまり、AAA は配列の最初の 12 ビット ワード全体です)。
  • 各ギャップは 16 ビット境界を表します。
  • >>2 は、1 バイトの論理右シフトを示します。
  • にんじん (^) 記号は、各ステップで 16 ビット境界にまたがっている関連する 12 ビット整数を強調するために使用されます。

:

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 には 8 つの連続する変換された整数が含まれています。

次の 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 の場合、結果のバイトはゼロになります。

したがって、

     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 レジスタを出力します。中間の 2 つの出力は、2 つの入力チャンクから結合する必要があり、追加のコピーとレジスターの結合が必要になります。

于 2013-03-18T07:33:37.493 に答える