EasyJPEG. Mikrokontrolerowa biblioteka dekodera JPEG

EasyJPEG. Mikrokontrolerowa biblioteka dekodera JPEG
Pobierz PDF Download icon
Niniejszy artykuł ma za zadanie przybliżenie Czytelnikowi zagadnień związanych z kompresją obrazów w popularnym standardzie JPEG. Prezentuje punkt widzenia programisty, bez zbytniego zagłębiania się w matematyczne meandry. Przedstawiony zostanie także projekt bezpłatnej, uniwersalnej biblioteki dekodującej, stworzonej przez autora w języku C. Dzięki jej małym wymaganiom sprzętowym i prostocie implementacji przez użytkownika końcowego, biblioteka idealnie nadaje się do wykorzystania z popularnymi mikrokontrolerami 32-bitowymi oraz kolorowymi wyświetlaczami TFT.
67ELEKTRONIKA PRAKTYCZNA 5/2010 Mikrokontrolerowa biblioteka dekodera JPEG Dodatkowe materiały na CD i  FTP: ftp://ep.com.pl, user: 15257, pass: 1ajsf046 Dodatkowe informacje: http://www.impulseadventure.com/photo/ http://www.ijg.org/ http://en.wikipedia.org/wiki/Jpeg Dodatkowe materiały na CD i FTP Pliki zakodowane w formacie JPEG (Jo- int Photography Experts Group) są w dzisiej- szych czasach najpopularniejszym i najczę- ściej spotykanym formatem używanym do przechowywania cyfrowych obrazów w po- staci skompresowanej. Kompresja pokrótce opiera się na właściwościach ludzkiego oka, którego wrażliwość spada dla coraz wyż- szych częstotliwości przestrzennych wystę- pujących w  obrazie. Innymi słowy ? czło- wiek słabiej rozróżnia drobne szczegóły ob- razu w obecności dużych detali obrazu, co jest dość oczywiste. Wiedząc o tym fakcie, jesteśmy w stanie przekształcić obraz z re- prezentacji przestrzennej do dwuwymiaro- wej reprezentacji częstotliwościowej (należy pamiętać, że mówimy cały czas o obrazach stałych, a  częstotliwość jest w  tym przy- padku wartością występującą na fizycznej osi w przestrzeni, a nie w czasie!) i usunąć wyższe składowe, znacznie redukując ilość zachowywanej informacji. Efekt końcowy jest praktycznie niezauważalny dla ludzkie- go oka, lecz oczywiście część informacji jest bezpowrotnie tracona. Taki rodzaj kompresji określany jest jako stratna (lossy). Pliki JPEG zapewniają wysoki stopień upakowania da- nych, często ponad 1:100 w  stosunku do surowej bitmapy z  8-bitową reprezentacją RGB. Dostępne rozwiązania Jednym z podstawowych założeń projek- tu było stworzenie otwartego, bezpłatnego kodu z możliwością wykorzystania go do do- wolnych celów, także komercyjnych. Więk- szość rozwiązań programowych dekoderów JPEG jest częścią systemów operacyjnych lub innych projektów, które nie mają otwar- tych źródeł albo te udostępnione są na re- EasyJPEG Mikrokontrolerowa biblioteka dekodera JPEG Niniejszy artykuł ma za zadanie przybliżenie Czytelnikowi zagadnień związanych z  kompresją obrazów w  popularnym standardzie JPEG. Prezentuje punkt widzenia programisty, bez zbytniego zagłębiania się w  matematyczne meandry. Przedstawiony zostanie także projekt bezpłatnej, uniwersalnej biblioteki dekodującej, stworzonej przez autora w  języku C. Dzięki jej małym wymaganiom sprzętowym i  prostocie implementacji przez użytkownika końcowego, biblioteka idealnie nadaje się do wykorzystania z  popularnymi mikrokontrolerami 32-bitowymi oraz kolorowymi wyświetlaczami TFT. strykcyjnych licencjach (GPL). Jedyną, zna- ną autorowi biblioteką niemającą tych ogra- niczeń, jest Independent JPEG Group Library, lecz jej rozmiar i  stopień skomplikowania (obejmujący ponad kilkadziesiąt plików źró- dłowych) może stanowić poważną barierę jej zastosowania w  małych projektach, szcze- gólnie na platformach pozbawionych syste- mu operacyjnego i  procedur dynamicznego alokowania pamięci. Z tego powodu zapadła decyzja o  napisaniu biblioteki od podstaw, z ewentualnym wykorzystaniem fragmentów biblioteki IJG. Dokumentacja standardu Pierwsze idee i  implementacje kompre- sji obrazu wykorzystujące transformaty ko- sinusowe pojawiły się już na przełomie lat 70./80. ubiegłego wieku, lecz dopiero w la- tach 1992?1994 opracowano oficjalne stan- dardy ITU-T T.81 oraz ISO/IEC 10918. Standard ISO jest płatny, natomiast w drugim przypadku sytuacja nie jest jasna. Według ITU standard również nie jest dar- mowy, lecz różne poważne organizacje, takie jak Word Wide Web Consortium publikują go na swoich stronach WWW nieodpłatnie. Ważnym elementem jest specyfikacja JFIF (JPEG File Interchange Format) stworzona przez IJG, która uzupełniła standardy ISO/ ITU w  taki sposób, aby postał przenośny i  uniwersalny format pliku *.jpg. Obraz w czystym standardzie JPEG jest tylko stru- mieniem danych, które mogą być enkapsulo- wane w dowolnym medium, formacie pliku itp. Powszechnie z kompresji JPEG korzysta- ją np. pliki w formacie TIFF. Jedyną książką w  całości poświęco- ną standardowi jest JPEG Still Image Data Compression Standard napisana przez W. B. Pennebakera i  J. L. Mitchella w  1993 roku. Fragmenty książki są dostępne poprzez wi- trynę Google Books. Istnieje duża liczba pu- blikacji i  artykułów poświęconych ogólnie przetwarzaniu sygnałów, w których znajdu- ją się pobieżne opisy działania kompresji JPEG, lecz jest to materiał niewystarczający do zaprojektowania dekodera lub enkodera. Rys. 1. Schemat kodera/dekodera JPEG notatnik konstruktora 68 ELEKTRONIKA PRAKTYCZNA 5/2010 notatnik konstruktora stopnia kompresji polega na skalowaniu całej macierzy kwantyzacji poprzez odpo- wiedni współczynnik. Ostatnim etapem tworzenia pliku JPEG jest kodowanie kodem Huffmana danych wynikowych z  transformat dla wszystkich bloków 8×8 w  obrazie. Dane szeregowane są wstępnie w tzw. zygzaku widocznym na rys.  5. Taki układ został wybrany ekspery- mentalnie i zapewnia względnie największe skupienie danych niezerowych na początku tablicy współczynników AC, podczas gdy wyższe składowe częstotliwościowe, zazwy- czaj redukowane w  procesie kwantyzacji, trafiają na koniec. Następnie dla każdego kolejnego, nieze- rowego współczynnika w zygzaku są tworzo- ne dwie 4-bitowe wartości RRRR oraz SSSS poprzedzające go w  strumieniu danych. Za pomocą RRRR deklarowana jest liczba współczynników zerowych występujących przed nim, a SSSS deklaruje przedział jego wartości, czyli liczbę bitów następujących po symbolu RRRRSSSS. Wartość współczyn- ników nie jest zapisywana za pomocą typo- wego kodu U2. Najstarszy bit definiuje, czy wartość jest dodatnia (1), czy ujemna (0), miarowych funkcji wynikowych dla każde- go z 64 współczynników transformaty 8×8. Współczynnik z  lewego górnego rogu (0,0) nazywany jest współczynnikiem stałym DC, a pozostałe 63 ? współczynnikami zmienny- mi AC. Każdy blok na rysunku reprezentuje obraz 8×8 powstały z odwrotnej transforma- ty macierzy, w  której tylko odpowiadający mu współczynnik nie był zerowy. Ostatecz- nie, sumując ze sobą takie bloki o  ?nasile- niu? zależnym od wartości współczynników, uzyskujemy rekonstrukcję obrazu. Transfor- mata DCT ma właściwość agregowania naj- istotniejszych (z  psychowizualnego punktu widzenia) informacji obrazu w lewej górnej ćwiartce macierzy wynikowej. Następnym elementem procesu kom- presji jest tzw. kwantyzacja. Polega ona na zredukowaniu w kontrolowany i regulowa- ny sposób liczby składowych wynikowych DCT, które będą przechowywane w  pli- ku. Odbywa się to w  wyniku podzielenia współczynników wynikowych DCT przez wartości z  macierzy kwanty- zacji. Ponieważ używana jest arytmetyka stałoprzecinkowa o zerowej liczby bitów po prze- cinku, część współczynników zostaje wyzerowana. W dekode- rze wszystkie wartości zostają z  powrotem pomnożone przez tę samą macierz (przechowy- waną w  nagłówku strumienia), lecz ilość danych wejściowych jest już znacznie mniejsza. Na rys.  4 pokazano przykład tego procesu. Macierze kwantyza- cji opracowane na podstawie badań sposobu widzenia czło- wieka zostały zaproponowa- ne w  standardzie, lecz kodery mogą używać praktycznie do- wolnych wartości. Regulacja Pomocnym źródłem informacji są artykuły umieszczone na stronie http://www.impul- seadventure.com/photo/. Ich autor stworzył również specjalny program o nazwie JPEG- snoop, pozwalający na dokładne analizowa- nie zawartości plików JPEG. Podstawy działania Na rys. 1 przedstawiono ogólny schemat kodera oraz dekodera JPEG. Ich najistotniej- szymi elementami są: dyskretna transfor- mata kosinusowa typu II (DCT-II) oraz jej odwrotność IDCT (DCT-III). Są one podobne do dyskretnej transformaty Fouriera w  tym sensie, że przekształcają sygnał z  domeny przestrzennej do domeny częstotliwości i na odwrót, lecz operują tylko na liczbach rzeczywistych. JPEG używa transformat dwuwymiarowych na blokach-fragmentach obrazu 8×8 pikseli, co jest rozsądnie niską wartością pod względem złożoności oblicze- niowej i  zapotrzebowania na pamięć ope- racyjną. Jednak przy tak małym rozmiarze i wysokim stopniu kompresji często na ob- razie widoczne są ostre przejścia barw i ja- sności pomiędzy sąsiednimi blokami. Efekt ten można zaobserwować na rys.  2. Trans- formata kosinusowa, jak większość tego typu transformat, wykorzystuje przedstawienie sygnału jako złożenie wielu funkcji trygo- nometrycznych o różnych częstotliwościach (w  tym przypadku kosinusoid). Na rys.  3 pokazano wizualne przedstawienie dwuwy- Rys. 2. Różne wielkości pikseli zależnie od stopnia kompresji Rys. 3. Dwuwymiarowe funkcje wynikowe Rys. 4. Operacje na macierzach kwantyzacji Rys. 5. 69ELEKTRONIKA PRAKTYCZNA 5/2010 Mikrokontrolerowa biblioteka dekodera JPEG 12-bitowych próbkach obrazu oraz Baseline DCT używający próbek 8-bitowych. Exten- ded DCT ma zastosowanie tylko i  wyłącz- nie w aplikacjach specjalnych, naukowych, przemysłowych ? jest praktycznie niespo- tykany w  zastosowaniach konsumenckich. Otaczające nas z każdej strony obrazy JPEG są praktycznie w  99 przypadkach na 100 skompresowane w Baseline DCT ? generują je wszystkie popularne narzędzia kompute- rowe, edytory graficzne, przeglądarki plików, konwertery formatów oraz popularne apara- ty cyfrowe, telefony komórkowe itp. Poza powyższym istnieją w standardzie jeszcze dwa sposoby podziału kompresji. Za- miast kodowania Huffmana może zostać uży- te kodowanie arytmetyczne. Mimo lepszych o ok. 10% wyników nie jest to rozwiązanie spotykane w praktyce. Powodem jest większe zapotrzebowanie na moc obliczeniową oraz dotyczące go obwarowania patentowe. Jesz- cze inny podział pozwala na zapisywanie współczynników AC w  sposób różnicowy, tak jak w przypadku DC. Jest to rozwiązanie całkowicie martwe, ze względu na swoją zni- komą efektywność. Z powyższych powodów projekt biblioteki skupia się tylko i wyłącz- nie na podstawowej odmianie JPEG: Baseline DCT z kodowaniem Huffmana i bez zapisu różnicowego. Przestrzeń kolorów Oryginalny standard JPEG nie narzuca sposobu zapisu obrazów kolorowych. Po- zwala on jedynie na zdefiniowanie i przesy- łanie dowolnej liczby składowych. Rozwią- zanie to jest oczywiście bardzo elastyczne i pozwala na używanie dowolnej przestrzeni barw czy też wygodne zastosowanie w apli- kacjach specjalistycznych ? jesteśmy np. w  stanie wyobrazić sobie specjalną kamerę mającą cztery zmienne filtry na określone długości fali, z  których chcemy uzyskać, skompresować i przesłać 4 składowe. W tym przypadku zastosowanie jednego ze standar- dowych profili kolorów spowoduje utratę lub przekłamanie części informacji. Istniała jednak potrzeba stworzenia formatu pliku ? pojemnika dla standardu JPEG, który byłby traktowany w ten sam sposób przez wszyst- kie kodery oraz dekodery na wszystkich platformach sprzętowych i  programowych. Standaryzację wprowadziła propozycja IJG ? format JFIF. Poza dodatkowymi nagłówkami zawierającymi takie informacje, jak rozdziel- czość DPI czy miniaturka obrazu zapisana w  postaci bitmapy, format ten wprowadza rzecz najistotniejszą ? ustandaryzowaną przestrzeń barw oraz zdefiniowaną kolej- ność składowych. Przestrzenią tą jest YCbCr, używana także powszechnie w analogowym standardzie telewizyjnym PAL. Warto wspo- mnieć, że istnieją profesjonalne aplikacje, w których niezwykle istotne jest zachowanie obrazu w niezmienionej formie RGB. Jednak rzanego obrazu. Do kodów krótkich przypi- sywane są wartości występujące najczęściej, a do kodów najdłuższych ? najrzadsze. Kody Huffmana generowane są w taki sposób, aby dekoder wczytujący kolejne bity ze strumie- nia był w stanie rozróżnić, czy wczytane n bitów jest już poprawnym kodem, czy należy wczytać jeszcze jeden. Przykładową tablicę kodów dla współczynników DC można zo- baczyć w tab. 2. Tablice liczby symboli dla danej długości kodu oraz listy ich wartości (symboli, nie kodów ? kody musimy wygene- rować samodzielnie w  dekoderze!), podob- nie jak tablice kwantyzacji są zawarte w na- główku strumienia danych. Warto zauważyć, że kodek JPEG nie może działać ?w  locie? i w celu wykonania statystyki częstości wy- stępowanie symboli cały obraz musi zostać przetworzony do postaci pośredniej. Odmiany JPEG Wyżej opisane ogólne podstawy doty- czą tylko jednego z  możliwych wariantów tworzenia plików JPEG ? tzw. Baseline DCT. Standard definiuje trzy możliwe sposoby kompresji danych: Sequential DCT, Progres- sive DCT oraz Lossless. Jak nazwa wskazuje, trzeci rodzaj jest kompresją bezstratną, która pomija transfor- matę DCT oraz kwantyzację. Jej efektywność jest niewielka i rzadko stosowana w prakty- ce. Progressive DCT jest rodzajem kompre- sji, w którym przesyłane są naraz komplety współczynników dla wszystkich bloków w  obrazie. Pozwala to na wyświetlenie od razu całej klatki, a  następnie wyostrzanie jej i dodawanie kolejnych szczegółów, wraz z napływającymi współczynnikami dla coraz wyższych częstotliwości. Format ten miał rację bytu w czasach bardzo wolnych łączy teleinformatycznych, ponieważ pozwalał na natychmiastowe zaprezentowanie ogólnej zawartości obrazu, podczas gdy dane były ciągle transmitowane. Dziś tę odmianę wy- korzystuje się tylko w bardzo specyficznych aplikacjach. Sequential DCT przesyła kom- pletne zestawy współczynników do kolej- nych bloków, w kierunku od lewej do prawej, a następnie od góry w dół. Typ ten ma dwie odmiany: Extended DCT, który operuje na a kolejne bity ustalają wartość w przedziale odpowiednim dla danej długości. Istnieje odpowiednia kombinacja, tj. RRRR=0 oraz SSSS=0, sygnalizująca dekoderowi, iż był to ostatni niezerowy współczynnik w  tym bloku (zakłada się, że wszystkie współczyn- niki zostały wstępnie wyzerowane). Drugą kombinacją specjalną jest RRRR=15 oraz SSSS=0. Oznacza ona przeskoczenie peł- nych 16 zer. Współczynnik DC jest kodowany w tro- chę inny sposób. Po pierwsze, jego wartość jest poprzedzona tylko jej długością bitową SSSS. Po drugie, w kolejnych blokach zapi- sywana jest tylko różnica wartości w stosun- ku do ostatniego przetwarzanego bloku. Taka technika pozwala na znaczne zredukowanie liczby danych w przypadku obrazów mają- cych duże płaszczyzny w  jednolitym kolo- rze. W tab. 1 pokazano zależność przedziału wartości od jej długości bitowej SSSS dla współczynników AC i różnic DC. Po tych operacjach dość efektywnie skompresowane zostały zerowe współczyn- niki, lecz narzut danych wywołany poprzez obecność symboli RRRRSSSS o stałej, 8-bi- towej długości byłby nie do zaakceptowania. Z  pomocą przychodzi kodowanie Huffma- na (kodowane są nim tylko symbole RRR- RSSSS, a  nie same wartości współczynni- ków!). Ogólna zasada polega na stworzeniu słownika kodów o zmiennej długości (od 1 do 16 bitów) i  przypisaniu im wszystkich możliwych symboli RRRRSSSS (lub SSSS w przypadku DC) dla konkretnego, przetwa- Tab. 1. Zależność parametrów AC i DC od długości bitowej SSSS SSSS różnica DC współczynnik AC 0 0 ? 1 ?1,1 ?1,1 2 ?3:?2,2:3 ?3:?2,2:3 3 ?7:?4,4:7 ?7:?4,4:7 4 ?15:?8,8:15 ?15:?8,8:15 5 ?31:?16,16:31 ?31:?16,16:31 6 ?63:?32,32:63 ?63:?32,32:63 7 ?127:?64,64:127 ?127:?64,64:127 8 ?255:?128,128:255 ?255:?128,128:255 9 ?511:?256,256:511 ?511:?256,256:511 10 ?1023:?512,512:1023 ?1023:?512,512:1023 11 ?2047:?1024,1024:2047 ? Tab. 2. Tablica kodów współczynnika DC Długość Symbol Kod 2 0x00 00 3 0x01 010 3 0x02 011 3 0x03 100 3 0x04 101 3 0x05 110 4 0x06 1110 5 0x07 11110 6 0x08 111110 7 0x09 1111110 8 0x0A 11111110 9 0x0B 111111110 70 ELEKTRONIKA PRAKTYCZNA 5/2010 notatnik konstruktora Nagłówki danych Format JPEG pierwotnie zaprojektowano pod kątem przesyłania serii stałych obrazów przez media strumieniowe, takie jak łącza telefoniczne czy satelitarne. JPEG pozwala na jednorazowe przesłanie najważniejszych nagłówków z  informacjami o  strumieniu, a następnie ciągłą transmisję dowolnej licz- by obrazów z  uwzględnieniem możliwości ponownego zsynchronizowania się w  przy- padku wystąpienia błędów transmisji. Inte- resujący nas format plików JFIF zakłada, że w strumieniu występuje zawsze tylko poje- dyncza klatka obrazu. W  standardzie JPEG nagłówki nazywane są markerami lub znacz- nikami. Każdy marker składa się z  dwóch bajtów: 0xFF oraz przypisanego mu kodu. Po wszystkich rodzajach markerów (poza SOI, EOI i RSTn) występują dwa bajty precyzujące ilość zawartych w nich danych (z uwzględ- nieniem samych siebie, ale bez markera). Na rys. 7 pokazano układ markerów w typowym pliku JFIF. Dokument standardu JPEG bardzo szczegółowo i dogłębnie opisuje ich format, znaczenie i wartości kodów, dlatego poprze- staniemy tutaj tylko na ich pobieżnym opisie (dotyczy on tylko omawianej cały czas od- miany Baseline DCT!). SOI (Start Of Image) ? prosty marker, niezawierający dodatkowych danych, za- wsze musi znajdować się na początku pliku. APPn, n=0...16 (Application Marker) ? marker zawierający dane rozszerzające dla danej aplikacji. APP0 jest wykorzystywany przez format JFIF, lecz poza jego zidentyfi- kowaniem nie ma potrzeby dekodowania go internetowych. Plik z  subsamplinegiem 8×16 może powstać w  wyniku operacji bezstratnego obracania obrazu o  90° (bez pośredniej kompresji i dekompresji). Warto zauważyć, że często użytkownik urządzenia lub programu nie ma wpływu na ten para- metr. Projekt biblioteki przewiduje poprawną obsługę wszystkich wyżej wymienionych odmian. Istnieją, co prawda, wersje o współ- czynnikach proporcji Y:C nawet 4:1, lecz są praktycznie niespotykane na co dzień, dla- tego ich implementacja wydaje się zbytecz- na. Podobnie wygląda sytuacja w przypadku odmiany mającej tylko składową Y do prze- chowywania obrazów w skali odcieni szaro- ści. Specyfikacja JFIF poza zdefiniowaniem przestrzeni barw podaje także wzory po- zwalające na ujednoliconą konwersję YCbCr RGB, będące prostymi transformacjami liniowymi. Należy jeszcze wspomnieć o  sytuacji, w której wyzmiary obrazu poddanego kom- presji nie są wielokrotnością rozmiaru poje- dynczego MCU. W  takim przypadku obraz musi zostać rozszerzony do właściwych wymiarów, a  piksele znajdujące się poza jego prawą i  dolną krawędzią zostają wy- pełnione wartościami z widocznej krawędzi obrazu. Taka technika zapobiega powstawa- niu widocznych artefaktów, które nieodłącz- nie towarzyszą ostrym przejściom kolorów w obrazach JPEG. Dekoder musi obciąć nad- miarowe dane ze zdekodowanych MCU, tak aby rozmiar obrazu odpowiadał zdeklarowa- nemu w nagłówku strumienia. standardowe dekodery nie potrafią popraw- nie wyświetlić tak stworzonych plików. Za- stosowanie przestrzeni YCbCr jest korzystne z  punktu widzenia właściwości ludzkiego oka. Ma ono większą zdolność rozdzielczą pod względem różnic jasności sąsiednich punktów niż różnic w ich kolorach. Wyod- rębniając osobne płaszczyzny obrazu dla Y ? luminancji, oraz Cb i  Cr ? chrominancji, możemy zmniejszyć rozdzielczość tych dru- gich nawet 2...4-krotnie przed wykonaniem kompresji. Po rozciągnięciu w  dekoderze składowych Cr i Cb z powrotem do docelo- wego rozmiaru obrazu, różnica dla ludzkiego oka jest praktycznie niezauważalna, przy du- żej redukcji ilości danych. W  przypadku JPEG proces ten jest po- tocznie zwany subsamplingiem koloru. Na rys. 6 pokazano trzy najczęściej występują- ce odmiany oraz sytuację bez subsamplin- gu. Rysunek przedstawia też sposób usze- regowania skompresowany bloków 8×8 dla każdej ze składowych w strumieniu da- nych. Komplet bloków Y oraz Cr i Cb stano- wi tzw. MCU (Minimal Coded Unit). Jest to minimalna porcja danych, która pozwala na odtworzenie fragmentu obrazu z  uwzględ- nieniem rekonstrukcji koloru. Na poziomie pojedynczych MCU odbywa się wcześniej wspomniane rozciągnie składowych Cr i Cb. Przykładowo, dla subsamplingu 4:2:0 efektem wynikowym jest blok 16×16 pikse- li, gdzie każde 4 tworzące kwadrat piksele mogą mieć różną wartość luminancji, lecz ich chrominancja pozostaje taka sama. Pli- ki pozbawione subsamplingu generowane są głównie przez narzędzia do edycji i kon- wersji grafiki wysokiej jakości. Subsampling 16×8 jest najczęściej używany w koderach JPEG aparatów fotograficznych, a  16×16 spotyka się zazwyczaj w  plikach o  niższej jakości i małym rozmiarze, np. na stronach Rys. 6. Sposób kompozycji barw w formacie JPEG Rys. 7. Układ markerów w typowym pliku JPEG 71ELEKTRONIKA PRAKTYCZNA 5/2010 Mikrokontrolerowa biblioteka dekodera JPEG Wykorzystany został fakt, że format JPEG pierwotnie był przeznaczony dla me- diów strumieniowych. Biblioteka nie wyma- ga wczytania całego pliku wejściowego do pamięci ? przekazywany jest do niej tylko wskaźnik na dowolną funkcję zdeklarowaną przez użytkownika, pobierającą kolejny bajt strumienia. Takie rozwiązanie pozwala na dekodowanie w locie plików umieszczonych na nośnikach podzielonych na bloki, takich jak karty pamięci. Przykładowa funkcja w ra- zie wysycenia bufora jest odpowiedzialna za wczytanie następnej porcji, np. 512-baj- towego sektora. Jest to operacja całkowicie przeźroczysta z  punktu widzenia dekodera i zapewnia dużą uniwersalność. Biblioteka ma własne, zdefiniowane w pliku nagłówkowym zestawy typów pro- stych oraz wyliczeniowych. Wszystkie typy w  bibliotece poprzedzone są prefiksem ej_ np. ej_error_t, ej_s8, ej_u32 itp. Dla nietypo- wych kompilatorów i architektur może zajść konieczność modyfikacji typów prostych, tak aby odpowiadały założonym rozmiarom bi- towym. Dodatkowo zdefiniowany jest prefiks INLINE, który może mieć różną postać dla różnych kompilatorów (domyślnie podany dla GCC). Trzonem biblioteki jest struktura ej_info zawierająca wszystkie informacje o  aktual- nie przetwarzanym pliku. Dokładny opis pól struktury znajduje się w pliku nagłówkowym. Obecna wersja ma jedną globalną strukturę, z której korzystają wszystkie funkcje. Wyni- ka to z założenia, że użytkownik w prostych aplikacjach nie będzie chciał dekodować więcej niż jednego pliku jednocześnie. Pod- stawową rzeczą, którą należy wykonać przed rozpoczęciem korzystania z  biblioteki, jest ustawienie w strukturze wskaźnika *ej_info. get_byte na wyżej wspomnianą funkcję po- bierającą bajty danych. Użytkownik jest sam odpowiedzialny za ustawienie pozycji w swoim medium na początek pliku, który chce przetwarzać. Struktura ma także pole ej_info.error zawierające kod ostatniego na- potkanego błędu, a lista możliwych błędów jest zdefiniowana w  typie wyliczeniowym ej_error_t. Rozpoczęcie przetwarzania pliku nastę- puje poprzez wywołanie funkcji ej_info(). Interpretowane są wszystkie markery wy- stępujące przed strumieniem zakodowanych danych, a w polach struktury kompletowane są wszelkie potrzebne informacje. W  razie wystąpienia błędu funkcja zwróci wartość ?1, a w przypadku powodzenia 0. W tym mo- mencie użytkownik może odczytać ze struk- tury takie informacje, jak rozmiar całego obrazu (ej_info.ver, ej_info.hor) oraz rozmiar pojedynczego MCU (ej_info.ver_mcu, ej_info. hor_mcu). Właściwe dekodowanie następuje dopie- ro po wywołaniu funkcji ej_decode(ej_mo- de_t mode, ej_u?? *bmp). Funkcja przyjmuje Należy zaznaczyć, że wszystkie dane w  formacie JPEG zapisywane są w  postaci Big Endian, a kolejność występowania mar- kerów nie jest zdefiniowana. Istotne jest je- dynie to, aby przed rozpoczęciem skanu SOS pojawiły się wszystkie potrzebne informacje. Warto również wspomnieć o  jeszcze jednym markerze zdefiniowanym w  stan- dardzie ? DNL. Ma on za zadanie zdefinio- wanie liczby linii w obrazie, gdy wartość ta jest równa 0 w markerze SOF. Znacznik DNL powinien wystąpić zaraz po zakończeniu transmisji wszystkich bloków pierwszego skanu. Rozwiązanie to jest praktycznie mar- twe w przypadku plików. Standard pozwala także na wystąpienie dalszych skanów (mar- kerów SOS wraz z  zakodowanymi blokami obrazu) zamiast markera EOI, lecz jest to nie- spotykane w przypadku Baseline DCT i JFIF. Jedynie wcześniej opisana progresywna od- miana JPEG przesyła w  ten sposób kolejne zestawy współczynników dla całego obrazu. Zakodowane dane podlegają kilku regu- łom. Ponieważ może w nich wystąpić war- tość 0xFF, która jest zarezerwowana tylko dla znaczników, zastosowano technikę tzw. byte stuffingu. Po każdej wygenerowanej wartości 0xFF w  ciągu danych umieszczony zostaje dodatkowy bajt 0x00 (zasada ta nie dotyczy danych umieszczonych w  markerach!). De- koder natrafiając na 0xFF sprawdza wartość następnego bajtu i jeśli jest to 0x00, to zosta- je on zignorowany. Może to być także jeden ze znaczników RST, lecz w  każdym innym przypadku będzie to oznaczało błąd. Ponie- waż kodowanie Huffmana operuje na kodach o zmiennej długości, cały strumień danych jest interpretowany w dekoderze bit po bicie, zawsze z  najstarszym bitem wczytywanym jako pierwszy, bez zaokrąglania do pełnych bajtów. Zaokrąglenie występuje tylko i  wy- łącznie w przypadku wystąpienia markerów RSTn ? nawet jeśli w bajcie poprzedzającym marker pozostały niewczytane bity, muszą one zostać zignorowane. Biblioteka Główny nacisk w projekcie biblioteki de- kodującej został położony na prostotę, ogra- niczenie ilości kodu, zapotrzebowania na pa- mięć RAM oraz względnie dużą wydajność. Projekt został stworzony w  czystym języku ANSI C, bez wykorzystania jakichkolwiek funkcji bibliotecznych. Dzięki temu jest on całkowicie przenośny między platformami sprzętowymi oraz różnymi kompilatorami. Jednak należy zaznaczyć, że testy wykonane zostały tylko na kompilatorach Borland Tur- bo C++ oraz GCC. Inne bardziej egzotyczne środowiska mogą stwarzać potencjalnie pew- ne problemy związane np. z przesuwaniem bitowym zmiennych typu signed lub mno- żeniem liczb. Biblioteka składa się z  pliku nagłówkowego easyjpeg.h oraz właściwego kodu zawartego w easyjpeg.c. w prostych aplikacjach. APP1-2 mogą zawie- rać dane w popularnym w aparatach cyfro- wych formacie EXIF. DQT (Define Quantization Table) ? mar- ker definiujący zawartość tablic kwantyzacji. Dekoder musi mieć cztery sloty, w  których mogą być umieszczone cztery różne tablice. Jeden marker DQT może zawierać od 1 do 4 tablic, mogą one również mieć postać osob- nych markerów. W  praktyce kodery tworzą zazwyczaj tylko dwie tablice: jedną dla skła- dowej luminancji i jedną wspólną dla skła- dowych chrominancji. SOFn (Start Of Frame) ? marker defi- niujący parametry tzw. ramki. Dla Baseline DCT jest to marker SOF0, pozostałe definiują omówione wcześniej inne odmiany kompre- sji. Zawiera liczbę bitów na próbkę, rozmia- ry obrazu w  pikselach oraz definicję skła- dowych. JFIF narzuca tutaj trzy składowe o następujących numerach i kolejności: Y(1), Cb(2), Cr(3). Dla każdej składowej precyzo- wane są współczynniki subsamplingu oraz numer używanej tablicy kwantyzacji. DHT (Define Huffman Table) ? marker definiujący tablice pomocnicze do dekodo- wania Huffmana. Dekoder musi mieć w su- mie cztery sloty, dwa dla tablic kodów DC i dwa dla tablic kodów AC. Tak jak w przy- padku DQT, znacznik może zawierać od 1 do 4 tablic, mogą one także mieć postać osob- nych markerów. DRI (Define Restart Interval) ? marker definiujący liczbę MCU, co którą wymagana jest obecność znacznika RSTn w strumieniu danych. Technika ta pozwala na ponow- ną synchronizację dekodera w  przypadku, w którym dane w pliku są uszkodzone. Jest ona dość rzadko spotykana, jednak istnie- je na rynku przynajmniej jeden popularny program do edycji grafiki korzystający z niej. Większość plików jest go pozbawiona i przyj- muje się, że znaczniki RSTn nie mogą poja- wić się w strumieniu. SOS (Start Of Scan) ? marker rozpo- czynający strumień zakodowanych danych. Zawiera definicję liczby zawartych w  nim składowych, informację o  kolejności ich występowania (posługując się numerami przyporządkowanymi w  SOF) oraz infor- mację o numerach przyporządkowanych im tablic Huffmana dla składników DC i  AC. Bezpośrednio po markerze SOS następuje ciąg zakodowanych danych obrazu ? od tego momentu, aż do czasu przesłania wszystkich bloków poza RSTn nie może już pojawić się żaden inny marker. RSTn, n=0...7 (Reset) ? marker pojawia- jący się w strumieniu zakodowanych danych w  ściśle zdefiniowanych przez DRI odstę- pach. Każdy kolejny marker musi mieć nu- mer modulo 8 o jeden większy od poprzed- niego. EOI (End Of Image) ? marker występują- cy zawsze na końcu pliku. 72 ELEKTRONIKA PRAKTYCZNA 5/2010 notatnik konstruktora funkcji, aby uzyskać czarne wypełnienie tak jak w tab. 3. Nadmiarowe wywołania funk- cji, gdy dekodowanie zostało zakończone, są ignorowane, a  zawartość przekazywanej tablicy pozostaje niezmieniona. W  trybach pierwszym i  drugim postęp dekodowania można monitorować za pomocą pól ej_info. ver_pos oraz ej_info.hor_pos. Zawierają one współrzędne lewego górnego piksela MCU, który będzie dekodowany w następnym wy- wołaniu ej_decode(?). Biblioteka ma możliwość konfiguracji formatu generowanej bitmapy. Służą do tego dwie (domyślnie wyłączone znakiem ko- mentarza) definicje umieszczone w  plikach nagłówkowych BMP_16BIT oraz BMP_BGR. Pierwsza z  nich definiuje, czy bitmapa bę- dzie miała 16-bitowy kolor piksela w forma- cie 5:6:5 zamiast 32-bitego w formacie 8:8:8. Zależy od niej także typ wskaźnika (ej_u16* lub ej_u32*), który jest przekazywany do funkcji ej_decode(?). Druga definicja po- woduje odwrócenie kolejności składowych kolorów z RGB na BGR. Rys. 8 przedstawia wizualizację komórek tablicy (pikseli) dla wszystkich kombinacji ustawień. Format 24-bitowy (3 bajty na piksel) został celowo pominięty, ze względu na małą wydajność i  niepraktyczność przetwarzania tego typu danych na architekturach 32-bitowych. Dane 16-bitowe 5:6:5 mogą być bardzo wy- godne w stosowaniu z małymi wyświetlacza- mi TFT, których kontrolery zazwyczaj przyj- mują bitmapy właśnie w takim formacie. Szczegóły implementacji, testy wydajności Podstawowy element biblioteki, czyli transformata IDCT, został opracowany na podstawie jednej z implementacji stałoprze- cinkowych dostępnych w  bibliotece IJG. Opiera się ona na popularnym algorytmie AAN (nazwa pochodząca od nazwisk au- torów: Arai, Agui i Nakajima). Jego główną zaletą jest fakt, że do wykonania jednowy- miarowej, 8-punktowej transformaty po- trzebnych jest tylko pięć mnożeń i  ok. 40 dodawań/odejmowań. Uzyskano to poprzez ?wyprowadzenie? z  transformaty prawie wszystkich współczynników stałych i zinte- growanie ich z macierzą kwantyzacji, przez którą i  tak muszą zostać wymnożone dane wejściowe. W celu wykonania transformaty dwuwymiarowej przeprowadzane jest zło- żenie transformat jednowymiarowych ? naj- pierw przetwarzane są kolumny, a następnie Tab. 3. Dostępne tryby i zachowanie się funkcji Obraz Obraz przed kompresją Rozmiar 44×51 MCU 16×16 Rzeczywisty obraz w pliku JPEG z naniesionym podziałem na MCU Rozmiar 48×64 Tryb dekodowania EJ_SINGLE_MCU EJ_LINE_OF_MCU EJ_ALL_MCU Bitmapa wejściowa 16×16 44×51 44×51 1. wywołanie 2. wywołanie 3. wywołanie 4. wywołanie pamięci RAM, aby zdekodować całą bit- mapę w  jednym przebiegu (przykładowo dla bitmapy 320×240 jest konieczny bu- for o  pojemności ponad 300  kB!). Zamiast tego funkcja pracuje na małych bitmapach o  rozmiarach odpowiadających jednemu MCU (maksymalnie 16×16, co daje już bu- for o  rozmiarze 1  kB). Należy pamiętać, że dekoder nie wie niczego o rozmiarach prze- kazanego mu bufora. Przykładowo dla pliku z MCU 16×8 w każdym wywołaniu zapisa- nych zostanie pierwszych 128 elementów ta- blicy (8 wierszy po 16 elementów). Dla MCU leżących na krawędziach obrazu zdekodo- wane zostaną tylko piksele użyteczne, lecz tablica wyjściowa dalej jest traktowana jako bitmapa o  rozmiarach MCU. Piksele leżące za krawędzią obrazu pozostaną niezmienio- ne, dlatego może zajść konieczność wyze- rowania tablicy przed jej przekazaniem do jako parametry: tryb działania oraz wskaźnik do bitmapy, a  zwraca 0 w  przypadku po- wodzenia lub ?1 w  przypadku wystąpienia błędu. Tab. 3 prezentuje dostępne tryby i za- chowanie się funkcji przy kolejnych wywo- łaniach. Tryby drugi i  trzeci operują na pełnej bitmapie. Funkcji musi zostać przekazany wskaźnik do tablicy zawierającej co najmniej ej_info.ver  *  ej_info.hor elementów. Piksele w  rzędach zapisywane są od lewej do pra- wej, a  kolejne rzędy następują po sobie od góry do dołu. W przypadku obrazów, których rozmiar nie jest wielokrotnością rozmiaru MCU, obcięcie nadmiarowej krawędzi nastę- puje wewnętrznie i jest całkowicie przeźro- czyste dla użytkownika. Tryb drugi różni się od trybu trzeciego tym, że w jednym wywo- łaniu wykonuje dekodowanie tylko jednego rzędu kompletnych MCU. Takie zachowanie pozwala np. na zaimplementowanie paska postępu dekodowania i  nie blokuje perma- nentnie głównego kodu programu. W trybie tym funkcja w  każdym wywołaniu rozpo- czyna zapis danych od tego samego miejsca w tablicy, na którym zakończył się on w po- przednim. Tryb pierwszy jest preferowany w apli- kacjach, które nie mają dostatecznej ilości Rys. 8. Komórki tablicy pikseli 73ELEKTRONIKA PRAKTYCZNA 5/2010 Mikrokontrolerowa biblioteka dekodera JPEG Tab. 4. Przykłady pomiarów czasu dekodowania i wyświetlania obrazów Obraz Rozmiar 640×480 123 KB 640×480 20,5 KB 320×240 17,9 KB 125×183 17,8 KB 2048×1536 883 KB Ustawienie jakości 95/100 50/100 95/100 nieznane, obraz z WWW nieznane, obraz z aparatu fotograficznego Czas inicjalizacji PC: <1 ms ARM: 10 ms PC: <1 ms ARM: 10 ms PC: <1 ms ARM: 10 ms PC: <1 ms ARM: 14 ms PC: <1 ms ARM: 14 ms Czas dekodowania PC: 109 ms ARM: 1777 ms PC: 47 ms ARM: 796 ms PC: 16 ms ARM: 359 ms PC: 7 ms ARM: 116 ms PC: 391 ms ARM: 12839 ms wiersze. W implementacji biblioteki proces wymnażania współczynników transformaty i macierzy kwantyzacji przebiega w funkcji ej_init(), a wynik jest zapisywany bezpośred- nio w polach struktury ej_info.qt[]. Kosztem takiego rozwiązania jest dwukrotnie więk- sza wielkość zajmowanej przez nie pamię- ci, ponieważ wymnożone dane potrzebują co najmniej typu 16-bitowego. Większość spotykanych plików JPEG korzysta tylko z dwóch tablic kwantyzacji i dlatego można ograniczyć liczbę slotów poprzez definicję QT_CNT umieszczoną w  pliku nagłówko- wym. Powoduje to ograniczenie użycia pa- mięci o ok. 260 B. Procedura IDCT wykonuje obliczenia na danych o precyzji 5 bitów po przecinku (precyzja jest zwiększana poprzez odpowiednio mniejsze przesunięcie bitowe po mnożeniu tablicy kwantyzacji). Z  właś- ciwości transformaty wynika zwiększenie precyzji o kolejne 2 bity, dlatego ostateczne wyniki są dzielone poprzez przesunięcie o 7 bitów w prawo. Biblioteka powinna dać się łatwo mody- fikować do nietypowych aplikacji, np. o in- nej przestrzeni kolorów lub nietypowych współczynników subsamplingu. Podstawą jest funkcja decode_unit(), która dekoduje ze strumienia kolejny blok obrazu 8×8 i zwraca go w postaci 64-elementowej tablicy o war- tościach 16-bitowych ze znakiem. Wartości nie mogą być 8-bitowe, ponieważ drobne błędy wynikające z  precyzji obliczeń IDCT nakładają się i  w  efekcie niektóre współ- czynniki wychodzą poza zakres jednego bajtu. Podobne efekty mogą powstać w funk- cji ycc2rgb(?), która dokonuje konwersji przestrzeni kolorów, dlatego konieczne jest przeprowadzenie tzw. saturacji do 8 bitów. Odbywa się ona właśnie w ycc2rgb() i niwe- luje wszystkie skumulowane wyjścia poza zakres. Właściwe składanie obrazu z płasz- czyzn Y Cb i  Cr odbywa się już w  funkcji ej_decode(?). Dla każdego typu subsamplin- gu powstał oddzielny fragment prostszego kodu, niż byłoby to w  przypadku funkcji uniwersalnej. Testy, podsumowanie W celu przetestowania biblioteka zosta- ła wstępnie zaimplementowana w środowi- sku Borland Turbo C++, na komputerze PC z procesorem Intel Core Duo 1,66 GHz. Pro- sta aplikacja konsolowa (załączona do arty- kułu wraz z kodem biblioteki) przyjmuje jako argument wywołania ścieżkę do pliku *.jpg, wyświetla informacje na jego temat, czasy trwania wywołania funkcji ej_init() i  ej_de- code(EJ_ALL_MCU, ?), a następnie generu- je plik bitmapy *.bmp ze zdekodowanym obrazem. Drugi test został przeprowadzony w środowisku GCC 4.3 na procesorze ARM Cortex M3, zaimplementowanym w pewnym urządzeniu z wyświetlaczem TFT 320×240, nad którym pracuje autor. Procesor był tak- towany zegarem 72  MHz. Wyniki testów przedstawiono w tab. 4. Prędkość dekodowa- nia jest mocno zależna nie tylko od rozdziel- czości obrazu, ale także od stopnia jakości (kwantyzacji), z jakim został wygenerowany oraz jego szczegółowości. Różnica prędkości dekodowania między PC a ARM mieści się w granicach od 15 do 30 razy, co względnie odpowiada rzeczywistej różnicy częstotliwo- ści zegarów obu procesorów. W  przypadku kompilacji GCC z  opty- malizacją ? O2 kod biblioteki zajmował ok. 6,5 kB, a zapotrzebowanie na pamięć RAM wyniosło ok. 1,5  kB pamięci zajmowanej wprost (struktura ej_info) oraz ok. 1 kB pa- mięci zajmowanej lokalnie poprzez zmienne i  tablice umieszczane na stosie (nie można o tym zapominać!). Kod źródłowy to ok. 800 linii programu oraz 200 linii pliku nagłówko- wego (wliczając komentarze). Projekt biblioteki wydaje się być udany pod względem funkcjonalnym, choć można mieć zastrzeżenia co do jej wydajności. Nie potrzeba specjalnych pomiarów, aby zauwa- żyć, że dekodowanie tych samych obrazów w niektórych przeglądarkach obrazów na PC trwa krócej niż wywołanie programu demon- stracyjnego. Wynika to zapewne z wykorzy- stania rozszerzeń MMX i silnej optymalizacji kodu pod procesory x86. Biblioteka na pewno stanowi dobrą bazę do wykonania w przyszłości podobnej opty- malizacji np. pod ARM Cortex M3 bądź pro- cesor DSP. Przytoczone w artykule informa- cje powinny ułatwić to zadanie bardziej za- awansowanym Czytelnikom, a także pozwo- lić na własne modyfikacje i ulepszenia. Jed- nakże autor zaleca, aby przed zagłębieniem się w kod biblioteki zapoznać się, choćby po- bieżnie ze standardem ITU. Bardzo pomocne w zrozumieniu zasad kodowania Huffmana i  generowania tablic pomocniczych mogą być również artykuły z przytoczonej na po- czątku strony internetowej. Kod biblioteki został udostępniony na zasadach prostej licencji w  stylu MIT/X11, co oznacza, że może być wykorzystywany w dowolnych celach zamkniętych lub otwar- tych, także komercyjnych, pod warunkiem umieszczenia treści licencji w  wynikowym kodzie (jeśli jest on otwarty) lub w  doku- mentacji oprogramowania korzystającego z biblioteki. Michał Wysocki mos.wysocki@gmail.com R E K L A M A forum.ep.com.pl
Artykuł ukazał się w
Maj 2010
DO POBRANIA
Pobierz PDF Download icon
Elektronika Praktyczna Plus lipiec - grudzień 2012

Elektronika Praktyczna Plus

Monograficzne wydania specjalne

Elektronik wrzesień 2020

Elektronik

Magazyn elektroniki profesjonalnej

Raspberry Pi 2015

Raspberry Pi

Wykorzystaj wszystkie możliwości wyjątkowego minikomputera

Świat Radio październik 2020

Świat Radio

Magazyn użytkowników eteru

Automatyka Podzespoły Aplikacje wrzesień 2020

Automatyka Podzespoły Aplikacje

Technika i rynek systemów automatyki

Elektronika Praktyczna wrzesień 2020

Elektronika Praktyczna

Międzynarodowy magazyn elektroników konstruktorów

Praktyczny Kurs Elektroniki 2018

Praktyczny Kurs Elektroniki

24 pasjonujące projekty elektroniczne

Elektronika dla Wszystkich wrzesień 2020

Elektronika dla Wszystkich

Interesująca elektronika dla pasjonatów