wyświetlanie obrazu

Transkrypt

wyświetlanie obrazu
Ćwiczenie 8
FILTRACJA W DZIEDZINIE CZĘSTOTLIWOŚCI
Zakres pracy
W ramach ćwiczenia należy do przygotowanego wcześniej programu dodać możliwość
przeprowadzania następujących operacji:
1. wyświetlanie obrazu po przemnożeniu go przez tzw. okno Hamminga,
2. wyświetlanie wykresu amplitudy i fazy po przeprowadzeniu transformacji Fouriera obrazu
wejściowego,
3. zaznaczanie (za pomocą myszy) obszarów usuwanych z obrazu w dziedzinie
częstotliwości (a więc z wyniku transformacji Fouriera),
4. filtracja, czyli odtworzenie obrazu wejściowego ze zmodyfikowanej (w punkcie 3)
transformaty Fouriera.
Zadania te dotyczą wyłącznie obrazów 8-bitowych.
Realizując punkt 3 należy umożliwić rysowanie na obrazie wynikowym obszarów w kształcie
koła (lewy przycisk myszy) lub prostokąta (prawy przycisk). W normalnym trybie obszary te
powinny mieć kolor zielony o przeźroczystości 70 - będą wówczas reprezentować regiony
uwzględnione w filtracji. Rysowanie z wciśniętym przyciskiem SHIFT powinno skutkować
powstawaniem obszarów w kolorze czerwonym, a więc wykluczonych. Podwójne kliknięcie
prawym przyciskiem ma wykluczać cały obszar obrazu, podwójne kliknięcie lewym - usuwać
wszystkie obszary.
Informacje pomocnicze
Jednowymiarowe okno Hamminga to funkcja opisana następującym wzorem
 2n 
w(n)     cos

 N 1
gdzie  = 0,53836,  = 1 - , natomiast N oznacza szerokość okna. W naszym (dwuwymiarowym) przypadku N będzie równe przekątnej obrazu, natomiast n zostanie określone
wzorem
n  N 2r,
gdzie r oznacza odległość od środka obrazu.
Nałożenie na obraz okna Hamminga zapobiega niepożądanym zjawiskom, jakie do
transformaty Fouriera mogłyby wprowadzać granice obrazu.
Transformacja Fouriera obrazu o wymiarach M×N odbywa się wg wzoru:
M 1 N 1
F (u, v)   I ( x, y) exp i 2 ux / M  vy / N 
x 0 y 0
gdzie I(x,y) oznacza jasność piksela w punkcie (x,y). Należy pamiętać o następujących
zależnościach
e ix  cosx   i sin x 
e ix  cosx   i sin x 
W wyniku transformacji otrzymujemy liczbę zespoloną (złożoną z części rzeczywistej Re i
urojonej Im), którą możemy reprezentować w postaci modułu (amplitudy) i argumentu (fazy).
Aby prawidłowo wykreślić amplitudę i fazę transformaty Fouriera należy ćwiartki obrazu
przemieścić w sposób pokazany poniżej (wewnątrz poszczególnych obszarów nie ma żadnych
przemieszczeń).
Transformacja odwrotna odbywa się wg wzoru
I ( x, y ) 
1
MN
M 1 N 1
 F (u, v) expi 2 ux / M  vy / N 
u 0 v 0
Powinniśmy z niej otrzymać liczby zespolone o zerowej części urojonej.
Mnożenie liczb zespolonych opisuje wzór:
(a  bi)  (c  di)  ac  bd  i(ad  bc)
Przed wykonaniem transformacji odwrotnej należy przywrócić właściwą kolejność ćwiartek,
a po jej przeprowadzeniu przemnożyć wynik przez odwrotność okna Hamminga.
Wskazówki implementacyjne
1. Aby uzyskać prawidłowy wykres amplitudy (modułu), należy zastosować skalę
logarytmiczną:
I  log(1  I )
oraz przeskalować jasności do zakresu 0..255.
2. Przy wykreślaniu fazy (argumentu) w celu zmniejszenia niestabilności wyniku należy
przyjąć, że gdy wartość części rzeczywistej jest mniejsza od 10-3, faza wynosi  /2 lub - /2
(w zależności od znaku części urojonej).
3. Przed wyświetleniem obrazu przefiltrowanego należy przeskalować uzyskane wartości
jasności do przedziału 0..255.
4. Aby umożliwić rysowanie figur o barwach przeźroczystych, trzeba skorzystać z GDI+. W
tym celu w pliku PO1.h należy umieścić następujące polecenia:
#include <gdiplus.h>
using namespace Gdiplus;
Poza tym w klasie CPOApp należy dodać następujące pola:
GdiplusStartupInput gdiplusParametry;
ULONG_PTR
gdiplusToken;
W metodzie CPOApp::InitInstance() inicjujemy GDI+:
GdiplusStartup(&gdiplusToken, &gdiplusParametry, NULL);
W metodzie CPOApp::ExitInstance() wyłączamy GDI+:
GdiplusShutdown(gdiplusToken);
5. Aby rysowanie przebiegało płynnie (bez migotania), należy wykorzystać kontekst
pamięciowy. Do metody CImgWnd::Create(...) dodajemy następujący kod:
CDC* pDC = GetDC();
dcMemory.CreateCompatibleDC(pDC); //dcMemory to pole typu CDC
CBitmap memBM;
memBM.CreateCompatibleBitmap(pDC, szer_okna, wys_okna);
dcMemory.SelectObject(memBM);
ReleaseDC(pDC);
Teraz możemy wewnątrz CImgWnd::OnPaint() rysować na kontekście pamięciowym
używając GDI+:
Graphics gr(dcMemory);
SolidBrush pedzelCzerwony(Color(70, 255, 0, 0));
Rect r = Rect(10,10,100,100);
gr.FillRectangle(&pedzelCzerwony,r);
Na koniec gotowy obraz kopiujemy do kontekstu ekranowego:
dc.BitBlt(0, 0, szer_okna, wys_okna, &dcMemory, 0, 0, SRCCOPY);
6. Obszary rysowane na ekranie mają stanowić maskę filtra (wyłączać określone
częstotliwości). Dlatego równolegle warto tworzyć złożoną z tych samych obszarów binarną
mapę, która zostanie nałożona na część rzeczywistą i urojoną transformaty Fouriera. Trzeba
jednak pamiętać, że obraz w oknie jest przeskalowany, a transformata ma rozmiary obrazu
rzeczywistego. Dlatego najprościej jest potraktować maskę filtra jako bitmapę i - korzystając
z kolejnego kontekstu pamięciowego - przeskalować ją przy użyciu funkcji StretchBlt():
StretchBlt(dcDest, 0, 0, DestWidth, DestHeight, dcSrc, 0, 0, SrcWidth, SrcHeight,
SRCCOPY);

Podobne dokumenty