Kodowanie obrazu metodą DPCM

 

1.      Celem projektu było skonstruowanie kodera DPCM działającego na platformie spyder FPGA Virtex XCV300.

           

Koder DPCM koduje różnicę między przewidywaną i rzeczywistą wartością każdej próbki. Dekoder natomiast odtwarza oryginalny sygnał używając przewidzianej przez siebie wartości oraz zakodowanej różnicy. Jak w każdej metodzie predykcyjnej, efektywność DPCM zależy od zdolności algorytmu predykcji do nadążania za zmianami w sygnale wejściowym.

Top of Form

Bottom of Form

 

W układzie kodera/dekodera DPCM użyto predykcyjnego kodowania bezstratnego. Dzięki temu obraz różnicowy (błędu predykcji) ma znacznie zmniejszoną wariancję co widać na poniższych obrazkach (dane z matlaba):

 

rys 1. histogram obrazka źródłowego

 

Oś pozioma reprezentuje poziomy szarości (0-255), natomiast pionowa częstotoliwość występowania danego odcienia w kodowanym obrazku.

rys 2. histogram obrazu błędu (error image)

 

Obraz błędu powstały po kodowaniu DPCM ma zmienioną statystykę w stosunku do źródła: histogram sygnału różnicowego w pobliżu centrum ma duże wartości, może to być wykorzystane przez enkoder Huffmana. Dzięki DPCM obraz błędu jest znacznie mniej skorelowany od obrazu źródłowego.

2.      Schemat ideowy kodera i dekodera DPCM:

 

rys. 3. schemat nadajnika i odbiornika DPCM

W naszym układzie nie ma kwantyzera, obrazek może przyjmować 255 odcieni szarości.

3.      Obrazkiem testowym była (jak można się było spodziewać ;) Lena:

 

rys 4.  lena.jpg

4.      Współczynniki predykcji.

rys 4. dwuwymiarowa predykcja

 

Użyliśmy predyktora 2-wymiarowego, który cechuje się poziomem SNR o 3 dB lepszym niż predyktor 1D. Wadą tego rozwiązania jest konieczność buforowania poprzedniej linii. Ilość pikseli wykorzystywanych do predykcji to rząd predyktora, my użyliśmy dwóch (A z wagą 0.5 i B z wagą 0.5)

= 0.50A+0.50C

5.      Schemat kodera i dekodera.

 

Układ połączonego kodera i dekodera:

 

rys 5. tor przetwarzania koder-dekoder (układ dpcm_lite)

 

Sygnał wejściowy (z intefejsu spyder) wchodzi na wejście PIN(7:0) kodera dpcm, flaga OUTREADY informuje FPGA o gotowości spyder_interface na przyjęcie danych. DPCM_OUT(16:8) to obraz błędu, wygląda jak płaskorzeźba, im bardziej „wyrównane” są na nim odcienie szarości tym lepsza została osiągnięta predykcja:

 

rys 6. obraz błędu (error image)

Dane wychodzą z toru przetwarzania na wyjściu POUT(7:0) (dpcm_decoder) i są ładowane na spyder_interface sygnałem WRITEDATA. Są one ładowane do spyder_interface jednak nie z tego wyjścia ale z wyjścia DEL_OUT(16:0) układu delay. Układ ten zatrzaskuje dane wyjściowe ze względu na to że są one poprawne tylko przez czas stanu wysokiego na INPUTDATAVALID (2 cykle, ale skrócone do jednego przez układ ce_gen ).

Sygnały STOPI i STOPO wykorzystywane są tylko w symulacji (testbench DPCM_Lite_tb). Wejście nEN to chip enable układów, reset układu, RST jest aktywny stanem niskim.

 

Mnożenie przez współczynniki zmiennoprzecinkowe 0.5 zostało zrealizowane poprzez przesuwanie danych o n bitów, co daje przy przesunięciu w lewo o n-bitów mnożenie przez 2 do potęgi n (analogicznie dzielenie). Układ BUF służy do buforowania poprzedniej linii, CE_GEN skraca impuls INPUTDATAVALID ze spyder_interface tak żeby trwał tylko jeden cykl zegara SYS_CLK. Układy adder_9, adder_13 i subst_8 realizują odpowiednio operacje dodawania i odejmowania.

6. Komunikacja FPGA z interfejsem spyder.

 

Sygnały OUTREADY i WRITEDATA zostały opisane wcześniej. W układzie  DPCM_lite został umieszczony układ DELAY. Jest to rejestr, który zatrzaskuje dane opadającym zboczem zegara przy CEO w stanie wysokim i wystawia te dane przy następnym zboczu opadającym,  celem zapisu do OUTPUTPORT (jest to konieczne bo dane na wyjściu INPUTPORT są ważne tylko przez dwa takty zegara.

Wejście PIN kodeka korzysta z INPUTPORT(7:0), a wyjście FPGA_OUT jest mapowane na port OUTPUTPORT.

 

 

7. Program wczytujący / zapisujący obrazki.

 

Dane obrazka podawane są na magistrale PCI za pomocą programu napisanego w C. Następnie idą na interfejs spyder_interface który pośredniczy pomiędzy PCI a FPGA Virtex. Obrazek (*.pgm) musi mieć nie więcej niż 142 pixele szerokości i powinien być w formacie PGM (portable grey bitmap). Po przetworzeniu przez kodek program zapisuje 2 obrazki wyjściowe: jeden który powinien być taki jak oryginał (output.pgm) i drugi obraz błędu (error.pgm).

program

 

8. Testbenche

 

a) Testbenche są dwa, jeden jest w pliku DPCM_with_PCI_tb.vhd, podaje on liczby od 1 do 1000 z krokiem 1(inkrementer) na fpga i odczytuje je z powrotem.

Waveform z testbencha:

 

Widzimy że liczba „6A” wystawiona na INPUTPORT przy LA = FC jest też obecna na 8 najmniej znaczących bitach portu OUTPUTPORT (a na 16:8 są dane obrazu błędu) ładowana wysokim stanem LOADOUTPUTINTERFACE.

Na poniższym waveformie można zauważyć, że dana z wyjścia toru DPCM „UUU?0507” (gdzie ‘07’ to bajt obrazka wyjściowego, a ‘05’ bajt obrazka błędu) załadowana wcześniej na do spyder_interface wysokim stanem LOADOUTPUTINTERFACE, pojawia się na magistrali danych przy zmianie FRD_0 ze stanu wysokiego na stan niski. W nieco dalszej chwili czasowej widzimy zapis do FPGA strobem FWR_0 (dana „00000008”).

 

b) Drugim testbenchem jest DPCM_lite_tb.vhd, który obrazuję tor przetwarzania DPCM:

(na czas symulacji tego tb konieczne jest przepięcie sygnału nEN z wejścia CE ce_gen na wejście CE BUF)

 

            Sygnał na wyjściu pojawia się natychmiast po sygnale wyjściowym, po implementacji będą widoczne opóźnienia:

 

 

(ERR jest taki sam jak POUT ponieważ sygnał nEN nie był wysterowany jak do normalnej pracy).

  

 

Testbench ten, otwiera plik tekstowy w którym umieszczone są dane obrazka. Plik tekstowy utworzony został w matlabie(wimage.m):

 

I = imread('lena','jpg');

fid = fopen('image.txt','w+');

[X,Y,Z] = size(I);

fprintf(fid, '%d\n',X);  % lines

fprintf(fid, '%d\n',Y);           % pixels in line

for x = 1:X

   for y = 1:Y

      if I(x,y) < 16

         fprintf(fid, '0%x', double(I(x,y)));

      else

                fprintf(fid, '%x', double(I(x,y)));

                end;    

   end;

   fprintf(fid,'\n');

end;

fclose(fid);

 

Jak widać jest to konwersja jpg na txt.

 

            Tak przetworzone dane z obrazka umożliwiają łatwy dostęp z poziomu VHDL-a. Dane te są przez tb odczytywane i wysyłane na wejście PIN(7:0). Po przejściu przez tor DPCM dane z POUT są zapisywane w formacie tekstowym, który może być zamieniony na format jpg m-plikiem rimage.m uruchomionym w środowisku matlab:

 

 

clear

fid = fopen('imageout.txt','r+');

 

X = fscanf(fid, '%d',1) % lines

Y = fscanf(fid, '%d',1) % pixels in line

 

for x = 1:X

   for y = 1:Y

      I(x,y) = fscanf(fid, '%2x',1);

   end;

end;

I = 255 - I;

imwrite(I,'lenaout.jpg','jpg');

fclose(fid);

 

 

9. Synteza i implementacja.

 

Przed syntezą należy skompilować pliki xilinxcorelib (2 sumatory i jeden układ odejmujący) w formacie EDIF, aby zostały poprawnie dołączone podczas implementacji.

Ekwiwalentna ilość bramek dla projektu wynosi ok. 20 tys., dodtatkowa ilość bramek dla IOB wynosi 2300. Częstotliwość pracy równa jest 33.3 MHz (PCI).

10. Pliki

dpcm.zip

 

Hosted by www.Geocities.ws

1