Filtracja obrazu CPU (aktualizacja 1.IV.2014).

Transkrypt

Filtracja obrazu CPU (aktualizacja 1.IV.2014).
SMOR - LABORATORIUM 1
FILTRACJA OBRAZU CPU
CEL I ZADANIA
Celem laboratorium jest zapoznanie studentów z problemami programowania współbieżnego.
Zadanie: rozszerz załączoną aplikację "FiltracjaObrazu" o:
1.
2.
3.
Synchronizację zapisywania i wyświetlania obrazu przefiltrowanego.
Filtrowanie (filtr Sobela) obrazu w jednym wątku.
Filtrowanie (filtr Sobela) obrazu wielowątkowe (równoległe).
Założenia:


Możliwe jest wielokrotne, jednoczesne wywołanie funkcji filtracji.
Liczba wątków w przetwarzaniu równoległym może być z góry ustalona (ale >= 4).
INFORMACJE SZCZEGÓŁOWE
Załączona aplikacja wymaga Visual Studio w wersji co najmniej 2010. Wymaga zainstalowanej biblioteki MFC, a
więc nie można jej uruchomić w wersjach Visual Studio Express Edition.
Do wykonania laboratorium wystarczy
ImageProcessing.cpp. Pliki te zawierają:



modyfikacja
jedynie
dwóch
plików:
ImageProcessing.h
i
Klasę ImageProcessing, która zawiera funkcję rysowania obrazu: drawImage (przefiltrowanego lub nie
- w zależności od wartości checkboxa "Pokaż wynik filtracji").
Treść funkcji wątku filteringThreadFunction, który jest uruchamiany w momencie naciśnięcia przycisku
"Uruchom filtrację". Po zakończeniu wątek ten wysyła wiadomość do głównego okna WMU_PROCESSING_COMPLETE, informującą, że proces został zakończony. Główny wątek programu w
obsłudze tej wiadomości sprawdza, czy ustawiony jest checkbox "Filtracja ciągła". Jeśli tak, to po
zakończeniu ponownie tworzony jest wątek wywołujący funkcję filtracji. Dzieje się to do momentu
odznaczenia tej flagi.
Funkcję processImage, która jest odpowiedzialna za przetwarzanie obrazu.
Zaimplementowana w obecnej postaci funkcja processImage pokazuje w jaki sposób uzyskać dostęp do
elementów obrazu z klasy SimpleImage oraz wykonuje prostą operację zwiększenia wartości wszystkich pikseli.
Zadaniem studenta jest zmiana tej funkcji na funkcję filtracji krawędziowej za pomocą filtru Sobela (opisany w
kolejnym rozdziale).
Należy także zmodyfikować funkcję OnInitDialog w pliku FiltracjaObrazuDlg.cpp w polu „TODO: Add extra
initialization here”. Funkcja ta jest uruchamiana jeden raz w czasie tworzenia okienka dialogowego. Można w
niej wpisać stworzenie obiektu synchronizacyjnego, np. typu Mutex. W innych funkcjach będzie można uzyskać
dostęp do tego obiektu poprzez funkcję OpenMutex, gdzie jako parametr podana będzie jego nazwa.
Rysunek 1 przedstawia główne okno aplikacji. Interfejs pozwala na wczytanie obrazu (format JPG) lub
wygenerowanie obrazu testowego. Po wciśnięciu przycisku "Rozpocznij filtrację" następuje jednokrotna filtracja
za pomocą napisanej funkcji wątka, o ile nie została zaznaczona flaga "Filtracja ciągła", która powoduje, że
filtracja jest wykonywana ciągle jedna po drugiej. Zaznaczenie flagi "Pokaż wynik filtracji" powoduje
wyświetlanie obrazu przefiltrowanego zamiast oryginalnego.
Rysunek 1: Główne okno aplikacji.
FILTR SOBELA
Filtr Sobela jest jednym z podstawowych filtrów krawędziowych. Opiera się on na dwóch maskach 3x3:
Gx
1
0
-1
2
0
-2
1
0
-1
0
0
0
-1
-2
-1
Gy
1
2
1
Pierwsza z nich służy do wyznaczania wartości krawędzi poziomych, druga do wartości krawędzi pionowych.
Filtracji dokonuje się poprzez splot wartości w maskach z obrazem. Splot ten można określić w następujący
sposób:
Dla każdego piksela (x, y) obrazu I:
a. Wyznacz Gx jako Gx = 1 * I(x-1,y-1) + 2 * I(x, y-1) + 1 * I(x+1, y-1) +
-1 * I(x-1,y+1) – 2 * I(x, y+1) – 1 * I(x+1, y+1).
b. Wyznacz Gy jako Gy = 1 * I(x-1,y-1) + 2 * I(x-1, y) + 1 * I(x-1, y+1) +
-1 * I(x+1,y-1) – 2 * I(x+1, y) – 1 * I(x+1, y+1).
Proszę pamiętać, że zarówno wartości Gx jak i Gy mogą przyjmować wartości dodatnie i ujemne, poza zakresem
typu unsigned char. Następnie dla każdego piksela należy wyznaczyć całkowitą siłę krawędzi jako:
G  Gx  G y
2
2
Całkowita siła krawędzi obcięta do zakresu [0..255] będzie naszym ostatecznym wynikiem filtracji.
Proszę pamiętać, aby pośrednie wyniki filtracji zapisywać w zmiennych pomocniczych, a nie w obrazie
oryginalnym! Proszę także pamiętać, że indeksy analizowanych pikseli nie mogą wyjść poza zakres obrazu.
SYNCHRONIZACJA
Należy również pamiętać o wyznaczeniu sekcji krytycznej (poprzez obiekt sekcji krytycznej lub mutex) przy
zapisie obrazu przefiltrowanego do tablicy znajdującej się pod wskaźnikiem będącym parametrem wywołania
wątku, czyli funkcji:
if (params.filtered_image!=NULL)
*(params.filtered_image) = local_filtered_image;
Również przy rysowaniu obrazu dostęp do zmiennej powinien być chroniony aby zapobiec sytuacji, w której
wyświetlamy częściowo zmieniony obraz:
StretchDIBits(pDC->m_hDC, 1, 1, dest_w - 2, dest_h - 2, 0, 0, image.width,
image.height, image.data_ptr, image.getBip(), DIB_RGB_COLORS, SRCCOPY);
KLASA SIMPLEIMAGE
Klasa SimpleImage zaimplementowana w aplikacji służy przechowywaniu, wczytywaniu i zapisywaniu obrazów
typu JPG i PGM. Do jej podstawowych zmiennych należą:
width – szerokość obrazu
height – wysokość obrazu
data_ptr – wskaźnik na dane obrazu ułożone wierszami. Każdy piksel to jedna wartość jasności w zakresie 0-255
typu unsigned char.
W aplikacji do funkcji ImageProcessing podawane są zawsze obrazy w skali szarości, tak więc dostęp do
pojedynczego elementu (x, y) obrazu mamy poprzez operację:
image.data_ptr[x + y*image.width]
Powodzenia! W razie pytań I wątpliwości proszę pytać w czasie laboratorium, czy mailowo.

Podobne dokumenty