Laboratorium Podstaw Informatyki Strona 1 Laboratorium Podstaw Informatyki Kierunek Elektrotechnika Ćwiczenie Graf Elementy grafiki komputerowej: mapy bitowe. wykresy funkcji dwóch zmiennych w poziomach szarości. Oprac. Paweł Turcza Kraków 2014
Laboratorium Podstaw Informatyki Strona 2 1. Podstawy obsługi map bitowych Celem niniejszej instrukcji jest zapoznanie Czytelnika z biblioteką SDL oraz jej wykorzystaniem w operacjach graficznych takich jak wyświetlanie obrazów cyfrowych (map bitowych) oraz wykresów funkcji dwóch zmiennych. Przy okazji prezentowany jest format plików: PGM, PPM oraz BPM. 1.1 Przykład Operacje graficzne będą realizowane z użyciem wieloplatformowej biblioteki graficznej SDL. Poniżej przedstawiony jest prosty program ilustrujący sposób tworzenia tzw. powierzchni ekranu, która wykorzystywana jest do wyświetlania grafiki. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <SDL/SDL.h> SDL_Surface *screen = NULL; /* wskaznik na strukture reprezentujaca powierzchnie ekranu */ void draw () { Uint32 color = SDL_MapRGB (screen->format, 0, 0, 0); /* utworz kolor czarny */ SDL_FillRect (screen, NULL, color); if(screen->format->bytesperpixel!= 4) return; /* wypelnij caly ekran tym kolorem*/ /* sprawdz czy pixele ekranu sa 32 bitowe*/ int *p; //ARGB int h, w; for(h=0; h < screen->h/3; h++) { //ustaw wskaznik do pixeli na poczatek h-tej linii //screen->pitch -- odstep (bajtowy) pomiedzy poszczegolnymi liniami p = (int *)screen->pixels + h*screen->pitch/4; for(w=0; w < screen->w; w++) *p++ = 255<<16; //ARGB for(h=screen->h/3; h < 2*screen->h/3; h++) { p = (int *)screen->pixels + h*screen->pitch/4; for(w=0; w < screen->w; w++) *p++ = 255<<8; for(h=2*screen->h/3; h < screen->h; h++) { p = (int *)screen->pixels + h*screen->pitch/4; for(w=0; w < screen->w; w++) *p++ = 255; SDL_Flip (screen); SDL_Delay (1); //przelacz strone //poczekaj 1 sek. int main (int argc, char *argv[]) { /* Initialize SDL */ if (SDL_Init (SDL_INIT_VIDEO) < 0) { fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError ()); return -1; fprintf(stderr, "init OK\n"); screen = SDL_SetVideoMode (640, 480, 32, SDL_SWSURFACE SDL_DOUBLEBUF); /* Ustaw tryb graf. 640x480 32-bity */
Laboratorium Podstaw Informatyki Strona 3 if (screen == NULL) { fprintf(stderr, "%s", "Couldn't set 640x480x16 video mode: %s\n", SDL_GetError ()); return -1; fprintf(stderr, "SDL_SetVideoMode\n"); SDL_WM_SetCaption ("SDL MultiMedia Application", NULL); int done = 0; while (!done) { SDL_Event event; while (SDL_PollEvent (&event)) { /* sprawdz czy sa jakies komunikaty (klawiatura, mysz) */ switch (event.type) { case SDL_KEYDOWN: break; case SDL_QUIT: done = 1; break; default: break; draw (); /* rysuj na ekranie */ return 0; 1.2 Struktura pliku *.PGM Pliki te używane są do przechowywania obrazów monochromatycznych, tj. o odcieniach szarości. Struktura pliku PGM jest następująca: 1. Dwuliterowy identyfikator formatu pliku "P5". 2. Separator, tj. znak biały (spacja, TABs, CRs, LFs). 3. Liczba dziesiętna w kodzie ASCII reprezentująca szerokość obrazu 4. Separator 5. Liczba dziesiętna w kodzie ASCII reprezentująca liczbę linii w obrazie (wysokość ) 6. Separator 7. Liczba dziesiętna w kodzie ASCII określająca maksymalną jasność pixela 8. Separator (zwykle nowa linia) 9. Dane obrazowe. W przypadku, gdy maksymalna jasność pixela (z pk. 7) nie przekracza 255 jeden pixel obrazu reprezentowany jest przez jeden bajt. W przeciwnym przypadku przez dwa bajty. Dodatkowo w nagłówku może być umieszczony komentarz, który rozpoczyna się od znaku "#" i rozciąga do końca linii. Więcej informacji można znaleźć tutaj: http://netpbm.sourceforge.net/doc/pgm.html 1.3 Struktura pliku *.PPM Struktura pliku PPM jest podobna do pliku PGM. Występują dwie różnice: 1. identyfikatorem pliku jest "P6" 2. Dane obrazowe dotyczą poszczególnych składowych kolorów podstawowych tj. czerwonego (R), zielonego (G), niebieskiego (B), zapisanych w tej kolejności przy użyciu jednego bajtu na składową, jeśli wartość określająca maksymalne nasycenie składowej (odpowiednik wartości z punktu 7 PGM) nie przekracza 255.
Laboratorium Podstaw Informatyki Strona 4 Więcej informacji można znaleźć tutaj: http://netpbm.sourceforge.net/doc/ppm.html Zadanie 1: Na podstawie przykładu 1.1 napisać przeglądarkę do plików PGM i PPM. Na początku należy przyjąć, że interesują nas tylko 8-bitowe PGM tj. obrazy w odcieniach szarości, w których każdy pixel reprezentowany jest przez pojedynczy bajt. Algorytm postępowania: Zadeklarować zmienne globalne: FILE *fp; //wskaźnik do pliku int W funkcji main: 1. otworzyć plik z obrazem PGM, wczytać nagłówek pliku wraz z informacją o wielkości obrazu. 2. uruchomić funkcję SDL_SetVideoMode z odpowiednimi parametrami reprezentującymi szerokość i wysokość obrazu. Liczbę bitów na pixel pozostawić bez zmian (32). 3. Zamknąć plik z obrazem W funkcji draw: 1. otworzyć plik z obrazem PGM, pominąć nagłówek obrazu. 2. pominąć (fgetc) znak oddzielający nagłówek od danych. 3. w pętli for kopiować dane z pliku do pamięci obrazu 4. zamknąć plik obrazu. 1.4. Struktura pliku *.BMP Plik *.BMP składa się zasadniczo z czterech kolejno umieszczonych części: 1) struktura BITMAPFILEHEADER 2) struktura BITMAPINFOHEADER 3) tablica 256 struktur struktur typu RGBQUAD 4) dane bitmapy W przypadku systemu Windows, definicje podanych struktur zawarte są w pliku nagłówkowym windows.h. W przypadku systemu Linux definicje to zostały umieszczone w pliku bmp.h. Warto zajrzeć do tego pliku i zobaczyć jak te definicje zostały zrobione. Najważniejszymi polami struktury BITMAPFILEHEADER są: bftype - powinno być równe B M bfoffbits - początek danych bitmapy, liczony względem początku pliku Najważniejszymi polami struktury BITMAPINFOHEADER są: biwidth - szerokość bitmapy (liczba punktów w linii) biheight - wysokość bitmapy (liczba linii) bibitcount - ilość bitów na jeden piksel Tablica 256 struktur typu RGBQUAD zawiera paletę kolorów stosowaną w danej bitmapie. Zadanie 2: Na podstawie przykładu 1.1 napisać przeglądarkę do bitmap. Na początku należy przyjąć, że interesują nas tylko bitmapy w odcieniach szarości mające po 8 bitów na piksel. Algorytm rozwiązania zadania powinien wyglądać następująco:
Laboratorium Podstaw Informatyki Strona 5 1) zadeklarować potrzebne struktury danych (zmienne) typu: BITMAPFILEHEADER, BITMAPINFOHEADER, tablica 256 elementów typu RGBQUAD, bufor na jedną linię, 2) otworzyć plik zawierający bitmapę, przy użyciu funkcji fopen, 3) używając funkcji fread, wczytać z pliku dane do zadeklarowanych zmiennych wyżej wymienionych typów tj.: BITMAPFILEHEADER, BITMAPINFOHEADER, tablicy struktur RGBQUAD, 4) zainicjować odpowiedni tryb graficzny, tak jak podano to w przykładzie, 5) w pętli wykonywać kolejno: czytanie całej linii, przy pomocy fread do bufora wyświetlanie całej linii tak jak w przykładzie. Dodatkowo przeglądarkę należy wyposażyć w możliwość regulacji jasności i kontrastu (sterowanie za pomocą strzałek, lub klawiszy +/-). W przypadku korzystania z trybu 256 kolorów można to uzyskać poprzez zmianę palety karty graficznej. Technicznie można to zrobić poprzez dodanie pewnej składowej stałej do każdego elementu palety (regulacja jasności), oraz mnożenie elementów palety przez stałą (kontrast). W przypadku trybów o większej ilości kolorów należy odpowiednio modyfikować pixele obrazu. Zadanie 3: Przerobić napisaną wcześniej przeglądarkę, tak aby mogła obsługiwać bitmapy kolorowe posiadające 8 bitów na piksel czyli 256 kolorów. Uwaga: w przypadku obrazów kolorowych, w których informacja o kolorze zakodowana jest na 8 lub mniejszej ilości bitów poszczególne pixele obrazu nie reprezentują bezpośrednio poszczególnych składowych koloru (R,G,B). Są one indeksami do tablicy zwanej paletą kolorów. Paleta ta jest zorganizowana w postaci 256 wierszowej (lub mniejszej) tablicy struktur. W każdej z 256 struktur umieszczona jest informacja o intensywności każdej z trzech podstawowych barw (R-czerwony, G-zielony B-niebieski). Tak jak przedstawia to powyższy rysunek. Dlatego chcąc poprawnie wyświetlić 8-bitowe obrazy (zawierające paletę kolorów) należy wartość pixela traktować jako indeks do tablicy (palety) z której to uzyskuje się poszczególne składowe koloru.
Laboratorium Podstaw Informatyki Strona 6 Zadanie 4: Do przeglądarki dodać funkcję pozwalającą na przeglądanie zdjęć. Funkcja ta działa w ten sposób, że jako argument przeglądarce podaje się ścieżkę do katalogu, gdzie znajdują się bitmapy (zdjęcia). Przeglądarka kolejno (np. po naciśnięciu klawisza, lub po określonym czasie) wyświetla wszystkie znajdujące się w danym katalogu bitmapy. Jeżeli ścieżka nie została podana, to przeglądarka wyświetla bitmapy znajdujące się w katalogu z którego została uruchomiona. Podczas rozwiązywania zadania należy skorzystać z następujących funkcji: findfirst(char *pathname, struct ffblk *ffblk, int attrib); //znajdź pierwszy findnext(struct ffblk *ffblk); //znajdź następny opis argumentów: pathname: ciąg znaków, który może zawieraæ literę określającą numer dysku (opcjonalnie), ścieżkę, nazwę pliku, którego poszukujemy. Nazwa pliku może zawierać znaki? i *. Przykład: c:\\obrazy\\*.bmp - interesują nas wszystkie pliki znajdujące się na dysku C w katalogu obrazy i mające rozszerzenie bmp. ffblk: wskaźnik (adres) do struktury, w której umieszczany jest wynik poszukiwania zwrócony przez funkcje findfirst i findnext. attrib: atrybuty pliku - ustawiæ na 0 Każde wywołanie funkcji findfirst, findnext zwróci jedną nazwę pliku z podanego katalogu i pasującą do podanego wzorca, aż wszystkie pliki zostaną znalezione. Funkcje zwracają 0 jeśli poszukiwanie zakończyło się sukcesem, w przeciwnym razie -1. Proces poszukiwania zawsze rozpoczynamy od wywołania funkcji findfirst, potem findnext, aż wszystkie pliki zostaną odnalezione. Nazwa znalezionego pliku umieszczana jest w polu ff_name struktury ffblk. 2. Obrazowanie wykresów funkcji dwóch zmiennych w odcieniach szarości. Najprostszym sposobem na obrazowanie przebiegu funkcji dwóch zmiennych na ekranie komputera jest użycie metody wykorzystywanej przez twórców map papierowych. Jak wiemy, na takiej mapie wysokość terenu prezentowana jest przy użyciu odpowiedniej skali kolorów. My ograniczymy się do odcieni szarości. 0 0 w W-1 y min x min x i x max h y i H-1 y max Załóżmy, że chcemy w ten sposób zobrazować wykres funkcji dwóch zmiennych z = f(x,y) dla x min < x < x max oraz y min < y < y max na ekranie o rozdzielczości W H. W tym celu każdemu punktowi ekranu (w, h) musimy przypisać wartość funkcji z i,j = f(x i, y j ), gdzie x i = x min + w (x max x min )/(W-1), w = 0,...,W-1 y j = y min + h (y max y min )/(H-1), h = 0,...,H-1
Laboratorium Podstaw Informatyki Strona 7 Obliczone wartości funkcji z i,j są następnie przeliczane na wartość określającą kolor lub odcień szarości i obrazowane jako punkt o współrzędnych (i, j) na ekranie. Zadanie 5: Narysować funkcję z = f(x,y) = sin( x + y ) dla x, y z przedziału [-2, 2]. Narysować funkcję z = f(x,y) = sin( x 2 + y 2 ) dla x, y z przedziału [-2, 2]. 3. Elementy.przetwarzania obrazów Jedną z prostszych operacji dokonywanych na obrazach jest wydobywanie krawędzi. Operację tą wykonuje się używając specjalnie zaprojektowanych dwuwymiarowych filtrów. Najprostszym filtrem tego typu jest filtr o współczynnikach: 1 1 h(i, 1 8. j)=[ 1 1 1] Przy czym indeksy i, j zmieniają się od 1 do 1: a więc element h(-1,-1)=-1, a h(0,0)=8, h(1,1)=-1 Operacja filtracji polega na wyznaczaniu wartości wyrażenia 1,1 p( x, y) = p( x + i, y + j) h( i, j) (*) i= 1, j= 1 Mówiąc inaczej, od każdego punktu obrazu pomnożonego przez 8 odejmij wartości wszystkich jego ośmiu sąsiadów. W przypadku punktów leżących na krawędzi, czyli tam gdzie nie ma któregoś z sąsiadów, rozszerz obraz poprzez jego lustrzane odbicie, które w tym przypadku sprowadza się do przyjęcia, że wartością brakującego punktu jest wartość punktu dla którego wyznaczamy wartość wyrażenia (*).