pobierz 234KB
Transkrypt
pobierz 234KB
Tomasz Władziński Michał Leśniewski Układy Cyfrowe – projekt Korekcja jasności obrazów w 24-bitowym formacie BMP z użyciem funkcji gamma Cel projektu Celem jest zaprojektowanie układu cyfrowego, który po podaniu parametru γ i wysłaniu przez port USB do układu pliku BMP o głębi kolorów 24BPP, skorygował jasność jego kolorów z wykorzystaniem funkcji gamma zgodnie z parametrem, a następnie odesłał do komputera. Wstęp teoretyczny Obrazy i zdjęcia cyfrowe pochodzące z różnych źródeł często posiadają wiele niedoskonałości wynikających z różnych przyczyn – zdjęcia z aparatów wbudowanych w telefony komórkowe i obrazy zeskanowane są często za ciemne lub za jasne, zdjęcia prześwietlone lub zrobione przy nieodpowiednim świetle. W związku z tym wykorzystuje się rozmaite filtry, by skorygować te niedoskonałości. Korekcja jasności obrazów Przykładem typowej operacji na obrazie jest rozjaśnienie lub przyciemnienie kolorów. Najprostszym sposobem jest oczywiście operacja liniowa, czyli każdy kolor rozjaśniony lub przyciemniony w tym samym stopniu. Jeżeli więc jasność koloru określona jest przez liczbę z przedziału <0; 1>, gdzie 0 odpowiada głębokiej czerni, a 1 najjaśniejszej bieli, możemy każdy kolor przesunąć w kierunku bieli lub czerni o pewną stałą wartość. Zasadniczą wadą tej metody jest fakt, że przesuwając o stałą możemy wyjść poza zakres <0; 1>, przez co część kolorów rozróżnionych w obrazie pierwotnym zostanie w obrazie wynikowym utracona – zostanie im przypisana biel lub czerń (czyli odpowiedni kraniec zakresu). Ponadto część wartości z przedziału (na jego początku lub końcu) w wyniku przesunięcia nie zostanie wykorzystana wcale. Lepszym rozwiązaniem jest wykorzystanie funkcji gamma. Zakładając tak, jak wcześniej, że wartość jasności leży w przedziale <0; 1>, możemy zależność nowego stopnia jasności od starego wyrazić wzorem: ly = lx1/γ gdzie: lx – jasność koloru w obrazie pierwotnym, ly – jasność koloru w obrazie po korekcji, γ – parametr funkcji. Metoda ta jest lepsza, gdyż jej zbiór wartości to <0; 1>, więc obraz wynikowy wykorzysta wszystkie dostępne stopnie jasności, a kolory rozróżnialne na obrazie pierwotnym, będą dalej rozróżnione. Mamy więc do czynienia z korekcją jasności oraz dodatkowo kontrastu. Parametr γ występujący we wzorze odpowiada stopniowi rozjaśnienia lub przyciemnienia. Wartości γ < 1 odpowiadają przyciemnianiu, γ > 1 rozjaśnianiu, zaś γ = 1 powoduje uzyskanie na wyjściu obrazu identycznego jak na wejściu. Teoretycznie γ może przyjmować wartości z zakresu (0; +∞), ale w praktyce zazwyczaj sensowne są tylko wartości z zakresu około <0,7; 1,3>. Na wykresie 1 przedstawiono funkcję gamma dla trzech różnych parametrów. Wartości parametrów są celowo dosyć nietypowe (za bardzo odbiegają od 1), aby uwidocznić zmianę kształtu krzywej. Format graficzny BMP Wykres 1: Funkcja gamma dla różnych parametrów. Format pliku, z jakim będzie współpracować program to Windows Bitmap (skrót i rozszerzenie plików to BMP). Jest to jeden z najprostszych formatów grafiki rastrowej, praktycznie nie wykorzystujący kompresji (teoretycznie format umożliwia kompresję run length encoding, ale nie jest ona zazwyczaj wykorzystywana). Format umożliwia zapis z różnymi liczbami bitów na pixel, co wiąże się z liczbą (głębią) kolorów. Dostępne liczby bitów to: — 32 (po 8 bitów na składową czerwoną, błękitną i zieloną, czwarty bajt ignorowany lub interpretowany jako kanał przeźroczystości), — 24 (jak przy 32 bitach, lecz bez ostatniego bajtu), — 16 (6 bitów na czerwień i po 5 bitów na zieleń i błękit), — 8, 4 i 1 (formaty starsze, obecnie praktycznie nieużywane, wykorzystywały paletę kolorów dołączonych do pliku) Układ obsługiwać będzie jedynie pliki 24 bitowe, gdyż są one dziś obok 32 bitowych najpowszechniej używane, pozwalają na wystarczająco dokładne określenie intensywności składowych, intensywności mają te same zakresy (po 8 bitów na każdą składową). Format BMP a jasność W poprzednich częściach była mowa o stopniu jasności, jednak nie została podana metoda obliczenia takiego stopnia. Jasność łatwo obliczyć i podstawić do wzoru dla obrazu monochromatycznego. Dla obrazu kolorowego natomiast, stopień jasności można określić przeliczając składowe modelu RGB na HSL – składowa L odpowiada wówczas jasności. W przypadku korekcji gamma nie musimy jednak tego jednak robić – okazuje się, że wystarczy potraktować każdy z kanałów R, G i B jako pojedynczy obraz monochromatyczny. Należy jednak zwrócić uwagę, że w związku z tym, że format BMP zapisuje składowe R, G i B każdego piksela osobno, każdy na 8 bitach, ich wartości leżą w zakresie <0; 255>, a nie jak wcześniej przyjęliśmy <0; 1>. Musimy więc wziąć to pod uwagę i zmodyfikować wzór. Otrzymamy: ly = 255 (lx/255)1/γ Dzięki temu dziedzina i zbiór wartości funkcji będą równe zbiorowi <0; 255>. Rozwiązanie praktyczne Niestety podane wzory na funkcję są bardzo skomplikowane. W związku z tym obliczanie wartości funkcji przy pomocy płytki byłoby bardzo skomplikowane i prawdopodobnie działałoby dość wolno. W związku z tym musimy ograniczyć się do aproksymowania funkcji gamma. Stablicowanie funkcji gamma Najprostszym sposobem realizacji funkcji jest oczywiście jej stablicowanie. Wówczas otrzymaną tablicę należałoby wgrać do pamięci płytki i zaprogramować układ tak, by odczytywał odpowiednią wartość zgodnie z zadanym parametrem γ i jasnością piksela. Nie jest to jednak możliwe, mamy bowiem do czynienia ze zbyt dużą liczbą punktów dla każdego parametru funkcji gamma (256 wartości po 8 bitów). Ponadto należy pamiętać, że parametr γ może teoretycznie przyjmować wartości ciągłe. W sprzęcie mamy jednak do dyspozycji pamięć o wielkości 2048 bitów. Ograniczenie zbioru wartości parametru γ Rozpatrzmy najpierw parametr γ. Jak wcześniej było wspomniane, parametr ten jest ustawiany na ogół na wartości z zakresu <0,7; 1,30>. Czasem jednak użytkownicy chcą uzyskać nietypowy obraz ustawiając bardzo wysokie lub bardzo małe wartości γ. Należy więc przyjąć pewien kompromisowy zakres. Założony w projekcie zakres to <0,25; 4>. Krańce zbioru zostały dobrane tak, by końcowy był odwrotnością początkowego. Dzięki temu pierwsza i ostatnia krzywa są symetryczne względem prostej y = x. Na rysunku przedstawiono wykres obu krańcowych krzywych: 280 y γ = 0,25 γ=4 y=x 260 240 220 200 180 160 140 120 100 80 60 40 20 x 20 40 60 80 100 120 140 160 180 200 220 240 260 Wykres 2: Pierwsza i ostatnia krzywa możliwa do otrzymania przy założonych parametrach Spośród wszystkich wartości parametru γ leżących w zakresie należy wybrać pewien dyskretny zbiór wartości. Należy podzielić zakres tak, by wartości odpowiadały krzywym równoodległym od siebie. Taki podział uzyskamy wprowadzając: γ[n] = a(n – k/2) gdzie: n – numer parametru, n = 0, 1, 2...k k – liczba krzywych dostępnych w pamięci (parzysta liczba całkowita) a – pewien współczynnik Współczynnik a można obliczyć znając wartość minimalną parametru γ (początek zakresu): a = γmin2/k gdzie: γmin – początek zakresu 260 y Funkcje gamma po kwantyzacji wartości gamma 240 220 200 180 160 140 120 100 80 60 40 20 x 20 40 60 80 100 120 140 160 180 200 220 240 260 Wykres 3: Rozkład krzywych względem siebie dla γmin = 0.25 oraz k = 10 Dowolna ciągła wartość parametru γ podana przez użytkownika może być wówczas przypisana do pewnej wartości n odpowiadającej najbliższemu parametrowi γ z tablicy. Następujący wzór pozwala wyznaczyć odpowiednią wartość n dla danego parametru γ: n = [logaγ + k/2] Należy zaznaczyć, że wszystkie przedstawione obliczenia wykonane zostaną albo przez program komunikujący się z płytką, albo jeszcze w czasie projektowania układu. Układ więc nie będzie musiał wykonać żadnego z podanych obliczeń, otrzyma jedynie liczbę gamma, której przyporządkuje pewną liczbę n (w zależności od zakresu, w którym znajduje się gamma). Będzie ona wykorzystana tylko do obliczenia z którego pola tablicy będą czytane parametry. Ograniczenie zbioru punktów Ograniczając liczbę wartości parametru γ nie rozwiązaliśmy jeszcze problemu z brakiem pamięci. Nawet przy małych wartościach liczby parametrów otrzymujemy zbyt dużo danych do zapisania. Przykładowo dla k = 8, ilość potrzebnych bitów wynosi 8∙256∙8 = 16384, a więc stanowczo za dużo. Okazuje się jednak, że wystarczy znać współrzędne tylko kilku punktów należących do krzywej, by móc dość dobrze ją odwzorować w całości. Wystarczy pomiędzy punktami liniowo przybliżać wartość funkcji. Zwłaszcza dla wartości parametru γ bliskich jedności metoda ta dobrze się sprawdza. y Funkcja Aproksymacja 260 240 220 200 180 160 140 120 100 80 60 40 20 x -20 20 40 60 80 100 120 140 160 180 200 220 240 260 -20 Wykres 4: Aproksymacja liniowa dla γ = 1.32 i liczbie punktów i = 11 Jak widać wykresy praktycznie się nie różnią. Niewielki błąd pojawia się na tylko na początku, dla małych wartości x. Maksymalne odchylenie aproksymacji od funkcji występuje dla x = 5 i wynosi około 3. Następujące wzory pozwalają określić numery punktów, pomiędzy którymi będzie obliczana aproksymacja: p(x) = [x/∆]↓ (zaokrąglenie w dół) n(x) = p(x) + 1 Funkcja Stablicowane punkty Aktualny punkt ∆ gdzie: ∆ – odstęp pomiędzy punktami, ∆ = 256 / i i – liczba stablicowanych punktów 5 n(x) = 4 Kolejny wzór pozwala wyznaczyć jaką część drogi między punktami p(x) i n(x) między punktem odpowiada liczbie x: i(x) = x/∆ - p(x) p(x) = 3 ∆ i(x) x 2 Aproksymowana wartość funkcji będzie mieć wartość następującą: v(x) = tab[n(x)] ∙ (1 - i(x)) + tab[n(x)] ∙ i(x) gdzie: tab[k] – wartość odpowiadająca k-temu punktowi odczytanemu z tablicy Wzór jest rodzajem średniej ważonej wartości funkcji w 2 stablicowanych punktach, przy czym wagom odpowiadają odległości od nich. Warto zauważyć, że tablica w pamięci nie musi mieć wprowadzonych wartości dla pierwszego i ostatniego punktu, ponieważ dla każdej krzywej wartość ta jest taka sama – pierwszy punkt jest w zerze, ostatni w 255 Ostatecznie założone parametry Po wprowadzeniu powyższych uproszczeń możemy zdecydować się na następujące parametry: ● Zakres regulacji parametru γ: <0,25; 4> ● Liczba krzywych stablicowanych: 16 ● Liczba punktów stablicowanych dla każdej krzywej: 17 Takiemu dobór parametrów okazuje się optymalny. Dzięki 17 punktom dla każdej krzywej otrzymamy 16 przedziałów, wówczas ∆ = 16, co jest bardzo korzystne przy obliczeniach w systemie binarnym. Ponadto dostępna pamięć zostanie wykorzystana optymalnie. Biorąc pod uwagę, że dla każdej krzywej wystarczy zapisać jedynie 15 punktów (bo wartość dla pierwszego i ostatniego nie zmienia się), wykorzystane zostanie dokładnie 16∙15∙8 = 1920 bitów, a więc prawie całość. y Funkcje gamma po kwantyzacji wartości gamma i aproksymacji liniowej 260 240 220 200 180 160 140 120 100 80 60 40 20 x -20 20 40 60 80 100 120 140 160 180 200 220 240 260 -20 Wykres 5: Wykres przedstawia wszystkie możliwe do otrzymania krzywe przy założonych parametrach. Algorytm Dzięki przyjęciu konkretnych założeń, algorytm wyznaczania wartości funkcji można bardzo znacznie uprościć. Liczby i funkcje zdefiniowane wcześniej, zawierające liczne mnożenia i dzielenia, są w większości przypadków równoznaczne z przesunięciami bitowymi bądź iloczynom logicznym. W dalszej części przedstawiono dokładniejszy opis działań koniecznych do wykonania po uproszczeniu. Użyte zmienne i uproszczone funkcje Jak wcześniej wspomniano w praktyce liczba x na wejściu będzie reprezentować jasność jednej z trzech składowych koloru. Dla standardu 24-bitowego każdą składową reprezentuje liczba całkowita z przedziału <0, 255>. Zakładamy więc, że x jest 8-bitową liczbą całkowitą bez znaku. W związku z tym, że przyjęto liczbę punktów w tablicy równą 17, będziemy mieć do czynienia z 16 przedziałami, każdy z nich długości ∆ = 16. W związku z tym funkcja p(x) zwraca po prostu część całkowitą wyniku dzielenia przez 16, co jest bardzo korzystne w systemie binarnym, gdyż odpowiada to przesunięciu bitowemu liczby x w prawo o 4 bity. Można również przyjąć że p(x) reprezentują pierwsze cztery bity liczby x. Liczba p będzie więc reprezentowana przez 4 bity i interpretowana jako liczba całkowita bez znaku. Funkcję i(x) możemy przy natomiast potraktować jak iloczyn logiczny z liczbą 15 (binarnie 00001111). Analogicznie jak przy funkcji p(x), możemy uznać wartość funkcji i(x) jako równą 4 ostatnim bitom liczby x. Należy jednak zaznaczyć, że jest to ułamek. Zmienną i będziemy zatem traktować jako 4-bitową liczbę stałoprzecinkową bez znaku o pozycji przecinka przed jej pierwszym bitem. Tablica wartości funkcji gamma powinna być tablicą bajtów. Indeks tablicy mówi o numerze odczytywanego bajtu. Wartości powinny być zapisane w takiej kolejności, że aby odczytać k-ty punkt przy parametrze n należy odczytać dane z komórki numer 16n + k – 1. Należy pamiętać, że wartości punktu pierwszego (właściwie zerowego) jak i ostatniego nie są czytane z tablicy. Algorytm obliczając adres korzystać może wówczas wykorzystać prostszy wzór: a = n << 4 + k - 1 Ponieważ najwyższy adres jest równy 255, zmienne przechowujące adresy możemy traktować jako 8-bitowe liczby całkowite bez znaku. Wynik interpolacji jest liczbą stałoprzecinkową o przecinku przed 4 bitem od końca. Obliczony zostaje ze wzoru v = w2 ∙ i + w1 ∙ (1 - i) gdzie: w1, w2 – odczytane z tablicy wartości funkcji w najbliższych punktach Aby obciąć to, co po przecinku wystarczy odczytać pierwsze 8 bitów liczby v. Jest to wynik końcowy działania. Podsumowanie zmiennych Nazwa zmiennej Ilość bitów Rodzaj Pozycja przecinka x 8 Bez znaku (liczba całkowita) n 4 Bez znaku (liczba całkowita) p 4 Bez znaku (liczba całkowita) i 5 Bez znaku Po 1. bicie i2 5 Bez znaku Po 1. bicie w1 8 Bez znaku (liczba całkowita) w2 8 Bez znaku (liczba całkowita) v 13 Bez znaku Po 9. bicie Schemat algorytmu Bibliografia http://en.wikipedia.org/wiki/RGB_color_model – Informacje o modelu barw RGB http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html – Specyfikacja formatu BMP http://www.algorytm.org/index.php?option=com_content&task=view&id=136&Itemid=28 – Opis funkcji gamma Inne informacje Do sporządzenia większości wykresów wykorzystano program Graph (http://www.padowan.dk/). Schemat blokowy algorytmu został utworzony programem Structured Flow Chart Editor (http://www.cs.sonoma.edu/~tiawatts/SFC/index.html).