Zobaczyć ocean

W Prog & Play bardzo chętnie zajmujemy się fotografiami cyfrowymi, przekształcając je na różne sposoby za pomocą wymyślnych algorytmów. Dzisiaj zdjęcia ze zwykłej niedzielnej wycieczki przerobimy na materiały znad wody.

W Prog & Play bardzo chętnie zajmujemy się fotografiami cyfrowymi, przekształcając je na różne sposoby za pomocą wymyślnych algorytmów. Dzisiaj zdjęcia ze zwykłej niedzielnej wycieczki przerobimy na materiały znad wody.

Przetnijmy w myśli zwykłe, cyfrowe zdjęcie poziomą linią i w dolną połówkę wrysujmy piksele z górnej części, ale odwracając ich kolejność w kierunku pionowym. Widoczne na zdjęciu postacie będą miały jakby swoje odbicia. Czy tym prostym sposobem uda nam się zrobić taki montaż, jakbyśmy stali nad lustrem wody? Trzeba to zobaczyć.

Rysunek 1. Typowa aplikacja do przetwarzania obrazów składa się z dwóch map bitowych, reprezentowanych przez komponenty Image, przycisków realizujących odczyt i zapis pliku na dysku oraz przycisku uruchamiającego proces przetwarzania. Uzupełnieniem są komponenty wskazujące nazwy plików wejściowego i wyjściowego: OpenPictureDialog i SavePictureDialog.

Rysunek 1. Typowa aplikacja do przetwarzania obrazów składa się z dwóch map bitowych, reprezentowanych przez komponenty Image, przycisków realizujących odczyt i zapis pliku na dysku oraz przycisku uruchamiającego proces przetwarzania. Uzupełnieniem są komponenty wskazujące nazwy plików wejściowego i wyjściowego: OpenPictureDialog i SavePictureDialog.

Fotografią cyfrową zajmowaliśmy się między innymi w numerze 5/2006. Opracowaliśmy tam bardzo ważny mechanizm odczytu pliku z dysku i wyświetlania obrazu - są to punkty wyjścia do wszelkich dalszych rozważań. Po szczegóły zapraszam do analizy tamtego materiału, a tutaj tylko w skrócie przytoczymy niezbędne algorytmy (porównaj też rysunek 1).

Algorytm odczytu pliku i wyświetlenia obrazka w lewej części okna oraz przygotowania atrybutów drugiego obrazka można by zrealizować następująco:

if( OpenPictureDialog1 -> Execute())

{

Image1->Picture->LoadFromFile(

OpenPictureDialog1->FileName);

Image1->Picture->Bitmap->PixelFormat=pf32bit;

Image2->Picture->Bitmap->PixelFormat=pf32bit;

Image2->Picture->Bitmap->Width =

Image1->Picture->Bitmap->Width;

Image2->Picture->Bitmap->Height =

Image1->Picture->Bitmap->Height;

}

Wyjaśnijmy, że z powodu groźby komplikacji, wynikających z różnych formatów map bitowych, wymuszamy na obydwu obrazach najobszerniejszy format TrueColor, zwany tu pf32bit i przypisujący po jednym bajcie pamięci do każdej składowej koloru. Tak przygotowane mapy bitowe zajmują dużo pamięci, ale po ich piksele łatwo się sięga, łatwo się je czyta i modyfikuje, co za chwilę zobaczymy. Zauważmy też, że w powyższym skrawku algorytmu rozmiary obrazu docelowego utożsamiamy z obrazem wejściowym (wkrótce dokładniej zbadamy kwestie rozmiarów).

Bliźniaczy algorytm zapisu jest jeszcze prostszy i może wyglądać tak:

if( SavePictureDialog1 -> Execute())

{

Image2 -> Picture -> SaveToFile(

SavePictureDialog1 -> FileName);

}

Algorytm przetwarzania, tutaj polegający na prostym skopiowaniu obrazów techniką piksel po pikselu, zrealizujemy następująco:

int i, j, szer, wys;

TColor k;

szer = Image2 -> Picture -> Bitmap -> Width;

wys = Image2 -> Picture -> Bitmap -> Height;

for( i = 0; i < szer; ++i)

{

for( j = 0; j < wys; ++j)

{

k = Image1 -> Picture ->

Bitmap -> Canvas -> Pixels[ i][ j];

Image2 -> Picture ->

Bitmap -> Canvas -> Pixels[ i][ j] = k;

}

}