2013-03-15 13 views
13

La maggior parte delle moderne fotocamere CMOS è in grado di produrre immagini a 12 bit. Quale sarebbe il modo più veloce per convertire una matrice di dati di immagine da 12 bit a 16 bit, quindi l'elaborazione sarebbe possibile? Il vero problema è il riempimento di ogni numero di 12 bit con 4 zeri, si può ipotizzare little endian, anche SSE2/SSE3/SS4 accettabile.Il modo più veloce per convertire un'immagine a 12 bit in un'immagine a 16 bit

Codice aggiunto:

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

Ho aggiunto del codice. Converti un'immagine a 12 bit in una matrice mobile, ma può anche essere convertita in un UInt16 (cambia semplicemente il cast) – Gilad

+6

Questa è una domanda divertente e interessante. Di certo non ha bisogno di essere chiuso. – erisco

+0

Il più veloce ... dipende dalla piattaforma. RAM, cache, ecc. Ecc. Non è possibile utilizzare SSE solo con il linguaggio C#. Definire i parametri/vincoli e attenersi a loro, per favore. Altrimenti la domanda in realtà non è rispondente –

risposta

2

Non posso garantire più veloce, ma questo è un approccio che utilizza SSE. Otto conversioni da 12-16 bit sono fatte per iterazione e due conversioni (circa) sono fatte per step (cioè, ogni iterazione richiede più passaggi).

Questo approccio è a cavallo degli interi a 12 bit attorno ai limiti di 16 bit nel registro xmm. Qui sotto mostra come è fatto.

  • È in uso un registro xmm (assumere xmm0). Lo stato del registro è rappresentato da una riga di lettere.
  • Ogni lettera rappresenta 4 bit di un intero 12 bit (ovvero, AAA è l'intera prima parola a 12 bit nell'array).
  • Ogni spazio rappresenta un limite di 16 bit.
  • >> 2 indica uno spostamento logico di destra di un byte.
  • Il simbolo carota (^) viene utilizzato per evidenziare quali rilevanti numeri interi a 12 bit si trovano a cavallo di un limite di 16 bit in ogni passaggio.

:

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

Ad ogni passo, siamo in grado di estrarre i numeri interi 12bit allineati e memorizzarli nel registro delle XMM1. Alla fine, il nostro xmm1 avrà il seguente aspetto. I punti interrogativi indicano valori che non ci interessano.

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

Estrarre alto allineato interi (A, C, E, G) in XMM2 e poi, sul XMM2, eseguire uno shift verso destra parola logica di 4 bit. Ciò convertirà gli interi allineati in alto in allineati bassi. Miscelare questi numeri interi modificati in xmm1. Lo stato di XMM1 è ora:

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

finalmente possiamo mascherare i numeri interi (ad esempio, convertire il s 'a 0 di?) Con 0FFFH su ogni parola.

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

Ora xmm1 contiene otto numeri interi convertiti consecutivi.

Il seguente programma NASM dimostra questo algoritmo.

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

mi piacerebbe provare a costruire una soluzione in tutto l'istruzioni SSSE3 PSHUFB;

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

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

eccetto che il byte risultato sarà zero, se il bit superiore di bX è 1.

Pertanto, se

 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 

Una soluzione completa leggerebbe in 3 o 6 registri mmx/XMM e uscita 4/8 mmx/xmm registri ogni turno. Le due uscite centrali dovranno essere combinate da due blocchi di input, richiedendo copie aggiuntive e combinazioni di registri.

+0

Sono nuovo alla programmazione di assiemi e alle istruzioni SSE. PSHUFB è piuttosto la potente istruzione. Quale istruzione stai usando per 'C = C.16 >> [4 0 4 0]'? Non sono sicuro di cosa significhi anche in considerazione del risultato. – erisco

+0

Quello sarebbe PSRLW, o "parola logica corretta spostata del carico" spostamento dal numero variabile dei bit. Il vettore [4 0 4 0] designa l'altro operando. Anche gli esempi sono forniti per i registri di mmx solo per illustrare il concetto. Ho preso in prestito il prefisso .16 dal mondo neon. –

Problemi correlati