2013-03-15 11 views
13

Większość współczesnych aparatów CMOS może wyświetlać 12-bitowe obrazy z możliwością obróbki. Jaki byłby sposób, aby przekonwertować matrycę danych obrazu z 12bit na 16 bitów, aby przetwarzanie danych było możliwe? Prawdziwy problem polega na dopełnieniu każdej 12-bitowej liczby z 4 zerami, można przyjąć mały endian, dopuszczalne są również SSE2/SSE3/SS4.Najszybszy sposób konwersji obrazu 12-bitowego na obraz 16-bitowy

Kod dodania:

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

Dodałem kod. Konwertuj obraz 12-bitowy na tablicę zmiennoprzecinkową, ale można go również przesłać do UInt16 (wystarczy zmienić rzutowanie). – Gilad

+6

To zabawne, interesujące pytanie. Z pewnością nie trzeba go zamykać. – erisco

+0

Najszybsza ... zależy od platformy. Pamięć RAM, pamięć podręczna itp. Nie można używać SSE tylko z językiem C#. Zdefiniuj swoje parametry/ograniczenia i trzymaj się ich, proszę. W przeciwnym razie pytanie naprawdę nie jest odpowiedzialne. –

Odpowiedz

2

nie mogę zagwarantować najszybciej, ale jest to podejście, które wykorzystuje SSE. Osiem konwersji 12-16-bitowych jest wykonywanych w iteracji, a dwie konwersje (w przybliżeniu) są wykonywane na każdy krok (tj. Każda iteracja wymaga wielu kroków).

Podejście to obejmuje 12-bitowe liczby całkowite wokół granic 16-bitowych w rejestrze xmm. Poniżej pokazano, jak to się robi.

  • Używany jest jeden rejestr xmm (załóżmy xmm0). Stan rejestru jest reprezentowany przez jedną linię liter.
  • Każda litera reprezentuje 4 bity z 12bitowej liczby całkowitej (tj. AAA jest całym pierwszym 12-bitowym słowem w tablicy).
  • Każda przerwa reprezentuje 16-bitową granicę.
  • >> 2 oznacza logiczne przesunięcie w prawo o jeden bajt.
  • Symbol marchewki (^) służy do zaznaczenia, które 12-bitowe liczby 12-bitowe znajdują się na każdym kroku 16-bitowej granicy.

:

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

Na każdym kroku możemy wyodrębnić wyrównane całkowitymi 12bit i przechowywać je w rejestrze XMM1. Na końcu nasz xmm1 będzie wyglądał następująco. Znaki zapytania oznaczają wartości, na których nam nie zależy.

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

Ekstrakt wysokie wyrównane całkowite (A, C, E, G) do XMM2 a następnie na XMM2 należy przeprowadzić odpowiedni logiczny słowo przesunięcie 4 bitów. Spowoduje to przekonwertowanie liczb całkowitych o wysokiej wartości na wartość wyrównaną do dołu. Połącz te dostosowane liczby całkowite z powrotem do xmm1. Stan XMM1 jest teraz:

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

Wreszcie możemy zamaskować się z liczb całkowitych (tzn przekonwertować 's do 0'S?) Z 0FFFh na każdym słowie.

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

Teraz xmm1 zawiera osiem kolejnych skonwertowanych liczb całkowitych.

Następujący program NASM demonstruje ten algorytm.

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

Chciałbym zbudować rozwiązanie wokół instrukcji SSSE3 PSHUFB;

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

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

oprócz tego, że bajt wynikowy będzie wynosił zero, jeśli górny bit bX wynosi 1.

Zatem, jeżeli

 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 

Kompletny rozwiązanie odczytywane 3 lub 6 rejestrów mmx/Xmm i wyjścia 4/8 mmx/xmm rejestruje każdej rundy. Dwa środkowe wyjścia będą musiały być połączone z dwóch wejść, co wymaga dodatkowego kopiowania i łączenia rejestrów.

+0

Jestem nowy w zakresie programowania assemblera i instrukcji SSE. PSHUFB jest dość potężną instrukcją. Którą instrukcję używasz dla 'C = C.16 >> [4 0 4 0]'? Nie jestem pewien, co to znaczy, nawet biorąc pod uwagę wynik. – erisco

+0

To byłby PSRLW lub "przesunięcie w prawo logiczne słowo" przesunięcie o zmienną liczbę bitów. Wektor [4 0 4 0] oznacza drugi operand. Podano również przykłady dla rejestrów mmx, aby zilustrować tę koncepcję. Pożyczyłem prefiks .16 od neonowego świata. –

Powiązane problemy