Doc. dr inż. Jacek Jarnicki Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej jacek.jarnicki@pwr.wroc.pl Inżynieria obrazów cyfrowych Ćwiczenie 1 Środowisko MATLAB + Image Processing Toolbox - wprowadzenie Celem ćwiczenia jest uzyskanie elementarnej intuicji dotyczącej obrazu cyfrowego jako zbioru danych zapisanych w pamięci komputera oraz poznanie najprostszych operacji wykonywanych na obrazach cyfrowych. Jako narzędzie wykorzystane zostanie środowisko obliczeń inżynierskich MATLAB z pakietem Image Processing Toolbox. Na wstępie zademonstrowane zostaną proste przykłady ilustrujące możliwości wykorzystania środowiska MATLAB oraz sposób pisania programów z użyciem funkcji dostarczanych przez Image Processing Toolbox. 1. Ogólna charakterystyka systemu MATLAB MATLAB jest środowiskiem programistycznym do wykonywania obliczeń naukowych i inżynierskich. Nazwa programu pochodzi od słów MATrix LABoratory, bowiem na początku swego istnienia MATLAB przeznaczony był głównie do wykonywania obliczeń numerycznych z dziedziny rachunku macierzowego. Kolejne wersje programu uczyniły go narzędziem coraz bardziej uniwersalnym i obecnie jest to rozbudowany system służący do różnego rodzaju obliczań naukowych, inżynierskich oraz symulacji komputerowych, pozwalający na łatwą i wszechstronną prezentację wyników obliczeń w formie graficznej. MATLAB posiada swój własny język programowania. Jest to język wysokiego poziomu o składni zbliżonej do języka C. Można w nim używać pętli, instrukcji warunkowych, funkcji, struktur i pisać programy zorientowane obiektowo. O szczególnej atrakcyjności i popularności MATLABA decydują jednak tak zwane toolboxy, czyli zestawy funkcji napisanych także w języku MATLAB, pozwalające na wykonywanie obliczeń wykorzystujących algorytmy specyficzne dla różnych działów matematyki, techniki i wielu innych dziedzin, od biologii do finansów. Obecnie producent MATLABA firma MathWorks oferuje kilkadziesiąt takich pakietów. W dziedzinie inżynierii obrazów dostępne są obecnie trzy pakiety funkcji: Image Processing Toolbox, Image Aquisition Toolbox i Mapping Toolbox. Pierwszy z nich, najbardziej rozbudowany, zawiera kilkaset funkcji realizujących znane z literatury algorytmy przetwarzanie obrazów oraz różne funkcje pomocnicze przy pomocy, których można budować i badać własne algorytmy działające na obrazach cyfrowych. Drugi pakiet Aquisition Toolbox jest przeznaczony do wspomagania obsługi różnego rodzaju urządzeń do akwizycji obrazów statycznych i ruchomych, czyli kamer, skanerów, mikroskopów podłączonych do komputera klasy PC. Trzeci z pakietów Mapping
Toolbox jest natomiast przewidziany do analizowania i wizualizacji map geograficznych. Na zajęciach laboratoryjnych wykorzystywany będzie w podstawowym zakresie pakiet Image Processing Toolbox. 2. Demonstracja niektórych możliwości systemu System MATLAB + Image Processing Toolbox Na wstępie, aby dać jakieś wyobrażenie o możliwościach MATLABA wspomaganego funkcjami pakietu Image Processing Toolbox, pokazany zostanie prosty przykład. Przykład ma na celu zilustrowanie jak można poprawić jakość niezbyt dobrze naświetlonego zdjęcia. Czynności, jakie trzeba wykonać są następujące: Przygotowanie do pracy i uruchomienie środowiska MATLAB Przed przystąpieniem do pracy dobrze jest utworzyć w dostępnej do zapisu części dysku nowy folder o łatwej do zapamiętania nazwie, w którym przechowywane będą dane i napisane w czasie zajęć programy. Do folderu skopiować następnie rozpakowaną zawartość pliku cwiczenie_1.zip (link do pliku umieszczony jest obok instrukcji). Dwukrotnie kliknąć na ikonę MATLABA (ikona) i poczekać aż nastąpi pełna inicjalizacja środowiska. Może to trwać do kilku do kilkudziesięciu sekund, bowiem zainstalowane w laboratorium oprogramowanie posiada licencję sieciową i uruchomienie programu wymaga komunikacji z serwerem licencji. Po zakończeniu inicjalizacji powinien pojawić się ekran: Linia poleceń Przycisk Browse Rys. 1. Wygląd ekranu konsoli środowiska MATLAB
Następnie posługując się przyciskiem Browse ustawić ścieżkę do utworzonego wcześniej folderu. Środowisko jest gotowe do pracy. Po wpisaniu w linii poleceń (po symbolu >>) jakiegoś polecenia zrozumiałego dla interpretera komend MATLABA i naciśnięciu klawisza Enter nastąpi jego wykonanie. Przeczytanie obrazu, utworzenie tablicy z zapisem obrazu W linii poleceń wpisać: >> I = imread( Lena_1.tif ); i przekazać polecenie do wykonania przez naciśnięcie klawisza Enter. Na ekranie na razie nie pojawi się nic nowego, jednak wykonanie powyższego polecenia spowoduje przeczytanie z pliku Lena_1.tif i zapisanie w pamięci wczytanego obrazu w postaci dwuwymiarowej tablicy o nazwie I (nazwa tablicy oczywiście może być inna). Tablica ta zawiera dane opisujące obraz. Aby dowiedzieć się czegoś więcej o tej tablicy należy wydać kolejne polecenie w postaci: >> whos Na ekranie ukaże się teraz tekst opisujący tablicę I Name Size Bytes Class I 256x256 65536 uint8 array Grand total is 65536 elements using 65536 bytes Interpretacja wyświetlonego komunikatu jest prosta. Tablica I ma rozmiar 256x256 i zawiera dane w postaci liczb całkowitych 8-bitowych bez znaku (uint8), opisujących poszczególne elementy obrazu. Całkowita liczba bajtów zajmowanych przez dane opisujące wczytany obraz wynosi 65536 Utworzenie tablicy z zapisem treści obrazu daje możliwość bezpośredniego dostępu do każdego elementu tablicy, czyli możliwość dostępu do każdego elementu obrazu. Dla przykładu można sprawdzić, jaką liczbą opisany jest element (piksel) o współrzędnych (85, 35), wpisując w linii poleceń: >> I(85,35) Po wykonaniu polecenia na ekranie wyświetlona zostanie liczba 72. Jest to właśnie dana, odpowiadająca pikselowi o współrzędnych (85,35) (w lewym górnym rogu obrazu znajduje się piksel o współrzędnych (0,0)). Co dokładnie oznacza liczba opisującą piksel obrazu zostanie wyjaśnione dalej. Należy w tym miejscu zwrócić uwagę na bardzo ważną konwencję występującą w języku programowania MATLAB. Jeśli na końcu linii z treścią polecenia nie ma średnika na ekranie zostanie wyświetlony wynik jego wykonania (tak jak w ostatnim przykładzie). Jeśli średnik jest, to po naciśnięciu klawisza Enter polecenie zostanie wykonane, ale bez efektu w postaci wyświetlenia jakiegoś komunikatu. Wynik działania znaku średnika na końcu linii polecenia można zaobserwować wpisując w linii poleceń:
>> I(85,35); Wyświetlenie przeczytanego obrazu Aby w końcu zobaczyć jak wygląda zapisany w tablicy I obraz trzeba wykonać kolejne polecenie: >> imshow(i) Otwarte zostanie teraz nowe okno i wyświetlony wczytany wcześniej z pliku Lena_1.tif obraz, który wygląda tak: Rys. 2. Obraz przeczytany z pliku Lena_1.tif Zapisany w tablicy I obraz okazał się obrazem monochromatycznym. Należy zwrócić uwagę, że nowe okno o nazwie (figure) posiada własny interfejs pozwalający na wykonywanie na obrazie podstawowych operacji takich jak na przykład powiększanie, zmniejszanie, obracanie, czy zapis do pliku. Bezpośredni dostęp do elementów obrazu przez utworzoną w poprzednim kroku tablicę I, pozwala oczywiście na stosunkowo wygodne zmiany treści obrazu. Dla przykładu po wykonaniu polecenia: >> I(85,35) = 236; następuje zmiana wartości piksela o współrzędnych (85, 35) z 72 na 236. Rezultat tej zmiany można zaobserwować wykonując kolejny raz polecenie >> imshow(i)
Przy pomocy narzędzia do powiększania można teraz zaobserwować, co zmieniło się w treści wyświetlonego obrazu. Należy zaznaczyć, że wykonana zmiana dotyczy jedynie zawartości tablicy I, a nie obrazu zapisanego w pliku Lena_1.tif. Narysowanie histogramu Jeśli bliżej przyjrzeć się wyświetlonemu obrazowi to od razu widać, że nie wygląda on najlepiej. Podstawową wadą zdjęcia jest słabe wykorzystanie dostępnej skali szarości. Brak jest praktycznie punktów bardzo jasnych i zdecydowanie ciemnych. Dla liczbowej oceny wykorzystania skali szarości można wykorzystać metodę polegającą na analizie wykresu zwanego histogramem. Wykres ten pokazuje ilościową przynależność pikseli obrazu do poszczególnych poziomów szarości. Obliczenie i narysowanie histogramu obrazu w środowisku MATALAB z pakietem Image Processing Toolbox jest zadaniem prostym. Wystarczy użyć poleceń: >> figure >> imhist(i) Polecenie figure ma za zadanie otwarcie nowego okna graficznego, w którym zostanie narysowany histogram obrazu. Bez wydania tego polecenia histogram zostałby narysowany w otwartym wcześniej oknie, zamazując widok zdjęcia. Polecenie imhist spowoduje natomiast obliczenie i narysowania w ostatnio otwartym oknie graficznym wykresu histogramu obrazu zapisanego w tablicy I. Histogram wygląda tak: Rys. 3. Histogram obrazu zapisanego w tablicy I Na wykresie widać jasno, że wykorzystana została praktycznie tylko środkowa część skali szarości.
Poprawa obrazu przez wyrównanie histogramu W literaturze z dziedziny zwanej Przetwarzaniem obrazów (Image proceesing) opisanych jest wiele algorytmów zamieniających jeden obraz w drugi. Przekształcenia takie, niekiedy bardzo skomplikowane matematycznie, wykonywane są dla osiągnięcia różnych celów. Jednym z nich jest poprawa jakości obrazu. Dla polepszenia jakości obrazu, który został wczytany i wyświetlony w poprzednich punktach ćwiczenia zastosowany zostanie algorytm zmieniający jasność pikseli tak, aby histogram obrazu stał się możliwie wyrównany. Wyrównanie histogramu spowoduje niewątpliwie lepsze wykorzystanie będącej do dyspozycji skali szarości a tym samym poprawę wyglądu obrazu. Nie wnikając w zbędne szczegóły, działanie algorytmu polega na celowym rozjaśnianiu jednych pikseli obrazu i przyciemnianiu innych. Opis przykładowego algorytmu wyrównania histogramu można znaleźć w pracy [1]. Aby przekształcić obraz w inny o bardziej wyrównanym histogramie należy w linii polecenia wpisać: >> J = histeq(i); Wykonanie funkcji histeq() spowoduje utworzenie nowej tablicy o nazwie J, w której zapisany zostanie obraz będący wynikiem wykonania algorytmu. Można ta sprawdzić przez wydanie kolejny raz polecenia. >> whos Wyświetlenie poprawionego obrazu Pozostaje jeszcze zobaczyć jak wygląda poprawiony obraz, który jest zapisany w tablicy J. W tym celu należy w linii komend umieścić dwa użyte już wcześniej polecenia: >> figure >> imshow(j) Pierwsze z nich jest znów po to, aby utworzyć nowe okno graficzne nie niszcząc tego, co już zostało wyświetlone w poprzednio otwartych oknach. Drugie polecenie ma pokazać jak wygląda obraz uzyskany przez wyrównanie histogramu. Efekt jest taki jak to pokazano na rysunku 4. Porównując obraz źródłowy zapisany w tablicy I i obraz przetworzony zapisany w tablicy J, bez kłopotu można stwierdzić, że operacja wyrównania histogramu dała dobry efekt. Jak widać wyrównanie histogramu w znacznym stopniu poprawiło ogólny wygląd obrazu. Można zaobserwować zwiększenie tzw. dynamiki, czyli różnicy elementami pomiędzy najjaśniejszymi i najciemniejszymi, co niewątpliwie wpływa na zwiększenie plastyczności obrazu. Należy jednak zdawać sobie sprawę, że przeprowadzona operacja jest w pewnym sensie zabiegiem sztucznym, wprowadzającym do obrazu informację, która nie pochodzi z rzeczywistości a powstaje jedynie w wyniku zabiegów matematycznych.
Rys. 4. Obraz po wyrównaniu histogramu Pozostaje jeszcze sprawdzić jak wygląda histogram dla obrazu przetworzonego. Można to zrobić wydając znane już polecenia: >> figure >> imhist(j) Histogram obrazu przetworzonego wygląda teraz tak: Rys. 4. Histogram obrazu J
Widać, że histogram obrazu przetworzonego jest bardziej wyrównany. W efekcie wykonania całej dotychczas opisanej procedury zostały otwarte cztery okna graficzne. W pierwszych dwóch znajdują się obraz źródłowy i jego histogram, natomiast dwa kolejne zwierają efekt przetwarzania, czyli obraz wynikowy i także odpowiedni histogram. Zapis poprawionego obrazu do pliku Ostatnia czynnością do wykonania w niniejszym przykładzie jest zapis przetworzonego obrazu, który znajduje się w tej chwili w tablicy J, do pliku. Nie musi to być plik tego samego typu, z którego został odczytany obraz źródłowy (był to plik typu TIFF). Można na przykład zapisać przetworzony obraz w postaci skompresowanej przy pomocy algorytm JPEG. W tym celu wystarczy wydać kolejne polecenie w postaci: >> imwrite(j, Lena.jpg ) Wykonanie polecenia spowoduje zapisanie danych opisujących obraz w postaci skompresowanej do pliku o nazwie Lena.jpg. Należy dodać, że obraz źródłowy zapisany był w pliku typu TIFF. Format ten służy do zapisu obrazu w postaci nieskompresowanej. Można porównać wielkości obu plików, aby przekonać się, jaki efekt dała kompresja. 3. Pierwszy program w języku programowania MATLAB W poprzednim punkcie pokazano przykład wykorzystania możliwości MATLABA do poprawy jakości obrazu. Procedura polegała na wydawaniu sekwencji poleceń wpisywanych w linii komendy i przekazywanych do wykonania przez naciśnięcie klawisza Enter. Przy bardziej skomplikowanych zadaniach postępowanie takie może być z oczywistych względów niewygodnie. Dobrym wyjściem jest zapisanie ciągu poleceń w postaci programu. Jak już wspomniano na wstępie środowisko MATLAB zawiera własny język programowania. Język ten uznawany jest powszechnie jako jeden z języków programowania wysokiego poziomu tak jak język C, Pascal Basic czy inne. Programy napisane w tym języku mogą być wykonywane jednak w tylko środowisku, MATLAB, czyli na komputerach, na których system MATLAB został zainstalowany. Istnieje wprawdzie możliwość kompilacji takich programów i uzyskania wersji wykonywalnej, ale wymaga to dodatkowych zabiegów. Aby napisać i uruchomić program należy wykonać następujące czynności: Uruchomić środowisko MATLAB. Wybrać folder roboczy, w którym zapisywany będzie program i ustawić do niego ścieżkę za pomocą narzędzi dostępnych w okienku Browse. Wykonać sekwencję poleceń: File, New, M-file (otwarte zostanie w ten sposób okno edytora programu). Skopiować do okna edytora poniżej podany przykładowy program. Wykonać polecenie SaveAs i zapisać program w wybranym wcześniej folderze pod unikalną nazwą (powstanie w ten sposób plik tekstowy o nazwie nazwa_programu.m)
Zminimalizować okno edytora W linii komend środowiska MATLAB wpisać: >> nazwa_programu i nacisnąć klawisz Enter. Przykładowy program jest taki: %********************************************************************** % Pierwszy program w języku MATLAB %********************************************************************** I = imread('lena_1.tif'); J = histeq(i); subplot(2,2,1); imshow(i); subplot(2,2,2); imhist(i); subplot(2,2,3); imshow(j); subplot(2,2,4); imhist(j); imwrite(j, 'Wynik.jpg') % Przeczytanie obrazu wejściowego % i zapisnie go w tablicy I % Obliczenie obrazu wyjściowego J % z wykorzystaniem algorytmu wyrównania % histogramu % Górny lewy rysunek % Wyświetlenie obrazu wejściowego % Górny prawy rysunek % Wyświetlenie histogramu obrazu wejściowego % Dolny lewy rysunek % Wyświetlenie obrazu wyjściowego % Dolny prawy rysunek % Wyświetlenie histogramu obrazu wejściowego % Zapisnie obrazu wyjściowego do pliku % w postaci skompresowanej Jest to program wykonujący w zasadzie to samo, co zrobiono w poprzednim punkcie. Drobne zmiany dotyczą tylko sposobu wyświetlania obrazów i wykresów. W miejsce kilku okien graficznych dla wygody obserwatora zastosowano jedno okno, w którym pokazano dwa obrazy i dwa wykresy. Do wypełnienia okna graficznego wykorzystano funkcję subplot( ),która pozwala na narysowanie w jednym oknie graficznym prostokątnej tablicy rysunków (patrz system pomocy Help). 4. Samodzielne napisanie programu w języku MATLAB Zadanie polega na samodzielnym napisaniu prostego programu przekształcającego wczytany obraz w negatyw. Obraz źródłowy umieszczony jest w pliku Lena_2.tif. Jest to obraz monochromatyczny o rozmiarach 256 x 256 punktów. Stopnie szarości punktów obrazu kodowane są przy pomocy liczb całkowitych z zakresu [0, 225]. Liczba 0 oznacza kolor czarny, natomiast liczba 255, biały.
Algorytm przekształcania obrazu jest następujący: Przeczytać obraz wejściowy z pliku Lena_2.tif i zapisać go w tablicy X Wyświetlić przeczytany obraz wejściowy. Wyznaczyć rozmiary obrazu wejściowego. Zadeklarować tablicę dla zapisu obrazu wyjściowego Obliczyć wartości szarości dla punktów obrazu wyjściowego (negatywowego) Y posługując się zależnością: y(i, j ) 255 x(i, j ) Wyświetlić obraz wyjściowy, wejściowy i ich histogramy podobnie jak w poprzednim przykładzie. Wynik działania programu powinien być taki jak pokazano na rysunku 5. Rys. 5. Pozytyw, negatyw i ich histogramy
Zalecenia pomocnicze: Do przeczytania obrazu wejściowego użyć funkcji imread() (tak jak w poprzednim przykładzie) Do wyświetlenia obrazów użyć funkcji imshow(). Rozmiary obrazu wejściowego można wyznaczyć używając funkcji size( )(patrz Help). Przykładowo, aby określić rozmiary prostokątnej tablicy A, można użyć funkcji size( )w następujący sposób: [n, m ] = size(a); Wywołanie funkcji da w efekcie przypisanie zmiennym n i m, liczb określających odpowiednio ilość wierszy i kolumn tablicy A. Tablica, w której zostanie zapisany obraz wyjściowy powinna być wcześniej zadeklarowana. Deklaracja tablicy pozwala zarezerwować odpowiednią ilość pamięci dla danych, jakie znajdą się w tablicy. Deklarację tablicy można wykonać używając funkcji zeros(), powstanie w efekcie tablica wypełniona zerami. Użycie funkcji zeros()w następujący sposób: B = zeros(n, m, 'uint8'); spowoduje utworzenie tablicy B wypełnionej zerami. Tablica B ma n wierszy i m kolumn. Zera zostaną zapisane tablicy jako liczby całkowite bez znaku (uint8). Obliczenie szarości pikseli obrazu negatywowego przeprowadzić można na dwa sposoby Zastosować pętlę programową Szablon pętli jest taki: for i = 1:n end Operacje wewnątrz pętli Wykorzystać możliwości operacji na macierzach oferowane przez język MATLAB Sprawdzić posługując się plikiem pomocy, jak można napisać powyższy program bez użycia pętli.
Należy zaznaczyć, że pisząc programy w języku MATLAB w dobrym stylu jest minimalizowanie używania pętli. LITERATURA 1. Pavlidis T., Grafika i przetwarzanie obrazów, WNT, Warszawa 1987.