2013-03-15 15 views
13

Die meisten modernen CMOS-Kamera kann 12bit bayered Bilder produzieren. Was wäre die schnellste Möglichkeit, ein Bilddaten-Array von 12bit zu 16bit zu konvertieren, so dass Verarbeitung möglich wäre? Das eigentliche Problem besteht darin, jede 12-Bit-Zahl mit 4 Nullen aufzufüllen, Little Endian kann angenommen werden, SSE2/SSE3/SS4 ebenfalls akzeptabel.Schnellster Weg, um 12-Bit-Bild in 16-Bit-Bild zu konvertieren

-Code hinzugefügt:

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++; 
     } 
    } 
+0

Ich habe etwas Code hinzugefügt. Die Konvertierung eines 12-Bit-Bildes in ein Float-Array kann aber auch in ein UInt16 umgewandelt werden (ändern Sie einfach das Casting) – Gilad

+6

Dies ist eine interessante Frage. Es muss sicherlich nicht geschlossen werden. – erisco

+0

Schnellste ... hängt von der Plattform ab. RAM, Cache, etc etc .. Sie können SSE nicht nur mit der C# -Sprache verwenden. Definieren Sie Ihre Parameter/Einschränkungen und halten Sie sich daran. Ansonsten ist die Frage wirklich nicht beantwortbar –

Antwort

2

ich nicht schnellste garantieren kann, aber das ist ein Ansatz, der SSE verwendet. Acht 12-16-Bit-Konvertierungen werden pro Iteration durchgeführt und zwei Konvertierungen (ungefähr) werden pro Schritt durchgeführt (dh jede Iteration benötigt mehrere Schritte).

Dieser Ansatz straddelt die 12-Bit-Ganzzahlen um die 16-Bit-Grenzen im xmm-Register. Unten zeigt, wie dies gemacht wird.

  • Ein xmm-Register wird verwendet (nehme xmm0 an). Der Zustand des Registers wird durch eine Buchstabenzeile dargestellt.
  • Jeder Buchstabe steht für 4 Bits einer 12-Bit-Ganzzahl (dh AAA ist das gesamte erste 12-Bit-Wort im Array).
  • Jede Lücke stellt eine 16-Bit-Grenze dar.
  • >> 2 bedeutet eine logische Rechtsverschiebung von einem Byte.
  • Das Karotte (^) Symbol wird verwendet, um hervorzuheben, welche relevanten 12-Bit-Ganzzahlen in jedem Schritt eine 16-Bit-Grenze überspannen.

:

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 
            ^^^ 

Bei jedem Schritt können wir die ausgerichteten 12-Bit-Integer und speichern sie in der XMM1 Register extrahieren. Am Ende wird unser xmm1 wie folgt aussehen. Fragezeichen bezeichnen Werte, die uns nicht interessieren.

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

Extrahieren der hochausgerichteten ganzen Zahlen (A, C, E, G) in xmm2 und dann auf xmm2, eine rechte logischen Wort Verschiebung von 4 Bits durchzuführen. Dadurch werden die hoch ausgerichteten Ganzzahlen in niedrig ausgerichtete konvertiert. Mischen Sie diese angepassten Ganzzahlen wieder in xmm1. Der Zustand der XMM1 ist jetzt:

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

Endlich können wir die ganzen Zahlen maskieren (dh wandeln die 's auf 0 ist?) Mit 0FFFh auf jedes Wort.

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

Jetzt enthält xmm1 acht aufeinanderfolgende konvertierte Ganzzahlen.

Das folgende NASM-Programm demonstriert diesen Algorithmus.

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

Ich würde versuchen, eine Lösung rund um die SSSE3-Anweisung zu erstellen PSHUFB;

Gegeben A = [a0, a1, a2, a3 ... a7], B = [b0, b1, b2, .. b7];

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

mit der Ausnahme, dass das Ergebnisbyte Null ist, wenn das oberste Bit von bX 1 ist.

Wenn also

 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 

Eine vollständige Lösung wäre in 3 oder 6 mmx/XMM Register und Ausgabe 4/8 MMX/XMM jeder Runde Register gelesen. Die mittleren zwei Ausgänge müssen aus zwei Eingangsbausteinen kombiniert werden, was ein zusätzliches Kopieren und Kombinieren von Registern erfordert.

+0

Ich bin neu in Assembly-Programmierung und SSE-Anweisungen. PSHUFB ist ziemlich die mächtige Anweisung. Welchen Befehl verwendest du für 'C = C.16 >> [4 0 4 0]'? Ich bin mir nicht sicher, was es bedeutet, auch wenn das Ergebnis so ist. – erisco

+0

Das wäre PSRLW, oder "gepackte Verschiebung, richtiges logisches Wort" Verschiebung um variable Anzahl von Bits. Der Vektor [4 0 4 0] bezeichnet den anderen Operanden. Auch die Beispiele sind für mmx-Register angegeben, nur um das Konzept zu veranschaulichen. Ich habe das Präfix .16 aus der Neonwelt ausgeliehen. –

Verwandte Themen