![]() |
Pełny kod źródłowy |
W tym wpisie chciałem się podzielić szablonem aplikacji OpenCV, którego ostatnio używam. Jest to szablon, który może być szczególnie użyteczny dla aplikacji interaktywnych, w których użytkownik ma wpływ na zachowanie wyświetlanych elementów. Przygotowując ten szablon starałem się zachować podejście znane z programowania aplikacji okienkowych, gdzie pracujemy raczej na komponentach odnoszących się do interfejsu użytkownika, a nie na wielu obiektach z mniej lub bardziej złożoną strukturą powiązań. Jak widać z analizy poniższego kodu funkcja main została zredukowana do minimum, a cała logika aplikacji została przeniesiona do klasy MainApp. Klasa ta nie powinna być wielokrotnie tworzona, dlatego została ona skonstruowana w oparciu o wzorzec Singelton, który tego pilnuje.
Polecam teraz dokładnie przeanalizować podany szablon, a dalsze wyjaśnienia będzie można przeczytać poniżej.
#include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace cv; //MainApp singelton class class MainApp { private: Mat canvas; // Image for drawing Scalar bgr_color; // Background color int x, y, speedX, speedY; // Circle local params public: // Some global params: static int DELAY; static int CANVAS_WIDTH; static int CANVAS_HEIGHT; private: MainApp() {} MainApp(const MainApp &); MainApp& operator=(const MainApp&); // Initial commands for setup processing void setup() { x = 0; y = 0; speedX = 1; speedY = 1; bgr_color = Scalar(120,235,139); canvas = Mat(CANVAS_HEIGHT, CANVAS_WIDTH, CV_8UC3, bgr_color); } // Commands to modify the parameters void update() { if(x < 0 ){ x = 0; speedX *= -1; } else if(x > CANVAS_WIDTH){ x = CANVAS_WIDTH; speedX *= -1; } if(y < 0 ){ y = 0; speedY *= -1; } else if(y > CANVAS_HEIGHT){ y = CANVAS_HEIGHT; speedY *= -1; } x+=speedX; y+=speedY; } // Drawing functions: void draw() { canvas = bgr_color; circle(canvas, Point(x,y), 30, Scalar(0,255,255),-1,CV_AA); } public: static MainApp& getInstance() { static MainApp instance; return instance; } // Main loop function with displaying image support // and handle mouse and keyboard events void run() { setup(); const char *win_canvas = "Canvas"; namedWindow(win_canvas, CV_WINDOW_AUTOSIZE); while (cvWaitKey(4) == -1) { update(); draw(); imshow(win_canvas, canvas); waitKey(DELAY); } } }; // Best place to initialize global MainApp params: int MainApp::DELAY = 5; int MainApp::CANVAS_WIDTH = 500; int MainApp::CANVAS_HEIGHT= 350; int main(int, char**) { MainApp::getInstance().run(); return 0; }
Patrząc na powyższy kod nie trudno zauważyć, że został on podzielony na kilka części. Dotyczy to szczególnie klasy MainApp. Została ona podzielona na funkcje, które mają ściśle określone role:
- run() - publicznie dostępna funkcja, która obsługuje główną pętlę programu. Program będzie się w niej wykonywał do momentu, aż użytkownik wciśnie klawisz Escape. Funkcja ta nie tylko wywołuje kolejne, niżej opisane funkcje, ale również odpowiada za wyświetlanie głównego okienka programu i obsługę zdarzeń nadchodzących z klawiatury i myszki.
- setup() - funkcja wywoływana tylko raz, na początku działania programu, której zadaniem jest inicjalizacja zmiennych lokalnych i utworzenie obrazka, na którym będą rysowane pozostałe elementy.
- update() - funkcja modyfikująca wybrane parametry działania programu. Tak naprawdę to tutaj powinna być zapisana główna logika działania programu.
- draw() - zawiera wszystkie operacje rysowania na głównej scenie programu.
A. Tych funkcji jest kilka. Kodu samego nie ma wiele. Czy robi on coś konkretnego?
B. Wszystko co możemy zobaczyć na ekranie odbywa się w funkcji draw(). W tym przykładzie widać wyraźnie, że rysuje ona okręgi o promieniu 30 w punkcie o współrzędnych x, y.
A. Nie wydaje się to nic szczególnie ciekawego.
B. Warto teraz zajrzeć do funkcji update(). To tutaj znajduje się właściwe centrum sterowania aplikacji. To tutaj iteracyjnie modyfikowane są wybrane parametry elementów, które są wyświetlane na ekranie. W przypadku okręgu, o którym mowa, własnie w tej funkcji jest zaprogramowane, aby poruszał się on w linii prostej i odbijał się od krawędzi.
Domyślam się, że przedstawiony szablon nie pokazuje nic szczególnie odkrywczego ;-). Wielu zaawansowanych programistów OpenCV, do których ja się raczej nie zaliczam, pewnie stosuje podobne i lepsze rozwiązania od dawna. Mam jedynie nadzieje, że okaże się on przydatny dla osób, które dopiero zaczynają przygodę z OpenCV i chcą napisać swój pierwszy interaktywny program.
Czekam oczywiście na uwagi i komentarze co można poprawić i co można zrobić lepiej.
Aktualizacja 2011.04.11: Opisany w tym wpisie szkielet aplikacji OpenCV ma kilka niedoskonałości. Opisałem je we wpisie Poprawiony szkielet aplikacji interaktywnej dla OpenCV. Zaproponowałem tam również jego udoskonaloną wersję. Szablon opisany w tym wpisie może być jednak z powodzeniem stosowany do prostszych aplikacji.
2 komentarze:
Ostatnio trafiłem na świetną aplikację związaną z analizowaniem sekwencji wideo w czasie rzeczywistym. Autor miał naprawdę dobry pomysł i efekt jest bardziej niż zachwycający. Polecam obejrzeć: http://www.wired.com/gadgetlab/2011/04/predator-smart-camera-locks-on-tracks-anything-mercilessly/
Pozdrawiam.
Widziałem już ten filmik kilka dni temu :-) Pomimo tego, że system również zrobił na mnie wrażenie, autor jeszcze kilka dni temu nie udostępniał kodów źródłowych. Teraz widzę, że są one już dostępne. Jak znajdę chwile czasu to je przetestuję. Szkoda tylko, że kod jest pisany w C i Matlabie. Zawsze to czyni go mniej przenośnym.
Prześlij komentarz