Po zainstalowaniu Processing i ustawieniu wszystkiego zgodnie z moim przyzwyczajeniem, nadszedł czas na pierwsze linie kodu. Aplikacja w processing opiera się przede wszystkim na dwóch funkcjach:
setup()
draw()
Funkcja setup()
służy do ustalenia warunków początkowych. Wywoływana jest jednorazowo po uruchomieniu aplikacji. Umieszcza się tam wszystko to co potrzebujemy i możemy zainicjować, załadować, zanim nasz program zacznie działać na dobre.
void setup() { size(960, 540); }
Użycie funkcji size()
w setup()
pozwala ustawić początkowy rozmiar okna. Po uruchomieniu takiej aplikacji, mamy spektakularny efekt w postaci pustego okna.
Funkcja draw()
wywoływana jest cyklicznie, aż do zamknięcia aplikacji. Jest to połowiczna prawda, bo można zablokować wywoływanie tej funkcji, ale nie ma to teraz żadnego znaczenia. Domyślna częstotliwość dla draw()
to 60Hz. Zmianę można wywołać poprzez funkcje frameRate()
. Po uruchomieniu aplikacji zobaczymy takie okno
Mój projekt ma bazować na przetwarzaniu obrazu z kamery, więc należałoby dodać jej obsługę. Potrzebny do tego jest moduł Video. W przypadku Processing bazuje on na znanej bibliotece GStreamer. Instalacja poprzez “Contributon Manager” znacząco upraszcza sprawę.
Na początek planuję używać tego co mam pod ręką, czyli kamerę wbudowaną w laptopa. Nie jest zbyt spektakularna jeśli chodzi o parametry, 30 klatek w rozdzielczości 1280×720 będzie wystarczające. Sądzę, że nawet nieco mniej będzie wygodniejsze. Mniej danych, szybciej się policzy. Skoro kamera nie pracuje szybciej niż 30Hz to częstotliwość dla funkcji draw() ustawię też na 30. Czyli będzie to wyglądało następująco:
import processing.video.*; Capture video; void setup() { size(960, 540); frameRate(30); video = new Capture(this, width, height); video.start(); // uruchomienie kamery }
Zmienne systemowe – width
, height
zawierają odpowiednio szerokość i wysokość okna aplikacji. Zmienna globalna video zawiera obiekt kontrolujący obsługę kamery. Za wyświetlenie obrazu z kamery w oknie odpowiedzialna będzie funkcja draw():
void draw() { if ( video.available() ) //dostępna klatka z kamery video.read(); //odczyt klatki image(video, 0, 0); }
Konstrukcja aplikacji z podziałem na setup() i draw() jest mniej przejrzysta. Według mnie przydało by się wprowadzić jeszcze wyraźnie zaznaczony update(). Czyli kod, który aktualizuje stan naszej aplikacji, ale nie generuje obrazu. W taki sposób nieco bardziej będzie to przypominało standardową pętlę zdarzeń z silnika gier.
void update() { if ( video.available() ) //dostępna klatka z kamery video.read(); //odczyt klatki } void draw() { update(); image(video, 0, 0); }
Uruchomienie tego kodu wyświetli okno z obrazem z kamery. Niewiele kodu, a już coś działa.
Funkcja image() rysuje w oknie zadany obraz. Definiujemy górny lewy róg, oraz opcjonalnie szerokość i wysokość. Według dokumentacji nie należy do najszybszych. Może m.in. skalować wyświetlany obraz. Wersja bardziej bezpośrednia, to użycie set().
void draw() { update(); set(0, 0, video); }
Wracając do meritum, niespecjalnie spektakularny efekt, ale do przodu. Kolejny etap to obróbka obrazu. Nie mam w planie pisać wszystkiego od nowa. Znacznie mądrzejsi ode mnie stworzyli zacną bibliotekę OpenCV i z niej zamierzam niedługo skorzystać.