Algorytmy przetwarzania obrazów

Wielkość: px
Rozpocząć pokaz od strony:

Download "Algorytmy przetwarzania obrazów"

Transkrypt

1 Algorytmy przetwarzania obrazów i wstȩp do pracy z bibliotek a OpenCV Pod redakcj a: Ewarysta Rafajłowicza Wojciecha Rafajłowicza Andrzeja Rusieckiego

2

3 Algorytmy przetwarzania obrazów i wstȩp do pracy z bibliotek a OpenCV Pod redakcj a: Ewarysta Rafajłowicza Wojciecha Rafajłowicza Andrzeja Rusieckiego OFICYNA WYDAWNICZA POLITECHNIKI WROCŁAWSKIEJ WROCŁAW 2009

4 Autorzy rozdziałów: Kiełbicki Paweł Pajek Jakub Pietrowski Bartłomiej Wojciech Rafajłowicz Andrzej Rusiecki Sałata Marcin Recenzent Krzysztof Gałkowski Opracowanie redakcyjne i korekta Hanna Jurek Skład komputerowy Wojciech Myszka Wojciech Rafajłowicz Ewaryst Rafajłowicz Projekt okładki Ewaryst Rafajłowicz c Copyright by Oficyna Wydawnicza Politechniki Wrocławskiej, Wrocław 2009 OFICYNA WYDAWNICZA POLITECHNIKI WROCŁAWSKIEJ Wrocław, Wybrzeże Wyspiańskiego 27 ISBN Drukarnia Oficyny Wydawniczej Politechniki Wrocławskiej. Zam

5 Spis treści Od redaktorów Rozdział 1. Instalacja biblioteki, Wojciech Rafajłowicz Instalacja linux Instalacja pakietów Kompilacja biblioteki Kompilacja pierwszego programu System Windows Dev-C Kompilator GCC Obsługa kompilatora Optymalizacja Długość słowa GNU Debugger Rozdział 2. Podstawy konstrukcji biblioteki, Wojciech Rafajłowicz Obraz w pamięci komputera Zasady przyjęte w bibliotece Zarządzanie pamięcią Inne typy danych stosowane w bibliotece Tworzenie i usuwanie obrazów cvcreateimage cvcreateimageheader cvreleaseimage cvreleaseimageheader cvcloneimage Wczytywanie i zapisywanie obrazów cvloadimage cvsaveimage Tworzenie GUI Obsługa okien Obsługa myszy Obsługa suwaków

6 4 Spis treści Rozdział 3. Podstawowe operacje na obrazach, Wojciech Rafajłowicz Dostęp do pikseli Funkcje biblioteki Dostęp bezpośredni Fragmenty obrazu Dostęp ROI Algebra liniowa Mnożenie przez skalar Operator liniowy Inne operacje Rysowanie Reprezentacja punktu Reprezentacja prostokąta Typy linii cvline cvrectangle cvcircle Tekst cvinitfont cvputtext cvgettextsize Przykład Rozdział 4. Podstawowe transformacje, Andrzej Rusiecki Dokładniejszy odczyt fragmentów obrazu cvsampleline cvgetrectsubpix cvgetquadranglesubpix Transformacje cvresize cvwarpaffine cvgetaffinetransform cv2drotationmatrix cvwarpperspective cvgetperspectivetransform cvremap cvlogpolar Rozdział 5. Krawędzie i wierzchołki, Andrzej Rusiecki Detekcja krawędzi cvsobel cvlaplace cvcanny

7 Spis treści Detekcja wierzchołków cvprecornerdetect cvcornereigenvalsandvecs cvcornermineigenval cvcornerharris cvfindcornersubpix cvgoodfeaturestotrack Rozdział 6. Progowanie, Bartłomiej Pietrowski Funkcja cvthreshold Progowanie binarne Odwrócone progowanie binarne Progowanie okrawające Progowanie do zera Przykłady zastosowań Przykłady standardowe Zastosowanie do wykrywania defektów Rozdział 7. Operacje morfologiczne, Andrzej Rusiecki Element strukturalny cvcreatestructuringelementex cvreleasestructuringelement Erozja, dylatacja i ich kombinacje cverode cvdilate cvmorphologyex Rozdział 8. Detekcja ruchu i jej zastosowania, Paweł Kiełbicki i Marcin Sałata Informacje wprowadzające Przepływ optyczny metoda Lucas Kanade Funkcja cvcalcopticalflowlk Przykłady standardowe Przykłady zastosowań w monitorowaniu jakości produkcji Metoda dopasowywania bloków cvcalcopticalflowbm Zastosowania Rozdział 9. Bezcieniowa detekcja ruchu, Jakub Pajek MDetAllocateResources MDetDetectMotion MDetFreeResources Standardowe przykłady Bibliografia Skorowidz

8

9 Od redaktorów Oddawana w ręce Czytelnika książka opisuje wybrane algorytmy przetwarzania obrazów cyfrowych, a więc takich, których dostarczają nasze aparaty fotograficzne, kamery czy nawet telefony komórkowe. Jednakże przeznaczona jest ona dla Czytelników, którzy albo zechcą, choćby w zarysie, poznać działanie takich algorytmów, albo sami podejmą próbę stworzenia oprogramowanie do przetwarzania obrazów. Cegiełkami składowymi takiego oprogramowania mogą być funkcje biblioteki OpenCV, której elementy tutaj opisujemy. Warunkiem korzystania z niej, jest jednak podstawowa znajomość języka C. Biblioteka OpenCV została stworzona przez programistów firmy, która jest liderem na światowym rynku mikroprocesorów, a licencja pozwala na jej używanie oraz modyfikowanie i to zarówno do celów prywatnych, jak i komercyjnych. W tym kontekście trzeba zaznaczyć, że głównym źródłem przykładów w tej książce są problemy przetwarzania obrazów przemysłowych, w tym zwłaszcza takich, które powstają w trakcie kontroli jakości. Opisane tutaj procedury wejdą w skład modułowego systemu wizyjnego, który powstaje w Instytucie Informatyki, Automatyki i Robotyki Wydziału Elektroniki Politechniki Wrocławskiej w ramach projektu badawczo-rozwojowego, realizowanego w latach , który jest finansowany przez Ministerstwo Nauki i Szkolnictwa Wyższego. Czytelnik, poszukujący informacji o algorytmach przetwarzania obrazów, może ograniczyć się do przeczytania podrozdziałów zatytułowanych Uwagi na temat algorytmu. Są one końcowym fragmentem opisu każdego z algorytmów przedstawianych w tej książce. Należy jednak zaznaczyć, że w jednej książce nie sposób opisać wszystkich funkcji zawartych w bibliotece OpenCV. Musieliśmy zatem dokonać wyboru 1, kierując się z jednej strony wymogiem opisania funkcji podstawowych, potrzebnych w większości zastosowań, z drugiej zaś, zamysłem wykorzystania ich do przetwarzania obrazów przemysłowych. 1 Planowane jest wydanie drugiej książki, w której opiszemy modułowy system wizyjny, bazujący na procedurach opisanych w tej książce. Książka ta zawierać będzie także opisy dalszych procedur OpenCV oraz opisy metod i procedur naszego autorstwa.

10 8 Od redaktorów Czytelnik, chcący pogłębić swoją wiedzę na temat przetwarzania obrazów, może sięgnąć do bogatej literatury przedmiotu. Na polskim rynku wydawniczym ukazały się znakomicie napisane książki, które podajemy w kolejności alfabetycznej [6], [22], [24], [37]. Liczba książek w języku angielskim jest wielokrotnie większa, więc wymienimy tylko kilka: [18], [7], [19], [27], [12]. Czytelnik zainteresowany implementacjami algorytmów przetwarzania obrazów powinien zapoznać się z kilkoma pierwszymi rozdziałami na temat instalacji biblioteki OpenCV i jej struktury oraz z procedurami tworzenia, odczytu i wyświetlania obrazów. Opisy pozostałych funkcji można przeglądać względnie niezależnie, pamiętając jednak, że często użycie jednej z procedur wymaga wywołania kilku innych. Powiązania tego typu wskazywane w opisie każdej z funkcji, a zawarty na końcu książki indeks opisanych funkcji powinien ułatwić ich znalezienie. Biblioteka OpenCV dostępna jest pod adresem: projects/opencvlibrary natomiast źródłowe wersje programów testowych oraz funkcji opisanych w ostatnim rozdziale tej książki znajdzie Czytelnik na serwerze: Ewaryst Rafajłowicz Andrzej Rusiecki Wojciech Rafajłowicz

11 Rozdział 1 Instalacja biblioteki i pierwszy program Rozdział ten zawiera wstępne informacje na temat instalacji biblioteki OpenCV. Omówiono także podstawy korzystania z kompilatora GNU GCC ze szczególnym uwzględnieniem możliwości optymalizacji kodu wynikowego. Rozdział kończy się przeglądem możliwości znajdowania błędów w programach za pomocą GNU Debuggera Instalacja linux Instalacja biblioteki w systemach opartych na jądrze Linux może przebiegać na dwa sposoby. Najprostszym jest instalacja z gotowych pakietów dystrybucji. Drugim, trudniejszym jest kompilacja z kodu źródłowego. W obu przypadkach instalacja wymaga przywilejów administratora (użytkownik root). Istnieje możliwość instalacji biblioteki (z kodu źródłowego) wyłącznie dla jednego użytkownika, nie będzie ona tutaj jednak omawiana Instalacja pakietów Pakiety Open CV w systemie Debian podzielone są na trzy rodzaje. libcv1 i libhighgui1 zawierają wersje run-time biblioteki konieczne do uruchomienia programów libcv-dev i libhighgui-dev zawierają nagłówki konieczne do kompilacji własnych programów opencv-doc zawiera dokumentację W celu uruchomienia przykładów z niniejszej książki konieczne są pierwsze dwie grupy. Najlepiej jednak zainstalować również oryginalną, angielską dokumentację. Najprostszym sposobem instalacji jest użycie programu apt w następujący sposób: #apt-get install libcv1 libhighgui1 libcv-dev \ libhighgui-dev opencv-doc

12 10 Rozdział 1. Instalacja biblioteki i pierwszy program Po wprowadzeniu podanego polecenia system prawdopodobnie zapyta się o instalację dodatkowych wymaganych pakietów. Należy odpowiedzieć TAK. W systemach Ubuntu, gdzie konto root nie istnieje, linia poleceń wygląda trochę inaczej $sudo apt-get install libcv1 libhighgui1 libcv-dev \ libhighgui-dev opencv-doc W takim przypadku najpierw należy podać hasło Kompilacja biblioteki Jeżeli nasz system nie zawiera pakietu z biblioteką lub zawiera jej starszą wersję, 1 należy bibliotekę skompilować samodzielnie. Do tego celu konieczne są następujące programy i biblioteki (wraz z nagłówkami itp.) GCC 2 Python 2.3, 2.4 lub 2.5 GTK+ 2.x lub wyższa wraz z nagłówkami pkgconfig libpng, zlib, libjpeg, libtiff, libjasper ffmpeg itp. jeżeli zamierzamy korzystać Kod źródłowy najlepiej pobrać ze strony projektu projects/opencv/. Kompilacja przebiega standardowo, przez wywołanie $./configure $make $make check #make install #ldconfig Jeżeli do tej pory ścieżki do kartoteki z biblioteką (standardowo /usr/local/ lib nie zostały ustawione, to należy do pliku /etc/ld.so.conf dodać linię z tą ścieżką Kompilacja pierwszego programu Jeżeli zainstalowaliśmy już bibliotekę (metodą opisaną w punkcie lub 1.1.2), możemy przystąpić do kompilacji pierwszego programu. Program ten otwiera okno i wyświetla w nim obraz pobrany z pliku. 1 Dotyczy to np. Debian GNU/Linux 4.0 Etch, będącego wersją stabilną w czasie pisania tej książki. 2 Autor nie testował innych kompilatorów C.

13 1.1. Instalacja linux 11 /* prog1.c * Pierwszy program wykorzystujący bibliotekę OpenCV */ #include "cv.h" #include "highgui.h" int main() { IplImage *cvsourceimg = NULL; /* Czynności wstępne */ /* Odczytaj obraz, wymuś konwersje na odcienie szarości */ cvsourceimg = cvloadimage("lena.jpg", 0); /* Otwórz okienka na obraz źródłowy i wyświetl go*/ cvnamedwindow("lena", 1); cvshowimage("lena", cvsourceimg); cvwaitkey(0); cvdestroywindow("lena"); return(0); Kompilacji dokonujemy następująco 3 : $gcc -o prog1 prog1.c -I/usr/include/opencv -lcv -lhighgui Jeżeli wszystko przebiegło poprawnie, powinniśmy uzyskać program prog1. Po jego uruchomieniu powinniśmy uzyskać widok przedstawiony na rys Ponieważ wielokrotne wpisywanie długiego polecenia jest żmudne, można ułatwić sobie pracę wykorzystując program make. Po stworzeniu pliku Makefile o zawartości # Makefile # Uniwersalny makefile dla biblioteki OpenCV.c: gcc $< -o $@ -Wall -I/usr/local/include/opencv \ -lm -lcv -lhighgui -g kompilacja odbywa się przez make prog1. 3 W dalszej części książki zakładamy, że instalacji dokonano z pakietów. Jeżeli biblioteka była kompilowana, należy zmienić ścieżkę na zależną od miejsca instalacji.

14 12 Rozdział 1. Instalacja biblioteki i pierwszy program Rysunek 1.1. Wynik działania pierwszego programu 1.2. System Windows Wersję instalacyjną dla Windows można pobrać ze strony projektu http: //sourceforge.net/projects/opencv/. Instalacja przebiega standardowo i nie sprawia trudności. Następnie należy ustawić ścieżki w IDE Dev-C++ Do pracy z biblioteką OpenCV autor niniejszego rozdziału poleca środowisko Dev-C++. Korzysta ono z kompilatora GCC. Widok okna przedstawiono na rysunku 1.2. W środowisku Dev-C++ należy ustawić ścieżki w Tools Compiler Options. Najpierw podajemy, gdzie znajdują się pliki nagłówkowe. Należy podać co najmniej cv.h, highgui.h oraz cxcore.h. Odpowiednie ścieżki przedstawiono na rys Później podajemy ścieżki do bibliotek (rys. 1.4) oraz nazwy tych bibliotek (rys. 1.5). Środowisko Dev-C++ umożliwia również obsługę projektów. Wtedy część opcji można przenieść do pliku opisującego projekt. Umożliwia to dołączanie tylko potrzebnych w danym programie bibliotek. Można spróbować importu przykła- 4 W przypadku środowiska Cygwin należy postępować jak dla

15 1.2. System Windows 13 Rysunek 1.2. Okno środowiska Dev-C++ Rysunek 1.3. Ścieżki dostępu do bibliotek w środowisku Dev-C++

16 14 Rozdział 1. Instalacja biblioteki i pierwszy program Rysunek 1.4. Deklaracje używanych bibliotek Rysunek 1.5. Parametry programu łączącego nakazujące dołączanie procedur z bibliotek

17 1.3. Kompilator GCC 15 dowego projektu dostarczonego z OpenCV. W standardowej instalacji znajduje się on w C:\Program Files\OpenCV\samples\c pod nazwą cvsample.dsp. Dodatkowo należy upewnić się, czy system jest w stanie znaleźć biblioteki dll z OpenCV. Jeżeli nie, to należy je umieścić w tym samym folderze, w którym jest uruchamiany program lub w C:\WINDOWS\SYSTEM Kompilator GCC Kompilator C z pakietu GNU Compilers Collection jest optymalizującym kompilatorem dostosowanym do wielu platform sprzętowych. Przykłady zawarte w rozdziałach 1, 2, 3 kompilowane były tym kompilatorem. Biblioteka OpenCV zaprojektowana jest do współpracy z różnymi kompilatorami i systemami operacyjnymi. Rozdział opisuje jak efektywnie wykorzystać GCC w przetwarzaniu obrazów Obsługa kompilatora Kompilator GCC obsługuje się w sposób standardowy dla kompilatorów w systemach UNIX. Dalej omówimy tylko niektóre z nich. Za przykład posłuży wywołanie z rozdziału $gcc -o prog1 prog1.c -I/usr/include/opencv -lcv -lhighgui W tym przypadku -o określa nazwę pliku wynikowego prog1.c bez parametru oznacza nazwę pliku źródłowego -I dodatkowe miejsce poszukiwania plików nagłówkowych -lcv -lhighgui dołącza biblioteki CV i HighGUI konieczne podczas kompilacji Dodatkowo należy zwrócić uwagę na opcje: -lm dołączenie biblioteki matematycznej (z powodów historycznych funkcje zadeklarowane w math.h nie są standardowo dołączane), -g włączenie symboli do debugowania (patrz rozdział 1.3.4), -Wall włącza wszystkie ostrzeżenia, zwykle wykrywa część typowych błędów związanych z nazwami funkcji, wskaźnikami itp. -O optymalizacja patrz rozdział Kompilator umożliwia rozdzielenie programu na kilka oddzielnych zbiorów. Można kompilować wszystkie pliki jednocześnie $gcc -o program plik1.c plik2.c plik3.c lub odzielnie, tylko w razie potrzeby. W takiej sytuacji generujemy plik.o za pomocą opcji -c

18 16 Rozdział 1. Instalacja biblioteki i pierwszy program $gcc -c plik1.c powstaje plik1.o. Powtarzamy dla kolejnych plików. Do połączenia skompilowanych fragmentów stosujemy również polecenie gcc 5. Możemy skorzystać również z możliwości hybrydowej część plików została już skompilowana, część nie. $gcc -o program plik1.o plik2.o plik3.c Optymalizacja Celem optymalizacji jest polepszenie jakości kodu (zwykle przez kompilator). Ocena jakości kodu zależy od okoliczności. W naszym przypadku (przetwarzanie obrazów) najlepszy kod, to kod najszybszy. Kompilator GCC oferuje wiele możliwości optymalizacji kodu włączanych dużą (być może nawet zbyt dużą) liczbą przełączników przy jego wywołaniu. Najczęściej używane opcje zostały pogrupowane w następujący sposób: -O, -O1 podstawowa optymalizacja, kompilator próbuje zwiększyć wydajność oraz zmniejszyć rozmiar programu wynikowego, -O2 optymalizacja skoncentrowana na wydajności, kompilator próbuje ją powiększyć, nie zwiększając programu wynikowego, -O3 optymalizacja agresywna, nie obowiązuje ograniczenie wielkości programu, -Os optymalizacja wielkości programu, -O0 wyłącz optymalizację. Dodatkowo trzeba rozważyć użycie opcji -funroll-loops, która rozwija pętle o znanej z góry liczbie iteracji. Opcja ta może (ale nie w każdym przypadku musi) przyspieszyć kod. Trzeba też zauważyć, że GCC domyślnie generuje kod wykonywalny dostosowany do procesora 386 lub 686 (Pentium Pro). Zapewnia to przenośność binariów, ale nie wykorzystuje pewnych możliwości procesora. Opcja -mtune=native generuje kod dostrojony do aktualnego procesora (na innym też się uruchomi). Opcja march=native wykorzystuje wszystkie instrukcje używanego procesora (jeżeli inny procesor ich nie obsługuje, kod nie będzie działał). Do porównania poszczególnych opcji wykorzystamy podany program. Wykonuje on operację znajdowania minimum ze specjalnym rodzajem progowania, którego nie będziemy tu opisywać. Do uzyskania większej rozróżnialności wyników funkcja uruchamiana jest 100 razy 5 Istnieje również program łączący (ang. linker), jednak samodzielnie jest rzadko stosowany

19 1.3. Kompilator GCC 17 /* opt.c */ #include "cv.h" #include "highgui.h" void mspo_vert_mean(iplimage *in, IplImage *out, int box_width, int H); char mspo_vert_meani(cvmat *mat, int H, int x); int main() { IplImage *in = cvloadimage("lena.jpg", 0); IplImage *out = cvcreateimage(cvsize(in->width, in->height), 8, 1); int i; for (i = 0; i < 100; ++i) mspo_vert_mean(in, out, 3, 13); return(0); void mspo_vert_mean(iplimage *in, IplImage *out, int box_width, int H) { if ((box_width <= 0) (H < 0) (in == 0) (out == 0)) abort(); int bwr = 2 * box_width + 1; // prawdziwa szerokość // horyzontalnego okna CvRect rect = cvrect(0, 0, bwr, bwr); cvcopy(in, out, 0); int i, j; // po x, po y int el_sr_mac = (bwr / 2) * bwr + bwr / 2 + 1; CvMat *mat = cvcreatemat(bwr, bwr, CV_8SC1); for (j = 0; j < in->height - bwr; ++j) for (i = 0; i < in->width - bwr; ++i) { // pobieramy okienko rect.x = i; rect.y = j; cvgetsubrect(in, mat, rect);

20 18 Rozdział 1. Instalacja biblioteki i pierwszy program // przetwarzamy wycinek out->imagedata[(j + bwr) * in->width + i + bwr] = mspo_vert_meani(mat, H, el_sr_mac); char mspo_vert_meani(cvmat *mat, int H, int x) { int a, b, s, n; // po x,po y,średnia (tymczasowa), // ilość wyb. s = 0; n = 0; uchar el_sr = mat->data.ptr[x]; for (a = 0; a < mat->cols; ++a) for (b = 0; b < mat->rows; ++b) if (abs(el_sr - mat->data.ptr[a * mat->cols + b]) < H) { s += mat->data.ptr[a * mat->cols + b]; n++; s /= n; return(s); Porównajmy czas wykonania z różnymi wersjami optymalizacji. Opcja Czas [s] -O0 24,996 -O1 13,686 -O2 12,913 -O3 12,775 -O3 -funroll-loops 11,674 -mtune=native 24,865 -march=native 25,198 -march=native -O2 12,800 Widzimy więc, że optymalizacja do poziomu -O2 jest jak najbardziej wskazana. Dalsze zwiększanie poziomu optymalizacji, lub dostosowywanie się do architektury nie daje istotnej poprawy, a w pewnych przypadkach może przynieść wydłużenie czasu obliczeń.

21 1.3. Kompilator GCC Długość słowa Od czasu wprowadzenia architektury AMD64 (w wersji Intel EM64T) pojawiają się różne opinie dotyczące wzrostu wydajności w wyniku stosowania 64-bitowego słowa maszynowego. W celu zweryfikowania tych opinii, zbadano program z rozdziału Stosowano dwa komputery z procesorami o szybkości około 4800 bogomips (patrz [10]) przy poziomie optymalizacji -O2. Uzyskano następujące wyniki: Liczba bitów Czas wykonania 32 8, ,320 Zaobserwować można pewne przyspieszenie obliczeń, lecz nie jest ono duże. Dodatkowym aspektem wpływającym na wybór procesora jest dostępność sterowników 64-bitowych GNU Debugger Po napisaniu i skompilowaniu programu jego uruchomienie nie zawsze daje spodziewane rezultaty. Powstałe błędy można podzielić na dwa rodzaje błędy wykonania (program nie działa), błędy merytoryczne (program wprawdzie wykonuje obliczenia, lecz daje niepoprawne wyniki). Debuggery (programy uruchomieniowe) ułatwiają eliminację błędów (szczególnie tych rodzaju pierwszego). Program taki nadzoruje wykonywanie badanego programu. Umożliwia on, między innymi, przerywanie pracy programu w wybranym miejscu (breakpoint), śledzenie zmian wartości wybranych zmiennych (trace), przeglądanie pamięci (a więc i wartości zmiennych) wtedy, gdy program nie pracuje, wskazuje miejsce błędu wykonania. Ostatnia z tych właściwości jest szczególnie często wykorzystywana. Najczęstszym błędem programów napisanych w języku C jest błąd segmentacji (ang. segmentation fault). Błąd ten oznacza próbę dostępu do niedozwolonego obszaru pamięci. Obsługa programu Przed wywołaniem programu należy dołączyć do niego dane do odpluskwiania. Czyni się to przez dodanie opcji -g lub -ggdb. Wersja pierwsza dołącza powszechnie zrozumiałe symbole (można używać innego programu). Wersja druga dołącza symbole specyficzne dla gdb i zawiera więcej informacji.

22 20 Rozdział 1. Instalacja biblioteki i pierwszy program Rysunek 1.6. Interfejs debugera Po dodaniu symbolu uruchamiamy program $gdb./opt i widzimy interaktywny interfejs (tekstowy) przedsatwiony na rysunku 1.6 Przykład pracy z GDB Rozpatrzmy następujący program zawierający błąd /* sigseg.c */ #include <stdio.h> #include <stdlib.h> int main() { int *i; i = (int *)malloc(sizeof(int)); i = 5; printf("%d\n", *i); return(0);

23 1.3. Kompilator GCC 21 Widzimy, że zamiast przypisać liczbę 5 komórce pamięci wskazywanej przez i, przypisaliśmy tę liczbę jako adres. Poniżej pokazano przykładową sesję gdb. $ gcc -o sigseg sigseg.c -ggdb sigseg.c: In function main : sigseg.c:9: warning: assignment makes pointer from integer without a cast $./sigseg Segmentation fault $ gdb./sigseg GNU gdb debian Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i486-linux-gnu"...using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1". (gdb) r Starting program:./sigseg Program received signal SIGSEGV, Segmentation fault. 0x080483be in main () at sigseg.c:10 10 printf("%d\n",*i); (gdb) l 5 int main() 6 { 7 int *i; 8 i = (int *) malloc(sizeof(int)); 9 i = 5; 10 printf("%d\n",*i); 11 return(0); 12 (gdb) print i $1 = (int *) 0x5 (gdb)

24 22 Rozdział 1. Instalacja biblioteki i pierwszy program Po stwierdzeniu błędu uruchomiono gdb. Polecenie run zostało użyte w formie krótkiej r. Program został uruchomiony bez parametrów. W chwili napotkania błędu wykonanie zostało zatrzymane, linia programu zawierająca błąd została wyświetlona. Ponieważ nie zawiera nic podejrzanego (błędny jest adres we wskaźniku), wyświetlono okoliczne linie (polecenie list, skrócone do l). Wyświetlono następnie podejrzany wskaźnik poleceniem print (można skrócić do p). Nawet w tym ograniczonym zakresie gdb jest pożytecznym narzędziem. Dokładny opis jego możliwości zawiera polecenie help oraz dokumentacja texinfo.

25 Rozdział 2 Podstawy konstrukcji biblioteki Rozdział ten przedstawia podstawowe elementy potrzebne do korzystania z biblioteki OpenCV, począwszy od reprezentacji obrazu i zasad zarządzania pamięcią. Krok po kroku opisano procedury tworzenia i usuwania obrazów oraz ich wczytywania i zapisu. Opisano także proste procedury tworzenia graficznego interfejsu użytkownika, który może uwzględniać obsługę myszy, tworzenie okien oraz tak zwanych suwaków. Suwaki te, to bardzo pomocne narzędzie, które może służyć do zmiany parametrów algorytmów przetwarzania obrazów już w trakcie ich pracy. Dzięki temu możliwy jest interakcyjny dobór parametrów przetwarzania na podstawie oglądu wyników działania algorytmu Obraz w pamięci komputera W praktyce przetwarzania obrazów zakłada się zwykle, że obraz ma postać macierzy. Większość algorytmów dostosowana jest do przetwarzania obrazów w odcieniach szarości. Elementami macierzy są liczby, z zakresu 0 1 lub 0 255, reprezentujące poszczególne odcienie, przy czym zwykle 0 odpowiada odcieniowi czarnemu, a wartość maksymalna białemu. Pamięć komputera ma charakter liniowy. Należy więc przyjąć konwencję zapisu macierzy w postaci ciągu liczb. Zwykle, w tym także w OpenCV, przyjmuje się zapis poszczególnych wierszy jeden za drugim, zaczynając od górnego wiersza. Rozpatrzmy przykład, macierz zapisujemy jako a 11 a 12 a 13 a 21 a 22 a 23 a 31 a 32 a 33 a 11, a 12, a 13, a 21, a 22, a 23, a 31, a 32, a 33 Sytuacja dla obrazów kolorowych jest analogiczna, jednak elementami macierzy są trójki liczb.

26 24 Rozdział 2. Podstawy konstrukcji biblioteki Dostęp do elementów macierzy wymaga prostych operacji arytmetycznych 1. a xy = A [y width + x] Biblioteka OpenCV korzysta z formatu IplImage, będącego obecnie quasi- -standardem w przetwarzaniu obrazów. Format ten jest następującą strukturą w języku C. typedef struct _IplImage { int nsize; /* sizeof(iplimage) */ int ID; /* version (=0) */ int nchannels; /* Most of OpenCV functions support 1,2,3 or 4 channels */ int alphachannel; /* ignored by OpenCV */ int depth; /* pixel depth in bits: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U, IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F and IPL_DEPTH_64F are supported */ char colormodel[4]; /* ignored by OpenCV */ char channelseq[4]; /* ditto */ int dataorder; int origin; /* 0 - interleaved color channels, 1 - separate color channels. cvcreateimage can only create interleaved images */ /* 0 - top-left origin, 1 - bottom-left origin (Windows bitmaps style) */ int align; /* Alignment of image rows (4 or 8). OpenCV ignores it and uses widthstep instead */ int width; /* image width in pixels */ int height; /* image height in pixels */ struct _IplROI *roi; /* image ROI. when it is not NULL, this specifies image region to process */ struct _IplImage *maskroi; /* must be NULL in Open CV */ void *imageid; /* ditto */ 1 Wygodnie jest przyjąć konwencję, zgodnie z którą width oznacza szerokość, a height wysokość.

27 2.2. Zasady przyjęte w bibliotece 25 struct _IplTileInfo *tileinfo; /* ditto */ int imagesize; /* image data size in bytes (=image->height* image->widthstep in case of interleaved data) */ char *imagedata; /* pointer to aligned image data */ int widthstep; /* size of aligned image row in bytes*/ int BorderMode[4]; /* border completion mode, ignored by OpenCV */ int BorderConst[4]; /*ditto */ char *imagedataorigin;/*pointer to a very origin of image data (not necessarily aligned) it is needed for correct image deallocation */ IplImage; OpenCV wykorzystuje tylko pewną część możliwości struktury IplImage. Dalej znajduje się omówienie pól wykorzystywanych zwykle przez użytkownika. nchannels liczba kanałów, co zwykle oznacza liczbę kolorów w obrazie, depth rodzaj pojedynczego piksla w kanale, który może przyjąć wartości: 1. IPL_DEPTH_8U, IPL_DEPTH_8S 8 bitów (typ char) bez znaku lub ze znakiem, 2. IPL_DEPTH_16U, IPL_DEPTH_16S 16 bitów bez znaku lub ze znakiem, 3. IPL_DEPTH_32S 32 bity całkowite bez znaku, 4. IPL_DEPTH_32F liczba zmiennoprzecinkowa 32-bitowa, 5. IPL_DEPTH_64F liczba zmiennoprzecinkowa 64-bitowa, width szerokość obrazu, height wysokość obrazu, imagesize rozmiar obrazu w bajtach, *imagedata wskaźnik na tablicę z obrazem, widthstep długość pojedynczej linii obrazu (w bajtach). Pozostałe parametry nie są wykorzystywane w OpenCV bądź ich przydatność jest niewielka Zasady przyjęte w bibliotece Autorzy biblioteki OpenCV przyjęli pewne zasady nazewnictwa, które zwykle są przestrzegane. Część z nich ujęto następująco:

28 26 Rozdział 2. Podstawy konstrukcji biblioteki funkcje zaczynają się od prefiksu cv, stosowany jest tzw. CamelCasing, zwykle jedna funkcja grupuje kilka rodzajów przetwarzania podobnego typu, parametry funkcji podawane są w kolejności: 1. Obraz źródłowy. 2. Obraz docelowy. 3. Rodzaj przetwarzania. 4. Pozostałe parametry. Reguły tej nie stosują funkcje alokacji pamięci Zarządzanie pamięcią W przetwarzaniu obrazów zarządzanie pamięcią jest ważną kwestią. Dotyczy to szczególnie przetwarzania strumieni obrazów. Znaczącym problemem, dotykającym wszystkie programy w C, są wycieki pamięci. Niestety część funkcji OpenCV zawiera ten rodzaj błędu. Program wprawdzie przeprowadza zadane obliczenia, lecz w trakcie jego pracy następuje stopniowe wyczerpywanie się zasobów pamięci systemu. W konsekwencji, po pewnym czasie pracy programu następuje zużycie całej dostępnej pamięci. W systemach monitorowania jakości produkcji, w systemach nadzoru i w innych systemach, które powinny pracować poprawnie w długich okresach, takie zachowanie się programu nie jest dopuszczalne i dlatego zagadnieniu wycieków pamięci poświęcono w tej książce wiele uwagi. Obraz w OpenCV (jego strukturę omówiono w 2.1) musi zostać zaalokowany przed rozpoczęciem na nim jakichkolwiek operacji. Alokacja może nastąpić przez: pobranie obrazu z dysku (patrz 2.4.1) lub kamery, utworzenie nowego obrazu, utworzenie nagłówka obrazu i pobranie *imagedata z innego miejsca Inne typy danych stosowane w bibliotece CvScalar Typ CvScalar przeznaczony jest do zapisu informacji, składającej się od jednej do czterech liczb. Liczby te przechowywane jako typ double. typedef struct CvScalar { double val[4]; CvScalar;

29 2.2. Zasady przyjęte w bibliotece 27 CvArr Użycie CvArr oznacza, że funkcja akceptuje więcej niż jeden typ danych (zwykle IplImage oraz CvMat). CvMat Jest to macierz. Typ ten może być stosowany zamiast IplImage, zawiera jednak mniej informacji o obrazie. typedef struct CvMat { int type; /* Określenie typu */ int step; /* długość wiersza w bajtach */ int* refcount; union { uchar* ptr; short* s; int* i; float* fl; double* db; data; /* wskaźniki do danych */ #ifdef cplusplus union { int rows; int height; ; union { int cols; int width; ; #else int rows; /* ilość kolumn */ int cols; /* ilość wierszy */ #endif CvMat;

30 28 Rozdział 2. Podstawy konstrukcji biblioteki 2.3. Tworzenie i usuwanie obrazów cvcreateimage Tworzy nowy, pusty obraz. Utworzony zostaje nagłówek i zaalokowana pamięć na dane (*imagedata). IplImage* cvcreateimage(cvsize size, int depth, int channels); size struktura CvSize określająca rozmiar. Do jej utworzenia można wykorzystać funkcję cvsize(width, height), gdzie width, height ozanczają szerokość i wysokość obrazu. depth typ podstawowej jednostki określającej piksel, lista znajduje się w opisie IplImage channels liczba kolorów w obrazie, tworzony obraz jest przeplatany (kolejno (b0, g0, r0), (b1, g1, r1),... ) cvcreateimageheader Funkcja tworzy wyłącznie nagłówek obrazu, nie alokuje miejsca na dane. Jest to przydatne wtedy, gdy dysponujemy obrazem z innego źródła (np. kamera) w odpowiednim formacie. IplImage* cvcreateimageheader(cvsize size, int depth, int channels); Parametry funkcji są takie jak dla cvcreateimage cvreleaseimage Usuwa obraz i zwalnia pamięć. void cvreleaseimage(iplimage** image); Parametr image określa obraz, który należy zwolnić. Trzeba zwrócić uwagę, że jest to wskaźnik do wskaźnika. Jeżeli chcemy zwolnić obraz zadeklarowany jako IplImage *img, to stosujemy cvreleaseimage(&img); cvreleaseimageheader Zwalnia nagłówek obrazu, nie zwalnia *imagedata, jednak wskaźnik ten zostaje utracony. Nieuważne użycie tej funkcji prowadzi do wycieku pamięci.

31 2.4. Wczytywanie i zapisywanie obrazów 29 void cvreleaseimageheader(iplimage** image); Parametry są takie, jak dla cvreleaseimage cvcloneimage Tworzy dokładną kopię obrazu. IplImage* cvcloneimage(const IplImage* image); image obraz do kopiowania. Funkcja zwraca kopię obrazu Wczytywanie i zapisywanie obrazów Obrazy zapisane na dysku twardym lub innym urządzeniu pamięci masowej mają określony format. Dodatkowo, w celu oszczędności miejsca, mogą być kompresowane. W tym miejscu zajmujemy się jedynie formatami bitmapowymi, tj. opisującymi każdy piksel 2, formaty te można podzielić na trzy rodzaje: bez kompresji formaty te zawierają dokładny obraz, każda liczba jest zapisana w pamięci, a przykładami obecnie stosowanych formatów są: bmp tiff ppm, pgm, pbm kompresja bezstratna obraz zostaje skompresowany standardowym algorytmem kompresji, takim jak kod Huffmana, RLE czy LHARC 3 przykładami takich formatów są: png gif kompresja stratna powoduje usunięcie części informacji 4 obecnie najczęściej stosowany jest format jpeg. Biblioteka OpenCV zawiera funkcje do zapisu i odczytu obrazów w następujących formatach (podano nazwy i rozszerzenia plików): 1. bitmapy Windows BMP, DIB 2. JPEG JPEG, JPG, JPE 2 Oddzielną grupę stanowią formaty wektorowe zapisujące wygląd rysunku (figury geometryczne i ich rozmieszczenie). Formatami takimi jak eps nie zajmujemy się w tej książce. 3 Zastosowanie kompresji jest zwykle opcją wybieraną przy zapisie, jednak część formatów stosuje ją z definicji (nie ma wersji nieskompresowanej). 4 Wykorzystuje się pewne niedoskonałości naszego wzroku, które powodują, że usunięcie części informacji nie jest dostrzegane lub dostrzegane jest bardzo słabo (zależne od stopnia kompresji).

32 30 Rozdział 2. Podstawy konstrukcji biblioteki 3. Portable Network Graphics PNG 4. Portable image format PBM, PGM, PPM 5. Sun rasters SR, RAS 6. TIFF TIFF, TIF Dodatkowo, biblioteka OpenCV zawiera funkcje umożliwiające zapis struktury IplImage na dysk w formacie XML lub YAML. Funkcjami tymi nie będziemy się jednak tutaj zajmować cvloadimage Funkcja cvloadimage umożliwia odczytanie obrazu w jednym z obsługiwanych formatów. Wywołanie ma następującą postać: IplImage* cvloadimage(const char* filename, int iscolor = 1); Znaczenie parametrów jest następujące: filename nazwa pliku zawierającego obraz, typ obrazu zostanie rozpoznany na podstawie rozszerzenia 5, iscolor określa czy obraz jest kolorowy, zgodnie z następującym kodowaniem: > 0 obraz jest jest traktowany jako kolorowy, wynik ma trzy kanały, = 0 obraz jest w odcieniach szarości, jeżeli zachodzi potrzeba następuje konwersja, < 0 to czy obraz jest kolorowy jest ustalane po odczytaniu, liczba kanałów jest taka jak w pliku. Funkcja zwraca zaalokowany obraz jako wynik. Autorzy biblioteki nie byli konsekwentni w obsłudze błędów. Błąd polegający na pustej (zawierającej NULL) nazwie pliku skutkuje komunikatem: OpenCV ERROR: Null pointer (null filename) in function cvloadimage, loadsave.cpp(380) [...] Jeżeli plik nie istnieje lub format nie jest obsługiwany, funkcja zwraca wartość NULL. Pojawia się pytanie: co robić, gdy format nie jest obsługiwany. Najprościej dokonać konwersji obrazu do formatu obsługiwanego przez bibliotekę. Jeżeli dotyczy to kilku obrazów konwersji można dokonać ręcznie w dowolnym programie graficznym, np. GIMP. Jeżeli obrazy chcemy naszemu programowi (korzystającemu z biblioteki Open CV) umożliwić obsługę formatu wektorowego, lub bardziej egzotycznego formatu, nazwy. 5 W systemie Linux to pojęcie formalnie nie występuje, w tym przypadku jest to koniec

33 2.5. Tworzenie GUI 31 mamy dwie możliwości: możemy napisać własną funkcję odczytującą lub automatycznie dokonać konwersji pliku. Do automatycznej konwersji można wykorzystać ImageMagick 6. Dostarcza on prostego w użyciu programu convert oraz bibliotek, które możemy wykorzystać we własnych programach. Obsługa programu convert jest prosta. Przykładowo chcemy przetransformować plik lena.dib w starym formacie dib 7 do formatu png. Piszemy wówczas convert lena.dib lena.png i to wystarczy, gdyż program rozpoznaje typy po rozszerzeniu i dokonuje konwersji. Więcej szczegółów zawiera dokumentacja cvsaveimage Funkcja umożliwia zapis obrazu na dysk. Obraz musi mieć postać 8-bitową. Jeżeli obraz jest kolorowy, wymagane jest, by miał on format RGB z kolejnością kolorów: niebieski, zielony, czerwony (BGR). Funkcja ta obsługuje te same formaty, które wymieniono w opisie cvloadimage. int cvsaveimage(const char* filename, const CvArr* image); filename nazwa pliku, typ ustalany jest na podstawie rozszerzania, image obraz do zapisania. W razie sukcesu funkcja zwraca wartość 1. Jeżeli image jest pusty, lub zapis nie jest możliwy, funkcja ta generuje błąd, przerywający pracę programu Tworzenie GUI Z biblioteką OpenCV złączona jest biblioteka HighGUI. Biblioteka ta umożliwia tworzenie prostego interfejsu użytkownika. Interfejs ten jest przenośny ten sam program, bez modyfikacji, działa zarówno pod Microsoft Windows, jak i pod X Windows System z GTK+. Oferowane funkcje ograniczają się do: obsługi okien: tworzenie okna, zmiana rozmiaru okna, przesuwanie okna, wyświetlania obrazów IplImage, 6 Do pobrania z który występuje jako pakiet w większości dystrybucji Linuxa 7 device independent bitmap wykorzystywana dawniej w Windows (ok. wersji 3.1).

34 32 Rozdział 2. Podstawy konstrukcji biblioteki odczytu klawiatury (z aktywnego okna), obsługi myszy (odczyt położenia i kliknięć), tworzenia prostych suwaków, pobierania uchwytu okna (w Windows HWND, w GTK+ GtkWidget) Obsługa okien Okna w HighGUI określane są przez nazwę, będącą ciągiem znaków. Ciąg ten pojawia się jako tytuł okna. cvnamedwindow Funkcja ta otwiera nowe okno. int cvnamedwindow(const char* name, int flags); name nazwa okna, wyświetlana również jako tytuł, flags flaga CV_WINDOW_AUTOSIZE nakazuje automatycznie dostosowywać rozmiar okna; nie da się wtedy zmieniać jego rozmiaru. cvdestroywindow Zamyka okno o nazwie name void cvdestroywindow(const char* name); cvresizewindow Zmienia rozmiar okna. Nie działa, jeżeli ustawiono flagę CV_WINDOW_AUTOSIZE. void cvresizewindow(const char* name, int width, int height); name nazwa okna, width nowa szerokość, height nowa wysokość. cvmovewindow Przesuwa okno w określone miejsce. Podawane współrzędne dotyczą lewego, górnego rogu. void cvmovewindow(const char* name, int x, int y); name nazwa okna, x współrzędna x lewego, górnego rogu, y współrzędna y lewego, górnego rogu.

35 2.5. Tworzenie GUI 33 cvshowimage Wyświetla obraz. Jeżeli okno ma określony rozmiar, obraz jest skalowany, w przypadku flagi CV_WINDOW_AUTOSIZE zmiena się rozmiar okna. void cvshowimage( const char* name, const CvArr* image ); name nazwa okna, image obraz. Wyświetlenie obrazu w oknie zajmuje pewien czas. Jeżeli używamy tej funkcji do wyświetlania serii obrazów, to pomiędzy wywołaniami najlepiej odczekać co najmniej 10 ms. W tym celu można wykorzystać opisaną dalej funkcję cvwaitkey. cvwaitkey Funkcja czeka na naciśnięcie klawisza i przekazuje wartość. Dotyczy ona wszystkich aktywnych okien biblioteki HighGUI, na innych nie działa. int cvwaitkey(int delay=0); delay czas w ms, jaki należy odczekać, jeżeli podano 0, czeka w nieskończoność. Przykładowy program Możliwości HighGUI w zakresie obsługi okien prezentuje kolejny przykład. Dokonuje on następujących czynności: otwiera okno, powiększa je od rozmiaru 1x1 do 512x512, przesuwa, czeka na naciśnięcie klawisza. /* gui.c */ #include "cv.h" #include "highgui.h" #include <stdio.h> int main() { IplImage *i = 0; int j; i = cvloadimage("lena.jpg", -1); cvnamedwindow("test", 0); cvshowimage("test", i); cvwaitkey(10);

36 34 Rozdział 2. Podstawy konstrukcji biblioteki for (j = 1; j <= 512; ++j) { cvresizewindow("test", j, j); cvwaitkey(10); for (j = 1; j <= 64; ++j) { cvmovewindow("test", j, j); cvwaitkey(10); cvwaitkey(0); cvdestroywindow("test"); return(0); Obsługa myszy Podstawowe idee Do obsługi myszy w OpenCV musimy napisać funkcję, reagującą na zdarzenia takie, jak: ruch myszy, kliknięcie klawisza, naciścięcie klawisza, opuszczenie klawisza. Dodatkowo z podanymi zdarzeniami związana jest możliwość równoczesnego naciśnięcia klawiszy: control, alt, shift. Opiszemy tutaj podstawowe elementy systemu zdarzeń. Opis pozostałych znajduje się w dokumentacji. CV_EVENT_MOUSEMOVE prosty ruch myszy, CV_EVENT_RBUTTONDBLCLK podwójne kliknięcie prawym przyciskiem myszy, CV_EVENT_LBUTTONDBLCLK podwójne kliknięcie lewym przyciskiem myszy. W celu przechwycenia zdarzenia trzeba zarejestrować funkcję obsługi zdarzeń myszy. W HighGUI znajdziemy specjalną funkcję, która umożliwia dokonanie rejestracji: cvsetmousecallback Funkcja ta rejestruje funkcję obsługi zdarzeń myszy.

37 2.5. Tworzenie GUI 35 void cvsetmousecallback(const char* window_name, CvMouseCallback on_mouse, void* param = NULL); window_name nazwa okna, dla którego rejestrujemy funkcję, on_mouse rejestrowana funkcja, param parametr przekazywany do funkcji. Rejestrowana funkcja musi mieć postać: CV_EXTERN_C_FUNCPTR(void (*CvMouseCallback)(int event, int x, int y, intf lags, void *param)); W praktyce sprowadza się to do następującej deklaracji funkcji void Foo(int event, int x, int y, int flags, void* param) Gdy wystąpi jakieś zdarzenie, funkcja zostaje wywołana z następującymi parametrami event zdarzenie, które aktualnie nastąpiło, x współrzędna x pozycji kursora w oknie względem lewego, górnego rogu, y współrzędna y pozycji kursora w oknie względem lewego, górnego rogu, flags kombinacja flag (dokładny opis w dokumentacji), param parametr przekazany podczas wywołania cvsetmousecallback; umożliwia na przykład wykorzystanie tej samej funkcji dla wielu okien. Przykład Następny przykład ilustruje opisaną obsługę myszy. Przy każdej zmianie położenia następuje wypisanie pozycji kursora. Kliknięcie lewego lub prawego przycisku jest dodatkowo sygnalizowane. /* mouse.c */ #include <stdio.h> #include "cv.h" #include "highgui.h" void mouse_ev(int event, int x, int y, int flags, void* param); int main(int argc, char *argv) { IplImage *lena = cvloadimage("lena.jpg", 0);

38 36 Rozdział 2. Podstawy konstrukcji biblioteki cvnamedwindow("test myszy", CV_WINDOW_AUTOSIZE); cvshowimage("test myszy", lena); cvsetmousecallback("test myszy", mouse_ev, NULL); cvwaitkey(0); cvdestroywindow("test myszy"); return(0); void mouse_ev(int event, int x, int y, int flags, void* param) { IplImage *img = ((IplImage *)param); switch (event) { case CV_EVENT_LBUTTONDBLCLK: printf("l%d %d\n", x, y); break; case CV_EVENT_RBUTTONDBLCLK: printf("r%d %d\n", x, y); break; case CV_EVENT_MOUSEMOVE: printf("%d %d\n", x, y); break; Obsługa suwaków Suwak jest jedynym ruchomym elementem GUI zaimplementowanym w HighGUI. Do obsługi suwaka wykorzystywane są trzy funkcje. cvcreatetrackbar Tworzy nowy suwak o zakresie od 0 do count. Właściwie jest to jedyna funkcja potrzebna do jego obsługi. int cvcreatetrackbar(const char* trackbar_name, const char* window_name, int* value, int count, CvTrackbarCallback on_change); trackbar_name nazwa suwaka pojawia się jako jego opis w oknie, window_name nazwa okna, w którym tworzymy suwak, *value pozycja suwaka jest to wskaźnik. Zmienna, którą wskazuje, zawiera aktualną pozycję suwaka (przesunięcie powoduje jej uaktualnienie), count maksymalna wartość suwaka,

39 2.5. Tworzenie GUI 37 on_change funkcja wywoływana, gdy nastąpi zmiana suwaka (może mieć wartość NULL, wówczas żadna funkcja nie jest wywoływana). Funkcja on_change powinna być deklarowana następująco: void on_change(int pos); Wadą przyjętej w OpenCV metody jest brak dodatkowego parametru (takiego jak w cvsetmousecallback). Utrudnia to programowanie strukturalne oraz wielokrotne wykorzystanie funkcji. cvgettrackbarpos Podaje pozycje suwaka int cvgettrackbarpos(const char* trackbar_name, const char* window_name); trackbar_name nazwa suwaka, window_name nazwa okna. Warto zwrócić uwagę, że funkcja ta wymaga znajomości nazw okna i suwaka. Jeżeli tworzymy suwak w jednym miejscu, a odczytujemy w drugim, to nie musimy przekazywać wskaźnika *value. cvsettrackbarpos Ustawia suwak w zadanym miejscu. void cvsettrackbarpos(const char* trackbar_name, const char* window_name, int pos); trackbar_name nazwa suwaka, window_name nazwa okna, pos pozycja, w jaką należy ustawić suwak (tym razem jest to zmienna). Przykład Dalej przedstawiono program, który ilustruje obsługę suwaka. Przesunięcie suwaka powoduje zmianę parametru funkcji cvthreshold. Merytoryczny opis działania funkcji cvthreshold znajduje się w rozdziale 6.1. Realizacja obsługi zdarzeń w pętli nie jest optymalna, ale czyni kod bardziej przejrzystym. /* trackbar.c */ #include <stdio.h> #include "cv.h" #include "highgui.h"

40 38 Rozdział 2. Podstawy konstrukcji biblioteki Rysunek 2.1. Przykłady działania programu obsługującego suwak int main() { IplImage *lena = cvloadimage("lena.jpg", 0); /* Tworzenie miejsca na nowy obraz - patrz zarządzanie pamięcią */ IplImage *result = cvcreateimage(cvsize(lena->width, lena->height), 8, 1); int c; int sld_pos = 127; cvnamedwindow("test suwaka", CV_WINDOW_AUTOSIZE); cvshowimage("test suwaka", lena); cvcreatetrackbar("suwak", "Test suwaka", &sld_pos, 255, NULL); while ((c = cvwaitkey(10))!= q ) { /* Poniżej następuje progowanie, funkcję tą opisano * * w dalszej części książki */ cvthreshold(lena, result, 1. * sld_pos, 255., CV_THRESH_BINARY); cvshowimage("test suwaka", result); cvdestroywindow("test suwaka"); return(0); Wynik działania programu przedstawiono na rysunku 2.1.

41 Rozdział 3 Podstawowe operacje na obrazach W rozdziale zostaną opisane podstawowe operacje na obrazach. Operacje te można określić mianem pomocniczych, gdyż tylko pośrednio służą do przetwarzania obrazów lub uwypuklaniu rezultatów przetwarzania poprzez otaczanie obiektów prostokątami, okręgami itp. 1 Omawiane operacje można podzielić na kilka grup dostęp do pojedynczych pikseli, dostęp do poszczególnych fragmentów obrazu, operacje z zakresu algebry liniowej, rysowanie po obrazie, wstawianie tekstu Dostęp do pikseli OpenCV oferuje dwa sposoby dostępu do pikseli w obrazie Funkcje biblioteki Dostęp do pojedynczego piksela zapewniają funkcje z rodziny zdefiniowanej jako cvget*d oraz cvset*d 2. Funkcje te, umożliwiają dostęp do struktur różnych wymiarów, w tym także obrazów. Obsługują one elementy w zunifikowanej postaci: CvScalar lub double. W niniejszym rozdziale omówimy wyłącznie funkcje stosowane do obrazów. Dokładny opis zawiera dokumentacja. Obrazy w odcieniach szarości Do pobierania danych OpenCV służy funkcja double cvgetreal2d(const CvArr* arr, int idx0, int idx1); arr macierz, z której pobieramy dane (może być typu IplImage), 1 Część z nich tworzy jednak oddzielną klasę problemów, jak np. rysowanie linii i okręgów. 2 Znaku * użyto jako oznaczenia dowolnej liczby znaków.

42 40 Rozdział 3. Podstawowe operacje na obrazach idx0 współrzędna y, idx1 współrzędna x. Do zapisu przeznaczona jest funkcja void cvsetreal2d(cvarr* arr, int idx0, int idx1, double value); arr macierz, której elementom nadajemy wartości (może być typu IplImage), idx0 współrzędna y, idx1 współrzędna x, value wartość do zapisania we wskazane miejsce macierzy. Funkcje te należy stosować wyłącznie do obrazów z jednym kanałem. Obrazy wielokanałowe (kolorowe) Funkcje dla obrazów kolorowych są analogiczne do już omówionych. Jednak daną na której operujemy jest cvscalar. Opis tej struktury znajduje się w rozdziale Do pobierania elementów służy funkcja CvScalar cvget2d(const CvArr* arr, int idx0, int idx1); arr macierz, z której pobieramy elementy (może być typu IplImage), idx0 współrzędna y, idx1 współrzędna x. W zmiennej, którą uzyskujemy w wyniku zastosowania tej funkcji kolory ułożone są w kolejności BGR. Do nadawania wartości zmiennym w obrazach kolorowych służy funkcja void cvset2d(cvarr* arr, int idx0, int idx1, CvScalar value); arr macierz, której elementom nadajemy wartości (może być typu IplImage), idx0 współrzędna y, idx1 współrzędna x, value wartość do zapisania (o trzech składowych). Do utworzenia parametru value można wykorzystać zdefiniowane makro CV_RGB Dostęp bezpośredni Przedstawiona metoda wymusza konwersję danych do typu double oraz konwersję do typu, którego używamy. Konwersja powoduje narzut czasowy oraz two-

43 3.2. Fragmenty obrazu 41 rzy fałszywą precyzję obliczeń. Autor nie wypowiada się na temat różnic szybkości operacji zmiennopozycyjnych lub stałopozycyjnych. Dostęp do elementów obrazu można uzyskać też wprost, przez wskaźnik *image Data zawarty w strukturze IplImage. Elementy przechowywane są jako typ char. Należy więc rzutować ten wskaźnik na odpowiedni typ. Nawet jeżeli dane są ośmiobitowe, warto wykonać rzutowanie na typ unsigned char w celu uniknięcia kłopotów ze znakami. Długość linii obrazu określa zmienna widthstep. Wartość ta określana jest w bajtach (ze standardu ANSI typ char ma jeden bajt). Dla obrazu w odcieniach szarości dostęp do pojedynczego elementu przeprowadzić można więc następująco: gray = *(((unsigned char *)(img->imagedata + y * img->widthstep)) + x); Dla innych typów należy zmienić unsigned char na żądany typ. W przypadku obrazów kolorowych sytuacja zmienia się tak, że kolory przechowywane są jeden za drugim. b = *(((unsigned char *)(img->imagedata + y * img->widthstep)) + 3 * x); g = *(((unsigned char *)(img->imagedata + y * img->widthstep)) + 3 * x + 1); r = *(((unsigned char *)(img->imagedata + y * img->widthstep)) + 3 * x + 2); 3.2. Fragmenty obrazu Dostęp Dostęp do fragmentów obrazu zapewnia funkcja cvgetsubrect. Umożliwia ona pobranie prostokątnego fragmentu obrazu. Funkcja zwraca wynik w postaci pobranego fragmentu obrazu, traktowanego jako nowy obraz (patrz przykład). CvMat* cvgetsubrect(const CvArr* arr, CvMat* submat, CvRect rect); arr obraz, z którego pobieramy fragment, submat miejsce na nagłówek nowego obrazu (nie można tego pominąć), rect określenie parametrów prostokąta, którego wartości mamy pobrać (patrz opis struktury w rozdz ). Przykładowy program pobiera fragment obrazu i wyświetla go.

44 42 Rozdział 3. Podstawowe operacje na obrazach Rysunek 3.1. Wyświetlenie fragmentu obrazu /* submat.c */ #include <stdio.h> #include "cv.h" #include "highgui.h" int main() { IplImage *lena = cvloadimage("lena.jpg", 0); IplImage *cr; CvMat m; cr = cvgetsubrect(lena, &m, cvrect(100, 100, 100, 100)); cvnamedwindow("crop", CV_WINDOW_AUTOSIZE); cvshowimage("crop", cr); cvwaitkey(0); cvdestroywindow("crop"); return(0);

45 3.2. Fragmenty obrazu ROI Pojęcie ROI (ang. region of interest czyli obszar zainteresowania) obejmuje ograniczenie przetwarzania wyłącznie do pewnego (prostokątnego) fragmentu obrazu. Wszystkie współrzędne są w tym przypadku liczone od lewego, górnego rogu ROI. W przeciwieństwie do pobierania fragmentu obrazu, opisanego w rozdziale 3.2.1, pozostała informacja nie jest tracona. cvsetimageroi Funkcja pozwala określić prostokąt ROI w wybranym obrazie. Definiując ten prostokąt, posługujemy się jeszcze współrzędnymi wyjściowego obrazu. void cvsetimageroi(iplimage* image, CvRect rect); image obraz do ustawienia ROI, rect prostokąt ROI (CvRect omówiono w 3.4.2). cvgetimageroi Pobiera położenie ROI rozpatrywanego obrazu. Jeżeli obraz nie zawiera ROI, zwrócone zostają wymiary obrazu. CvRect cvgetimageroi(const IplImage* image); image obraz do pobrania ROI. Podana funkcja umożliwia usunięcie ROI z obrazu. cvresetimageroi void cvresetimageroi(iplimage* image); image obraz do usunięcia ROI. Przykład W kolejnym przykładzie pokazano zastosowanie ROI do progowania wybranego fragmentu obrazu. Zastosowano funkcję progującą opisaną w rozdziale 6.1. /* roi.c */ /* uwaga: wymaga OpenCV 1.0 */ #include <stdio.h> #include "cv.h" #include "highgui.h" int main() {

46 44 Rozdział 3. Podstawowe operacje na obrazach Rysunek 3.2. Operacja wykonana na wycinku obrazu IplImage *lena = cvloadimage("lena.jpg", 0); cvsetimageroi(lena, cvrect(170, 170, 170, 170)); cvthreshold(lena, lena, 127, 255, CV_THRESH_BINARY); cvresetimageroi(lena); cvnamedwindow("roi", CV_WINDOW_AUTOSIZE); cvshowimage("roi", lena); cvwaitkey(0); cvdestroywindow("roi"); return(0); W wyniku otrzymujemy pokazany na rysunku 3.2 obraz Algebra liniowa Biblioteka OpenCV zawiera dużą liczbę procedur numerycznych. W niniejszym opisie ograniczymy się wyłącznie do funkcji z zakresu algebry liniowej, jako najbardziej przydatnych w przetwarzaniu obrazów.

47 3.3. Algebra liniowa Mnożenie przez skalar Funkcja cvscaleadd dokonuje operacji zapisywanej jako C = α A + B Należy zwrócić uwagę, że macierze A,B,C oraz skalar α mogą składać się z uporządkowanych trójek elementów tworzących poszczególne kolory. void cvscaleadd(const CvArr* src1, CvScalar scale, const CvArr* src2, CvArr* dst); src1 element macierzy A, scale element α, src2 element macierzy B, dst element macierzy C. Trzeba zwrócić uwagę, że src1, src2 oraz dst muszą mieć ten sam rozmiar. Ponadto musimy zadbać o to, by macierze A, B i C miały takie same rozmiary Operator liniowy Funkcja cvtransform dokonuje przekształcenia każdej kolumny obrazu przez transformację opisaną macierzą. Dodatkowo wynik może być przesunięty o zadany wektor. void cvtransform(const CvArr* src, CvArr* dst, const CvMat* transmat, const CvMat* shiftvec = NULL); src obraz źródłowy, dst obraz docelowy (musi mieć odpowiednie wymiary), transmat macierz przekształcenia, shiftvec wektor przesunięcia (może być NULL) Inne operacje Do obliczania wyznacznika macierzy przeznaczona jest funkcja double cvdet(const CvArr* mat); Ślad macierzy zwraca funkcja CvScalar cvtrace(const CvArr* mat);

48 46 Rozdział 3. Podstawowe operacje na obrazach 3.4. Rysowanie Reprezentacja punktu Do określania położenia figur geometrycznych, tekstu itp. niezbędny jest opis punktu. W bibliotece OpenCV punkt jest reprezentowany przez strukturę typedef struct CvPoint { int x; int y; CvPoint; Do tworzenia tej struktur stosowana jest funkcja inline CvPoint cvpoint(int x, int y); Reprezentacja prostokąta Określenie prostokąta wymaga struktury zdefiniowanej następująco typedef struct CvRect { int x; /* x współrzędna lewego rogu */ int y; /* y współrzędna górnego rogu */ int width; /* szerokość */ int height; /* wysokość */ CvRect; Do stworzenia struktury można wykorzystać funkcję inline CvRect cvrect(int x, int y, int width, int height); Typy linii Biblioteka OpenCV zawiera trzy algorytmy rysowania linii. Dwa z nich to algorytmy Bresenhama, jeden jest algorytmem antyaliasingowym, wykorzystującym filtr Gaussa. Dodatkowo można określić grubość linii cvline Funkcja cvline umożliwia narysowanie linii (bardziej precyzyjnie odcinka) na obrazie.

49 3.4. Rysowanie 47 Rysunek 3.3. Przykład możliwych do uzyskania linii void cvline(cvarr* img, CvPoint pt1, CvPoint pt2, CvScalar color, int thickness = 1, int line_type = 8, int shift = 0); img obraz, na którym rysujemy, pt1 punkt określający odcinek, pt2 punkt określający odcinek, color kolor (format CV_RGB), thickness grubość linii, line_type typ linii, shift przesunięcie cvrectangle Umożliwia narysowanie prostokąta, z niezrozumiałych powodów, nie korzysta ze struktury CvRect. void cvrectangle(cvarr* img, CvPoint pt1, CvPoint pt2, CvScalar color, int thickness = 1, int line_type = 8, int shift = 0); img obraz, na którym rysujemy, pt1 punkt określający lewy, górny róg prostokąta,

50 48 Rozdział 3. Podstawowe operacje na obrazach Rysunek 3.4. Przykłady tekstu pt2 punkt określający prawy, dolny róg, color kolor (format CV_RGB), thickness grubość linii, jeżeli zamiast grubości wstawić liczbę ujemną (np. CV_FILLED), to prostkąt zostaje wypełniony w całości, line_type typ linii, shift przesunięcie cvcircle Umożliwia narysowanie okręgu, zadanego położeniem środka i promieniem. void cvcircle(cvarr* img, CvPoint center, int radius, CvScalar color, int thickness = 1, int line_type = 8, int shift = 0); img obraz, na którym rysujemy, center punkt określający środek okręgu, radius promień okręgu, color kolor (format CV_RGB), thickness grubość linii, jeżeli zamiast grubości wstawić liczbę ujemną (np. CV_FILLED) rysowane jest koło, line_type typ linii, shift przesunięcie Tekst Biblioteka OpenCV zapewnia możliwość umieszczenia tekstu na obrazach. Zestaw czcionek jest ograniczony wyłącznie do fontów Hersheya, które dostępne są w kilku krojach. Podano je dalej.

51 3.5. Tekst 49 W bibliotece przypisano im nazwy (kolejność taka jak na rys. 3.4) CV_FONT_HERSHEY_SIMPLEX CV_FONT_HERSHEY_PLAIN CV_FONT_HERSHEY_DUPLEX CV_FONT_HERSHEY_COMPLEX CV_FONT_HERSHEY_TRIPLEX CV_FONT_HERSHEY_COMPLEX_SMALL CV_FONT_HERSHEY_SCRIPT_SIMPLEX CV_FONT_HERSHEY_SCRIPT_COMPLEX cvinitfont Inicjuje strukturę odpowiedzialną za font. Ustawia wymiary pisma. void cvinitfont(cvfont* font, int font_face, double hscale, double vscale, double shear = 0, int thickness = 1, int line_type = 8); font wskaźnik do struktury fontu, font_face rodzaj fontu (patrz rysunek i tabelka), hscale względna wysokość fontu, vscale względna szerokość fontu, shear tangens kąta pochylenia (0 tekst prosty, 1 45 o ), thickness grubość linii, line_type typ linii, patrz cvputtext Umieszcza tekst na obrazie z wybranym fontem, w wybranym kolorze. void cvputtext(cvarr* img, const char* text, CvPoint org, const CvFont* font, CvScalar color); img obraz, po którym piszemy, text tekst do napisania, org położenie lewego, dolnego rogu tekstu (określenie punktu, patrz rozdział 3.4.1), font zainicjowana struktura fontu, color określenie koloru

52 50 Rozdział 3. Podstawowe operacje na obrazach cvgettextsize Określa prostokąt, w którym mieści się napis oraz położenie linii podstawowej pisma. void cvgettextsize(const char* text_string, const CvFont* font, CvSize* text_size, int* baseline); text_string tekst, którego wymiary badamy, font font, w jakim tekst ma być wypisany, text_size wskaźnik do struktury zawierającej wymiary, baseline wskaźnik do zmiennej zawierającej położenie linii (ang. baseline). Wymiary tekstu umieszczone są w strukturze CvSize zadeklarowanej następująco: typedef struct CvSize { int width; /* szerokość prostokąta */ int height; /* wysokość prostokąta */ CvSize; Linia, określana w dokumentacji jako baseline, nie spełnia powszechnie przyjętej definicji tej linii (linia pokrywająca się z dolną krawędzią liter bez wydłużeń) Przykład Ilustracja różnych fontów została wygenerowana za pomocą programu korzystającego z biblioteki OpenCV. Jego kod podano: /* text.c */ #include "cv.h" #include "highgui.h" int main() { IplImage *img; CvFont font; int y = 0, baseline; CvSize size; img = cvcreateimage(cvsize(400, 200), 8, 3); cvset(img, cvscalarall(255), NULL);

53 3.5. Tekst 51 cvinitfont(&font, CV_FONT_HERSHEY_SIMPLEX, 1, 1, 0., 1, 8); cvgettextsize("simplex", &font, &size, &baseline); y += size.height; cvputtext(img, "Simplex", cvpoint(0, y), &font, CV_RGB(0, 0, 0)); cvinitfont(&font, CV_FONT_HERSHEY_PLAIN, 1, 1, 0., 1, 8); cvgettextsize("plain", &font, &size, &baseline); y += (size.height + 5); cvputtext(img, "Plain", cvpoint(0, y), &font, CV_RGB(0, 0, 0)); cvinitfont(&font, CV_FONT_HERSHEY_DUPLEX, 1, 1, 0., 1, 8); cvgettextsize("duplex", &font, &size, &baseline); y += (size.height + 5); cvputtext(img, "Duplex", cvpoint(0, y), &font, CV_RGB(0, 0, 0)); cvinitfont(&font, CV_FONT_HERSHEY_COMPLEX, 1, 1, 0., 1, 8); cvgettextsize("complex", &font, &size, &baseline); y += (size.height + 5); cvputtext(img, "Complex", cvpoint(0, y), &font, CV_RGB(0, 0, 0)); cvinitfont(&font, CV_FONT_HERSHEY_TRIPLEX, 1, 1, 0., 1, 8); cvgettextsize("triplex", &font, &size, &baseline); y += (size.height + 5); cvputtext(img, "Triplex", cvpoint(0, y), &font, CV_RGB(0, 0, 0)); cvinitfont(&font, CV_FONT_HERSHEY_COMPLEX_SMALL, 1, 1, 0., 1, 8); cvgettextsize("complex small", &font, &size, &baseline); y += (size.height + 5); cvputtext(img, "Complex small", cvpoint(0, y), &font, CV_RGB(0, 0, 0)); cvinitfont(&font, CV_FONT_HERSHEY_SCRIPT_SIMPLEX, 1, 1, 0., 1, 8); cvgettextsize("script Simplex", &font, &size, &baseline); y += size.height; cvputtext(img, "Script Simplex", cvpoint(0, y), &font, CV_RGB(0, 0, 0)); cvinitfont(&font, CV_FONT_HERSHEY_SCRIPT_COMPLEX, 1, 1, 0., 1, 8); cvgettextsize("script Complex", &font, &size, &baseline); y += (size.height + 5);

54 52 Rozdział 3. Podstawowe operacje na obrazach cvputtext(img, "Script Complex", cvpoint(0, y), &font, CV_RGB(0, 0, 0)); cvnamedwindow("fonty", CV_WINDOW_AUTOSIZE); cvshowimage("fonty", img); cvwaitkey(0); cvdestroywindow("fonty"); return(0);

55 Rozdział 4 Podstawowe transformacje W rozdziale tym opisano dwa rodzaje funkcji biblioteki OpenCV: funkcje pobierania fragmentów obrazu z tak zwaną dokładnością subpikselową, właściwe, podstawowe transformacje obrazu, na które składają się operacje afiniczne oraz operacje nieliniowe, takie jak przejście do współrzędnych biegunowych. Funkcje pierwszej z wymienionych grup zostały umieszczone w tym rozdziale, gdyż one także w swej konstrukcji wewnętrznej korzystają z prostych transformacji obrazów Dokładniejszy odczyt fragmentów obrazu cvsampleline Funkcja odczytuje z obrazu wartości wzdłuż zadanej linii i zapisuje je do bufora. Sposób wywołania int cvsampleline(const CvArr* image, CvPoint pt1, CvPoint pt2, void* buffer, int connectivity = 8); image obraz, z którego odczytana zostanie linia, pt1 początkowy punkt linii, pt2 końcowy punkt linii, buffer bufor, w którym będą przechowywane punkty linii odczytane z obrazu. Aby je pomieścić, należy przygotować bufor odpowiedniego rozmiaru, a więc: max( pt2.x pt1.x +1, pt2.y pt1.y +1 ) w przypadku pikseli połączonych z ośmioma sąsiednimi, pt2.x pt1.x + pt2.y pt1.y + 1 dla pikseli połączonych z czterema sąsiadami,

56 54 Rozdział 4. Podstawowe transformacje connectivity parametr informuje, czy zakładamy połączenie każdego piksela z 4 czy z 8 pikselami sąsiednimi. Powiązania z innymi procedurami OpenCV Funkcja wymaga użycia bufora o odpowiedniej pojemności, a więc alokacji odpowiedniej ilości pamięci (np. funkcją cvalloc). Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c, j; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0; uchar* bufor; CvPoint2D32f* punkt = 0; if (argc > 1) { strcpy(nazwa, argv[1]); //załadowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); // alokacja pamięci: 41x rozmiar pojedynczego // punktu, żeby wystarczyło dla wpisanych // poniżej punktów bufor = cvalloc(41 * 3); // wywołanie funkcji dla dwóch punktów // wpisanych ręcznie cvsampleline(obr_zrodlowy, cvpoint(50, 120), cvpoint(10, 130), bufor, 8); //wypisanie zawartości bufora, żeby było //widać, że został zapisany for (j = 0; j < 41; j++) { printf("bufor %d:%uc \n", j, *(bufor + j)); c = cvwaitkey(0); //zwolnienie pamięci i~usunięcie okien cvfree(&bufor); cvreleaseimage(&obr_zrodlowy);

57 4.1. Dokładniejszy odczyt fragmentów obrazu 55 cvdestroyallwindows(); return(0); Uwagi dla użytkownika Dla prawidłowego działania funkcji kluczowe jest stworzenie bufora odpowiedniego rozmiaru. Uwaga: funkcja sama tego nie kontroluje! Uwagi na temat algorytmu Funkcja jest implementacją szczególnego przypadku iteratora liniowego. Odczytuje ona wszystkie punkty obrazu leżące na linii łączącej pt1 i pt2 (łącznie z nimi) i zapisuje je do bufora cvgetrectsubpix Ekstrahuje i pobiera, zadany przez podanie środka, prostokątny obszar obrazu wejściowego z subpikselową dokładnością. Sposób wywołania void cvgetrectsubpix(const CvArr* src, CvArr* dst, CvPoint2D32f center); src obraz źródłowy, dst obraz do zapisu ekstrahowanego prostokąta, jego rozmiar odpowiada za zdefiniowanie rozmiaru prostokąta, center zmiennoprzecinkowe współrzędne środka prostokąta na obrazie źródłowym (środek musi znajdować się wewnątrz obrazu). Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, *prostokat = 0; CvPoint2D32f* punkt = 0; if (argc > 1) { strcpy(nazwa, argv[1]);

58 56 Rozdział 4. Podstawowe transformacje Rysunek 4.1. Prostokątny obszar wyekstrahowany z obrazu Lena //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu o rozmiarach zadanego //prostokąta (wpisane ręcznie) prostokat = cvcreateimage(cvsize(201, 201), 8, 3); //wywołanie funkcji dla ręcznie wpisanego //środka prostokąta cvgetrectsubpix(obr_zrodlowy, prostokat, cvpoint2d32f(12, 225)); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", prostokat); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&prostokat); cvdestroyallwindows(); return(0);

59 4.1. Dokładniejszy odczyt fragmentów obrazu 57 Uwagi dla użytkownika Funkcja nie kontroluje dokładnie zgodności obrazu wejściowego i wyjściowego: np. w przypadku użycia różnych liczb kanałów, albo głębi koloru, może nie zwrócić błędu i działać nieprawidłowo. Uwagi na temat algorytmu Funkcja przetwarza piksele z obrazu wejściowego, znajdujące się w zadanym prostokącie, według formuły: dst(x, y) = src(x + center.x (width(dst) 1) 0.5, y + center.y (height(dst) 1) 0.5), gdzie niecałkowite wartości współrzędnych przybliżane są za pomocą interpolacji dwuliniowej. Część prostokąta (z wyłączeniem środka), może znajdować się poza obszarem obrazu. W takim przypadku stosuje się replikację pikseli z krawędzi obrazu do uzupełnienia brakujących punktów. Każdy kanał przetwarzany jest osobno cvgetquadranglesubpix Funkcja przetwarza z subppikselową dokładnością część obrazu wejściowego, zgodnie z podaną macierzą transformacji, zapisując wynik w kwadracie o zadanym rozmiarze. Sposób wywołania void cvgetquadranglesubpix(const CvArr* src, CvArr* dst, const CvMat* map_matrix); src obraz wejściowy, dst wyekstrahowany kwadrat, map_matrix macierz transformacji rozmiaru 2 x 3. Powiązania z innymi procedurami OpenCV Do zdefiniowania macierzy transformacji niezbędne jest utworzenie i wypełnienie odpowiedniego obiektu typu CvMat. Do tego celu można użyć jednej z funkcji inicjalizujących, na przykład cvinitmatheader.

60 58 Rozdział 4. Podstawowe transformacje Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, *kwadrat = 0; CvMat macierz; double a[] = { 1,.1, 0,.5, 2, 0 ; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu o rozmiarach zadanego // kwadratu (wpisane ręcznie) kwadrat = cvcreateimage(cvsize(201, 201), 8, 3); // wpisanie zawartości tablicy a do obiektu macierz cvinitmatheader(&macierz, 2, 3, CV_64FC1, a, CV_AUTOSTEP); //wywołanie funkcji cvgetquadranglesubpix(obr_zrodlowy, kwadrat, &macierz); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", kwadrat); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&kwadrat); cvdestroyallwindows(); return(0); Uwagi na temat algorytmu Funkcja przeprowadza ekstrakcję pikseli, zapisując wyniki w dst według zależności: dst(x, y) = src(a11x + A12y + b1, A21x + A22y + b2),

61 4.2. Transformacje 59 gdzie A i b zadane są macierzą map matrix, daną jako: [ ] A11 A12 b1 M =, A21 A22 b2 przy czym x = x (width(dst) 1) 0.5, y = y (height(dst) 1) 0.5. Wartości niecałkowitych współrzędnych pikseli A (x, y) T +b ustalane są z użyciem interpolacji dwuliniowej. W przypadku gdy przetwarzany obszar wykracza poza obraz, używa się powielania pikseli znajdujących się na krawędzi obrazu. Każdy kanał przetwarzany jest osobno Transformacje cvresize Funkcja zmienia rozmiar obrazu wejściowego, tak by był dokładnie dopasowany do zadanego rozmiaru obrazu wyjściowego. Sposób wywołania void cvresize(const CvArr* src, CvArr* dst, int interpolation = CV_INTER_LINEAR); src obraz źródłowy, dst obraz wyjściowy, interpolation metoda interpolacji, dopuszczalne są następujące wartości: CV INTER NN interpolacja typu najbliższy sąsiad, CV INTER LINEAR interpolacja dwuliniowa (domyślnie), CV INTER AREA interpolacja na podstawie sąsiedztwa pojedynczego piksela, metoda preferowana podczas zmniejszania obrazu, umożliwia uniknięcie efektu mory, w przypadku powiększania działa jak CV INTER - NN, CV INTER CUBIC interpolacja dwusześcienna. Standardowe przykłady #include <cv.h> #include <highgui.h>

62 60 Rozdział 4. Podstawowe transformacje int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, * obr_wyjsciowy = 0; if (argc > 1) { strcpy(nazwa, argv[1]); //załadowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu wyjściowego o ręcznie // wpisanym rozmiarze obr_wyjsciowy = cvcreateimage(cvsize(215, 330),IPL_DEPTH_8U,3); //wywołanie funkcji cvresize(obr_zrodlowy, obr_wyjsciowy, CV_INTER_CUBIC); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvdestroyallwindows(); return(0); Uwagi na temat algorytmu Funkcja zmienia rozmiar obrazu na zadany (również o innych proporcjach) z użyciem, jeśli to konieczne, wybranej metody interpolacji cvwarpaffine Stosuje zadaną transformację afiniczną do obrazu wejściowego. Sposób wywołania void cvwarpaffine(const CvArr* src, CvArr* dst, const CvMat* map_matrix, int flags = CV_INTER_LINEAR +

63 4.2. Transformacje 61 Rysunek 4.2. Przykładowa transformacja afiniczna obrazu Lena CV_WARP_FILL_OUTLIERS, CvScalar fillval = cvscalarall(0)); src obraz źródłowy, dst obraz wyjściowy, map_matrix macierz transformacji 2x3 (sposób jej zadawania opisano dalej), flags kombinacja flag, opisujących metodę interpolacji, oraz dodatkowych opcjonalnych flag: CV WARP FILL OUTLIERS wypełnia wszystkie piksele obrazu wyjściowego, piksele odstające od ogółu wypełniane są wartością fillval. CV WARP INVERSE MAP ustawienie tej flagi oznacza, że macierz opisuje transformację obrazu, który już wcześniej został przetransformowany, a który chcemy odzyskać, można więc bezpośrednio użyć jej do interpolacji pikseli. W przeciwnym wypadku funkcja znajduje transformatę odwrotną na podstawie macierzy map matrix. fillval wartość do wypełniania pikseli odstających (nietypowych). Powiązania z innymi procedurami OpenCV Do zdefiniowania macierzy transformacji niezbędne jest utworzenie i wypełnienie odpowiedniego obiektu typu CvMat. Do tego celu można użyć jednej z funkcji inicjalizujących, np. cvinitmatheader.

64 62 Rozdział 4. Podstawowe transformacje Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, * obr_wyjsciowy = 0, * obr_odtworzony = 0; CvMat macierz; double a[] = {.1,.5,.2,.5,.2,.3 ; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu wyjściowego obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3); obr_odtworzony = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3); // wpisanie zawartości tablicy a // do obiektu macierzowego cvinitmatheader(&macierz, 2, 3, CV_64FC1, a, CV_AUTOSTEP); //wywołanie funkcji transformującej obraz cvwarpaffine(obr_zrodlowy, obr_wyjsciowy, &macierz, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvscalarall(0)); //wywołanie funkcji jako transformaty odwrotnej // w celu odtworzenia obrazu wejsciowego cvwarpaffine(obr_wyjsciowy, obr_odtworzony, &macierz, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS + CV_WARP_INVERSE_MAP, cvscalarall(0)); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1);

65 4.2. Transformacje 63 cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); cvnamedwindow("obraz odtworzony", 1); cvshowimage("obraz odtworzony", obr_odtworzony); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvreleaseimage(&obr_odtworzony); cvdestroyallwindows(); return(0); Uwagi na temat algorytmu Funkcja przetwarza obraz zgodnie z zadaną macierzą transformacji: dst(x, y ) = src(x, y), gdzie: (x, y ) T = map matrix (x, y, 1) T + b jeżeli nie jest ustawiona flaga CV WARP INVERSE MAP, (x, y) T = map matrix (x, y, 1) T + b w przeciwnym wypadku. Funkcja działa podobnie do cvgetquadranglesubpix, ale różni się od niej kilkoma istotnymi szczegółami. Wymaga, między innymi, żeby typy obrazów wejściowego i wyjściowego były identyczne, podczas gdy cvgetquadranglesubpix może np. przekształcić obraz 8-bitowy na typ 32f. Jest również bardziej kosztowna obliczeniowo, lecz umożliwia pozostawienie części obrazu bez zmian (cvgetquadranglesubpix zawsze działa dla całego obrazu wejściowego). Do przetwarzania rozproszonych zbiorów punktów zaleca się używanie funkcji cvtransform z cxcore cvgetaffinetransform Oblicza parametry transformacji na podstawie współrzędnych trzech punktów przed i po jej zastosowaniu. Sposób wywołania CvMat* cvgetaffinetransform(const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* map_matrix);

66 64 Rozdział 4. Podstawowe transformacje src współrzędne trzech punktów (wierzchołków trójkąta) na obrazie źródłowym, dst współrzędne trzech, odpowiadających im punktów, po zastosowaniu transformacji, map_matrix wskaźnik do macierzy transformacji, w której zostaną zapisane obliczone współczynniki (również zwracany przez funkcję). Powiązania z innymi procedurami OpenCV Trzeba pamiętać, że funkcja używa wywołania funkcji cvsolve, opartej na dekompozycji LU, stąd w niektórych (uzasadnionych matematycznie) przypadkach, może nie znaleźć macierzy współczynników. Do zdefiniowania macierzy transformacji niezbędne jest utworzenie odpowiedniego obiektu typu CvMat. Do tego celu można użyć jednej z funkcji inicjalizujących, np. cvinitmatheader. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c, l; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, * obr_wyjsciowy = 0; double a[6]; CvMat macierz; CvPoint2D32f punkciki1[3], punkciki2[3]; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu wyjściowego obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3); // tu następuje ręczne wypełnienie // punktów - poglądowo for (l = 0; l < 3; l++) { punkciki1[l].x = l * l * ; punkciki1[l].y = l * ;

67 4.2. Transformacje 65 punkciki2[l].x = 3 * (punkciki1[l].x) + 2 * (punkciki1[l].y) + 1; punkciki2[l].y = 4 * (punkciki1[l].x) + 5 * (punkciki1[l].y) + 6; // zainicjalizowanie macierzy cvinitmatheader(&macierz, 2, 3, CV_64FC1, a, CV_AUTOSTEP); //wywołanie funkcji obliczającej //macierz transformacji cvgetaffinetransform(punkciki1, punkciki2, &macierz); //zastosowanie obliczonej transformacji // do obrazu cvwarpaffine(obr_zrodlowy, obr_wyjsciowy, &macierz, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvscalarall(0)); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvdestroyallwindows(); return(0); Uwagi dla użytkownika W przypadku gdy w trakcie obliczeń pojawiła się macierz osobliwa, funkcja zastępuje wszystkie współczynniki zerami. Funkcja zwraca wskaźnik do macierzy map matrix. Uwagi na temat algorytmu Funkcja oblicza macierz transformacji zakładając, że: (ui, vi) T = map matrix (xi, yi, 1) T

68 66 Rozdział 4. Podstawowe transformacje przy czym dst(i) = (ui, vi), src(i) = (xi, yi), i = 0,..., 2. Innymi słowy: ui = c 00 x i + c 01 y i + c 02 vi = c 10 x i + c 11 y i + c 12. Współczynniki transformacji obliczane są jako rozwiązanie liniowego układu równań postaci: x0 y x1 y x2 y x0 y0 1 c = ū, x1 y x2 y2 1 gdzie natomiast c = ū = c00 c01 c02 c10 c11 c12 u0 u1 u2 v0 v1 v2,, gdzie c ij oznacza odpowiedni element macierzy map matrix cv2drotationmatrix Funkcja oblicza macierz transformacji do wykonania dwuwymiarowej rotacji. Sposób wywołania CvMat* cv2drotationmatrix(cvpoint2d32f center, double angle, double scale, CvMat* map_matrix); center punkt, wokół którego ma nastąpić rotacja,

69 4.2. Transformacje 67 angle kąt rotacji podany w stopniach (kąt skierowany wartość dodatnia oznacza ruch w kierunku przeciwnym do wskazówek zegara), początek układu współrzędnych w lewym górnym rogu obrazu, scale współczynnik skalowania, map_matrix wskaźnik do macierzy transformacji rozmiaru 2 x 3 (również zwracany przez funkcję). Powiązania z innymi procedurami OpenCV Do zdefiniowania macierzy transformacji niezbędne jest utworzenie odpowiedniego obiektu typu CvMat. Do tego celu można użyć jednej z funkcji inicjalizujących, np. cvinitmatheader. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c, l; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, * obr_wyjsciowy = 0; double a[6]; CvMat macierz; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu wyjściowego obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3); // zainicjalizowanie macierzy cvinitmatheader(&macierz, 2, 3, CV_64FC1, a, CV_AUTOSTEP); //wywołanie funkcji dla ręcznie //wpisanych parametrów cv2drotationmatrix(cvpoint2d32f(411, 324), -120,.5, &macierz); //zastosowanie obliczonej transformacji do obrazu

70 68 Rozdział 4. Podstawowe transformacje cvwarpaffine(obr_zrodlowy, obr_wyjsciowy, &macierz, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvscalarall(0)); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvdestroyallwindows(); return(0); Uwagi na temat algorytmu Na podstawie zadanych parametrów, funkcja oblicza macierz współczynników w następujący sposób: [ ] α β (1 α)center.x β center.y, β α β center.x + (1 α)center.y gdzie α = scale cos(angle), β = scale sin(angle). Punkt centralny rotacji pozostaje niezmieniony cvwarpperspective Funkcja przeprowadza transformację perspektywy na obrazie. Sposób wywołania void cvwarpperspective(const CvArr* src, CvArr* dst, const CvMat* map_matrix, int flags = CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, CvScalar fillval = cvscalarall(0)); src obraz źródłowy, dst obraz wyjściowy,

71 4.2. Transformacje 69 map_matrix macierz transformacji o rozmiarze 3 x 3, flags kombinacja metody interpolacji i następujących opcjonalnych flag opcji: CV WARP FILL OUTLIERS wypełnia wszystkie piksele obrazu wyjściowego, piksele odstające od ogółu wypełniane są wartością fillval. CV WARP INVERSE MAP ustawienie flagi oznacza, że macierz opisuje transformację obrazu, który już wcześniej został przetransformowany, a który chcemy odzyskać, można więc bezpośrednio użyć jej do interpolacji pikseli. W przeciwnym wypadku funkcja znajduje transformatę odwrotną na podstawie macierzy map matrix. fillval wartość do wypełniania pikseli odstających. Powiązania z innymi procedurami OpenCV Do zdefiniowania i wypełnienia macierzy transformacji niezbędne jest utworzenie odpowiedniego obiektu typu CvMat. Do tego celu można użyć jednej z funkcji inicjalizujących, np. cvinitmatheader. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, * obr_wyjsciowy = 0, *obr_odtworzony = 0; double a[] = { -1, 1, 0, 0, 1, 0, 0, 0, 1 ; CvMat macierz; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu wyjściowego obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3); obr_odtworzony = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3);

72 70 Rozdział 4. Podstawowe transformacje // wpisanie zawartości tablicy a // do obiektu macierz cvinitmatheader(&macierz, 3, 3, CV_64FC1, a, CV_AUTOSTEP); //wywołanie funkcji cvwarpperspective(obr_zrodlowy, obr_wyjsciowy, &macierz, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvscalarall(0)); //wywołanie funkcji jako transformaty odwrotnej //w celu odtworzenia obrazu wejsciowego cvwarpperspective(obr_wyjsciowy, obr_odtworzony, &macierz, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS + CV_WARP_INVERSE_MAP, cvscalarall(0)); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); cvnamedwindow("obraz odtworzony", 1); cvshowimage("obraz odtworzony", obr_odtworzony); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvreleaseimage(&obr_odtworzony); cvdestroyallwindows(); return(0); Uwagi na temat algorytmu Funkcja przekształca obraz, używając macierzy transformującej następującej postaci: dst(x, y ) = src(x, y), gdzie: (t x, t y, t) T = map matrix (x, y, 1) T + b, stosowane jeśli

73 4.2. Transformacje 71 Rysunek 4.3. Przekształcenie perspektywy obrazu Lena CV WARP INVERSE MAP nie jest ustawione (t x, t y, t) T = map matrix (x, y, 1) T + b w przeciwnym wypadku. Do przetwarzania rozproszonych zbiorów punktów zaleca się używanie funkcji cvperspectivetransform z cxcore cvgetperspectivetransform Oblicza macierz transformacji perspektywy na podstawie współrzędnych czterech punktów przed i po zastosowaniu transformacji. Sposób wywołania CvMat* cvgetperspectivetransform(const CvPoint2D32f* src, const CvPoint2D32f* dst, CvMat* map_matrix); src współrzędne wierzchołków czworokąta na obrazie źródłowym, dst współrzędne wierzchołków czworokąta po transformacji, map_matrix wskaźnik do macierzy transformacji o rozmiarze 3 x 3 (również zwracany przez funkcję).

74 72 Rozdział 4. Podstawowe transformacje Powiązania z innymi procedurami OpenCV Do zdefiniowania macierzy transformacji niezbędne jest utworzenie odpowiedniego obiektu typu CvMat. Do tego celu można użyć jednej z funkcji inicjalizujących, np. cvinitmatheader. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c, l; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, * obr_wyjsciowy = 0; double a[9]; CvMat macierz; CvPoint2D32f punkciki1[4], punkciki2[4]; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu wyjściowego obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3); // tu następuje ręczne wypełnienie // punktów - poglądowo for (l = 0; l < 4; l++) { punkciki1[l].x = l * l * ; punkciki1[l].y = l * ; punkciki2[l].x = 3 * (punkciki1[l].x) + 2 * (punkciki1[l].y) + 1; punkciki2[l].y = 4 * (punkciki1[l].x) + 5 * (punkciki1[l].y) + 6; // zainicjalizowanie macierzy cvinitmatheader(&macierz, 3, 3, CV_64FC1, a, CV_AUTOSTEP);

75 4.2. Transformacje 73 //wywołanie funkcji cvgetperspectivetransform(punkciki1, punkciki2, &macierz); //zastosowanie obliczonej transformacji //do obrazu wejściowego cvwarpperspective(obr_zrodlowy, obr_wyjsciowy, &macierz, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvscalarall(0)); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvdestroyallwindows(); return(0); Uwagi na temat algorytmu Funkcja oblicza macierz transformacji perspektywy taką, że: (t i x2 i, t i y2 i, t i) T = map matrix (x1 i, y1 i, 1) T, gdzie dst(i) = (x2 i, y2 i), src(i) = (x1 i, y1 i), i = 0,..., cvremap Funkcja przeprowadza transformację obrazu na podstawie przekształcenia zadanego przez mapy. Sposób wywołania void cvremap(const CvArr* src, CvArr* dst, const CvArr* mapx, const CvArr* mapy, int flags = CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, CvScalar fillval = cvscalarall(0)); src obraz źródłowy, dst obraz wyjściowy,

76 74 Rozdział 4. Podstawowe transformacje Rysunek 4.4. Przekształcenie obrazu Lena funkcją cvremap mapx przekształcenie współrzędnych poziomych x (kodowanie 32fC1), mapy przekształcenie współrzędnych pionowych y (kodowanie 32fC1), flags flagi, kombinacja metod interpolacji i opcjonalnej flagi CV WARP FILL OUTLIERS wypełnia wszystkie piksele obrazu wyjściowego, piksele odstające od ogółu wypełniane są wartością fillval. fillval wartość do wypełniania pikseli odstających. Powiązania z innymi procedurami OpenCV Do zdefiniowania macierzy transformacji niezbędne jest utworzenie odpowiedniego obiektu typu CvMat. Do tego celu można użyć którejś z funkcji inicjalizujących, np. cvinitmatheader. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0,

77 4.2. Transformacje 75 * obr_wyjsciowy = 0; IplImage* mapa_x = 0, * mapa_y = 0, * obr_szary = 0; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu wyjściowego obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 1); // utworzenie jednokolorowej kopii obr_szary = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 1); cvcvtcolor(obr_zrodlowy, obr_szary, CV_BGR2GRAY); //utworzenie obrazów map -- koniecznie w~kodowaniu 32fC1 mapa_x = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_32F, 1); mapa_y = cvcloneimage(mapa_x); // wypełnienie map, przykładowo właśnie tak cvlaplace(obr_szary, mapa_x, 1); cvsobel(obr_szary, mapa_y, 1, 0, 3); //wywołanie funkcji cvremap(obr_szary, obr_wyjsciowy, mapa_x, mapa_y, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS, cvscalarall(0)); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvreleaseimage(&obr_szary); cvreleaseimage(&mapa_x); cvreleaseimage(&mapa_y);

78 76 Rozdział 4. Podstawowe transformacje Rysunek 4.5. Obrazy pasma miedzi i korozji poddane przekształceniu funkcją cvremap cvdestroyallwindows(); return(0); Uwagi na temat algorytmu Funkcja przeprowadza transformację obrazu według danej mapy: dst(x, y) = src(mapx(x, y), mapy(x, y)) Podobnie, jak w przypadku transformacji geometrycznej, odpowiednia metoda interpolacyjna używana jest do przetwarzania pikseli o współrzędnych niecałkowitych. Przykłady zastosowań w monitorowaniu jakości produkcji Dalej pokazano znane już obrazy pasma miedzi i korozji, poddane przekształceniu (negatyw) cvlogpolar Transformuje obraz wejściowy na płaszczyznę logarytmiczno-biegunową. Sposób wywołania void cvlogpolar(const CvArr* src, CvArr* dst, CvPoint2D32f center,

79 4.2. Transformacje 77 double M, int flags = CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS); src obraz źródłowy, dst obraz wyjściowy, center centrum transformacji (maksymalna precyzja na wyjściu), M parametr skalowania, flags kombinacja metody interpolacyjnej i danych opcji: CV WARP FILL OUTLIERS wypełnia wszystkie piksele obrazu wyjściowego, piksele odstające od ogółu wypełniane są wartością fillval. CV WARP INVERSE MAP ustawienie flagi oznacza, że macierz opisuje odwrotną transformację obrazu, który już wcześniej został przetransformowany, można więc bezpośrednio użyć jej do interpolacji pikseli. fillval wartość do wypełniania pikseli odstających. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, * obr_wyjsciowy = 0, * obr_odtworzony = 0; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu wyjściowego obr_wyjsciowy = cvcreateimage(cvsize(256, 256), IPL_DEPTH_8U, 3); obr_odtworzony = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3); //wywołanie funkcji cvlogpolar(obr_zrodlowy, obr_wyjsciowy,

80 78 Rozdział 4. Podstawowe transformacje cvpoint2d32f(obr_zrodlowy->width / 2, obr_zrodlowy->height / 2), 40, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS); //wywołanie transformaty odwrotnej cvlogpolar(obr_wyjsciowy, obr_odtworzony, cvpoint2d32f(obr_zrodlowy->width / 2, obr_zrodlowy->height / 2), 40, CV_INTER_LINEAR + CV_WARP_FILL_OUTLIERS + CV_WARP_INVERSE_MAP); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); cvnamedwindow("obraz odtworzony", 1); cvshowimage("obraz odtworzony", obr_odtworzony); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvreleaseimage(&obr_odtworzony); cvdestroyallwindows(); return(0); Uwagi dla użytkownika Rozmiar obrazu wyjściowego (po transformacji) może być różny od rozmiaru obrazu przetwarzanego. Uwagi na temat algorytmu Funkcja przekształca obraz źródłowy na płaszczyznę logarytmiczno-biegunową, używając następującej transformacji: dst(phi, rho) = src(x, y), gdy CV W ARP INV ERSE MAP nie jest ustawione, natomiast gdy

81 4.2. Transformacje 79 Rysunek 4.6. Przekształcenie obrazu Lena na płaszczyznę logarytmiczno-biegunową CV W ARP IN V ERSE M AP jest ustawione, wykonywana jest transformacja odwrotna dst(x, y) = src(phi, rho), przy czym rho = M log(sqrt(x2 + y2)), phi = atan(y/x). Funkcja emuluje ludzkie widzenie w centralnej części pola. Może być używana do szybkiego dopasowania skali i rotacji według zadanego szablonu i śledzenia obiektów. Dokładniejsze informacje na ten temat znaleźć można w pracy i bardzo obszernej literaturze, która ukazała się w latach następnych.

82

83 Rozdział 5 Krawędzie i wierzchołki W rozdziale tym opisano podstawowe algorytmy detekcji krawędzi oraz punktów wierzchołkowych obiektów, znajdujących się na obrazach. Opisano algorytmy Sobela, Laplace a i Canny i sposób korzystania z nich jako funkcji dostępnych w bibliotece OpenCV. Zagadnieniu detekcji krawędzi poświęcona jest bogata literatura (por. [26], [13]), w której znaleźć można opisy wielu innych metod detekcji, między innymi, Prewitta, Robertsa, LoG. Popularność zdobył także algorytm o akronimie SUSAN (por. [34]), którego modyfikację zaproponowano w pracy [28]. Algorytm SUSAN może być stosowany zarówno do detekcji krawędzi, jak i punktów wierzchołkowych. Zagadnieniu detekcji punktów wierzchołkowych poświęcona jest druga część tego rozdziału. Rozdział kończy opis algorytmu, którego celem jest znajdowanie dostatecznie wyrazistych punktów wierzchołkowych. Punkty takie są dobrym narzędziem dośledzenia ruchu, lecz jak pokazują zamieszczone tu przykłady warto rozważyć jego zastosowanie do detekcji defektów Detekcja krawędzi cvsobel Funkcja oblicza pierwszą, drugą i trzecią pochodną obrazu z zastosowaniem rozszerzonego operatora Sobela. Wynikiem działania funkcji jest obraz powstały po zastosowaniu odpowiedniej maski do obrazu wejściowego. Sposób wywołania void cvsobel(const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size = 3); src obraz źródłowy, dst obraz docelowy, xorder rząd pochodnej w kierunku x,

84 82 Rozdział 5. Krawędzie i wierzchołki Rysunek 5.1. Wynik działania operatora Sobela (pokazany w negatywie) yorder rząd pochodnej w kierunku y, aperture_size rozmiar rozszerzonego jądra Sobla, dopuszczalne są wartości: 1, 3, 5 i 7. Dla wartości większych od 1 do obliczania pochodnej używana jest macierz maski splotu o rozmiarze: aperture size aperture size. Dla wartości parametru aperture_size=1 przyjmuje ona postać wektora 3 x 1 lub 1 x 3. Możliwe jest również ustawienie wartości: CV_SCHARR (= -1), która powoduje zastosowanie filtru Sharra o masce 3x3. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/pic5.png" ; IplImage* obr_zrodlowy = 0; IplImage* obr_wyjsciowy = 0; if (argc > 1) { strcpy(nazwa, argv[1]);

85 5.1. Detekcja krawędzi 83 //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //stworzenie obrazu wyjściowego, jako kopii wejściowego obr_wyjsciowy = cvcloneimage(obr_zrodlowy); //wywołanie funkcji do obliczenia gradientu w kiernku //poziomym x z maską splotu 3x3 cvsobel(obr_zrodlowy, obr_wyjsciowy, 1, 0, 3); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvdestroyallwindows(); return(0); Uwagi dla użytkownika Jako że funkcja ta nie przeprowadza żadnego skalowania, wartości liczbowe obrazu wyjściowego mogą być większe od tych z obrazu początkowego. Aby uniknąć przepełnienia, zaleca się, aby obraz wyjściowy był 16-bitowy dla 8-bitowego obrazu wejściowego. Wynik może potem powtórnie zostać skonwertowany do formatu 8 bitów na piksel z użyciem funkcji cvconvertscale lub cvconvertscaleabs. Oprócz obrazów 8-bitowych funkcja może również przetwarzać obrazy formatu 32 bity na piksel. W takim przypadku, zarówno obraz wejściowy, jak i wyjściowy powinny mieć identyczny rozmiar i być kodowane z jednym kanałem. Jeśli nie chcemy przed wywołaniem funkcji kontrolować parametrów obrazu wejściowego, bezpiecznie założyć, że w obrazie wyjściowym stosujemy kodowanie 32-bitowe. Przykłady zastosowań w monitorowaniu jakości produkcji Zastosowanie: operator używany do detekcji krawędzi. Wykrywanie krawędzi może służyć do znajdowania pęknięć, zarysowań, przebarwień, zmian w fakturze materiału, etc. Na rysunku 5.2 pokazano pasmo miedzi z defektami i wynik ich wykrywania za pomocą operatora Sobela. Zastosowanie tegoż operatora do wykrywania korozji pokazano na rysunku 5.3.

86 84 Rozdział 5. Krawędzie i wierzchołki Rysunek 5.2. Pasmo miedzi z defektami i wynik ich wykrywania za pomocą operatora Sobela (negatyw) Rysunek 5.3. Fragment powierzchni pokrytej rdzą i wynik jej wykrywania za pomocą operatora Sobela (negatyw)

87 5.1. Detekcja krawędzi 85 Uwagi na temat algorytmu Funkcja cvsobel oblicza pochodne obrazu przez splot z odpowiednią maską: dst(x, y) = xorder+yorder x xorder src(x, y) yyorder Operator Sobela łączy właściwości gaussowskiego rozmywania z różniczkowaniem, można więc stwierdzić, że jest on w pewnym stopniu odporny na zakłócenia. W typowym zastosowaniu funkcja będzie wywoływana z parametrami (xorder=1, yorder=0, aperture_size=3) lub (xorder=0, yorder=1, aperture_size=3) podczas obliczania gradientu w kierunkach x i y. W tym pierwszym przypadku maska ma postać: w drugim zaś: lub zależnie od wartości pola origin obrazu typu IplImage, które determinuje orientację początku układu współrzędnych obrazu. Ustawienie wartości aperture_size na CV_SCHARR (= -1) powoduje zastosowanie filtru Sharra o masce splotu postaci: w przypadku pochodnej w kierunku x, lub podanej transpozycji macierzy dla pochodnej w kierunku y cvlaplace Oblicza laplasjan obrazu źródłowego, zapisując wynik w postaci obrazu wyjściowego.

88 86 Rozdział 5. Krawędzie i wierzchołki Rysunek 5.4. Wynik działania laplasjanu Sposób wywołania void cvlaplace(const CvArr* src, CvArr* dst, int aperture_size =3); src obraz źródłowy, dst obraz wyjściowy, aperture_size rozmiar macierzy splotu, analogicznie jak w przypadku funkcji cvsobel. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/pic5.png" ; IplImage* obr_zrodlowy = 0; IplImage* obr_wyjsciowy = 0; if (argc > 1) { strcpy(nazwa, argv[1]);

89 5.1. Detekcja krawędzi 87 //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); // utworzenie obrazu wyjściowego (kodowanie // 32f) na podstawie wejściowego obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_32F, obr_zrodlowy->nchannels); // wywołanie funkcji cvlaplace(obr_zrodlowy, obr_wyjsciowy, 1); //wyświetlenie obrazów vnamedwindow("obraz początkowy", 1); vshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvdestroyallwindows(); return(0); Uwagi dla użytkownika Ze względu na brak skalowania, podobnie jak w przypadku funkcji cvsobel, zaleca się użycie obrazu wyjściowego o odpowiednio dużej głębi (najbezpieczniej 32 bity na piksel). W przypadku ustawienia parametru aperture_size na wartość rzeczywistą mniejszą niż 6 (również ujemną), funkcja wykona się i nie zwróci błędu. Przykłady zastosowań w monitorowaniu jakości produkcji Zastosowanie: operator używany w detekcji krawędzi. Podobnie jak w przypadku operatora Sobela, operator Lapalce a może służyć do znajdowania pęknięć, zarysowań, przebarwień, zmian w fakturze materiału, etc. Na rysunkach 5.5 i 5.6 pokazano jego zastosowanie do znanych już nam przykładów znajdowania defektów pasma miedzianego i korozji. Uwagi na temat algorytmu Funkcja cvlaplace oblicza laplasjan obrazu źródłowego, sumując pochodne drugiego rzędu w kierunkach x i y, obliczone za pomocą operatora Sobela:

90 88 Rozdział 5. Krawędzie i wierzchołki Rysunek 5.5. Pasmo miedzi z defektami i wynik ich wykrywania za pomocą operatora Laplace a Rysunek 5.6. Fragment powierzchni pokrytej rdzą i wynik jej wykrywania za pomocą operatora Laplace a

91 5.1. Detekcja krawędzi 89 dst(x, y) = 2 src x src y 2 Przy parametrze aperture_size=1 otrzymujemy macierz splotu następującej postaci: cvcanny Funkcja realizuje algorytm Canny ego do detekcji krawędzi. Sposób wywołania void cvcanny(const CvArr* image, CvArr* edges, double threshold1, double threshold2, int aperture_size = 3); image obraz źródłowy, edges obraz wyjściowy (zostaną w nim zapisane wykryte krawędzie), threshold1 pierwszy próg, threshold2 drugi próg, aperture_size rozmiar macierzy splotu dla operatora Sobela (analogicznie jak w funkcji cvsobel). Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/pic5.png" ; IplImage* obr_zrodlowy = 0; IplImage* obr_wyjsciowy = 0, * obr_szary = 0; if (argc > 1) { strcpy(nazwa, argv[1]);

92 90 Rozdział 5. Krawędzie i wierzchołki Rysunek 5.7. Wynik działana algorytmu Canny ego na obrazie Lena //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); // utworzenie obrazu wejściowego i~konwersja // do kodowania z jednym kanałem obr_szary = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 1); cvcvtcolor(obr_zrodlowy, obr_szary, CV_BGR2GRAY); //utworzenie obrazu docelowego obr_wyjsciowy = cvcloneimage(obr_szary); // wywołanie funkcji z progami 2 i 50, // macierzą splotu o rozmiarze 3x3 cvcanny(obr_szary, obr_wyjsciowy, 2, 50, 3); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy);

93 5.1. Detekcja krawędzi 91 Rysunek 5.8. Pasmo miedzi z defektami i wynik ich wykrywania za pomocą operatora Canny ego (negatyw) cvreleaseimage(&obr_szary); cvdestroyallwindows(); return(0); Uwagi dla użytkownika Kolejność podawania progów nie ma znaczenia. Funkcja nie kontroluje poprawności zakresu podanych progów. Funkcja działa jedynie dla obrazów z jednym kanałem koloru, a więc zarówno obraz źródłowy, jak i wyjściowy powinny być kodowane w odcieniach szarości. Funkcja działa dla rozmiarów maski 3, 5 i 7. Przykłady zastosowań w monitorowaniu jakości produkcji Wykrywanie krawędzi może służyć do znajdowania pęknięć, zarysowań, przebarwień, zmian w fakturze materiału, etc. Na rysunkach 5.8 i 5.9 pokazano zastosowanie algorytmu Canny ego do znanych już nam przykładów znajdowania defektów pasma miedzianego i korozji. Uwagi na temat algorytmu Funkcja cvcanny znajduje z użyciem algorytmu Canny ego krawędzie na obrazie źródłowym. Wynik, a więc rysunek krawędzi zapisywany jest na obrazie wyjściowym. Mniejszy co do wartości z parametrów progowych threshold1 i threshold2 używany jest do łączenia krawędzi, większy zaś służy do wykrywania początkowych bloków krawędzi. Na podstawie spostrzeżenia, że krawędzie to separatory obszarów obrazu o różnej jasności, bądź kolorze, zaproponowany został efektywny algorytm detekcji krawędzi. Na wejściu potrzebuje on obrazu

94 92 Rozdział 5. Krawędzie i wierzchołki Rysunek 5.9. Obraz korozji i wynik jej wykrywania za pomocą operatora Canny ego (negatyw) z jednym kanałem koloru, dając na wyjściu obraz binarny z wykrytymi krawędziami. Algorytm składa się z 4 etapów: 1. Wygładzanie obrazu Przeprowadzane jest gaussowskie wygładzanie obrazu. 2. Różniczkowanie Obliczany jest gradient obrazu w kierunkach x i y. Uwaga: w przypadku funkcji cvcanny dwa pierwsze etapy są połączone i zaimplementowane za pomocą funkcji cvsobel. 3. Tłumienie wartości lokalnie niemaksymalnych Wiadomo, że punkty krawędzi charakteryzuje duża wartość gradientu. Wykonuje się więc eliminację punktów o wartościach niemaksymalnych w zadanym sąsiedztwie. 4. Progowanie krawędzi Operator Canny ego używa progowania z histerezą opartą na dwóch wartościach progowych: górnej i dolnej. Punkty przekraczające wartość górną są więc akceptowane jako punkty krawędzi, z kolei punkty poniżej wartości dolnej są automatycznie odrzucane. W przypadku punktów spomiędzy zadanych progów, akceptacja następuje jedynie wtedy, gdy są one powiązane z punktami należącymi do krawędzi. Dokładniejszy opis algorytmów znaleźć można w pracach [5], [9], [20].

95 5.2. Detekcja wierzchołków Detekcja wierzchołków cvprecornerdetect Oblicza wstępnie punkty, mogące być wierzchołkami obiektów na obrazie. Wynikiem działania jest obraz z zaznaczonymi punktami wierzchołkowymi. Sposób wywołania void cvprecornerdetect(const CvArr* image, CvArr* corners, int aperture_size = 3); image obraz źródłowy, corners obraz wyjściowy, w którym zostaną zaznaczone potencjalne wierzchołki, aperture_size rozmiar macierzy splotu w operatorze Sobela, analogicznie do funkcji cvsobel. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/pic5.png" ; IplImage* obr_zrodlowy = 0; IplImage* obr_wyjsciowy = 0, * obr_szary = 0; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); // utworzenie obrazu wejściowego i konwersja //do kodowania z jednym kanałem obr_szary = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 1); cvcvtcolor(obr_zrodlowy, obr_szary, CV_BGR2GRAY); //utworzenie obrazu docelowego obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_32F, 1);

96 94 Rozdział 5. Krawędzie i wierzchołki // wywołanie funkcji cvprecornerdetect(obr_szary, obr_wyjsciowy, 3); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvreleaseimage(&obr_szary); cvdestroyallwindows(); return(0); Uwagi dla użytkownika Funkcja działa jedynie dla obrazów z jednym kanałem koloru. Obraz wyjściowy musi być formatu 32-bitowego. Dopuszczalne rozmiary maski splotu: 3, 5 i 7. Przykładowy kod z dokumentacji OpenCV zawiera błąd. Uwagi na temat algorytmu Funkcja ta wykrywa potencjalne wierzchołki na obrazie, szukając punktów, dla których krzywizna krzywej pewnego poziomu luminancji i gradient są jednocześnie odpowiednio duże. Odbywa się to przez obliczenie wartości poniższego wyrażenia opartego na pochodnych obrazu i znalezienie jego lokalnych maksimów: D x 2 D yy + D y 2 D xx 2D x D y D xy gdzie D i i D ii oznaczają kolejno pierwsze i drugie pochodne obrazu liczone z zastosowaniem operatora Sobela. Szersze informacje na temat omawianych tu algorytmów znaleźć można w [20], [3] cvcornereigenvalsandvecs Funkcja oblicza wartości i wektory własne bloków obrazu o zadanym rozmiarze. Najczęstsze zastosowanie detekcja wierzchołków. Sposób wywołania void cvcornereigenvalsandvecs(const CvArr* image, CvArr* eigenvv,

97 5.2. Detekcja wierzchołków 95 int block_size, int aperture_size = 3); image obraz źródłowy, eigenvv obraz wyjściowy (szerokość 6 x szerokość obrazu wejściowego), block_size wielkość sąsiedztwa (pojedynczego bloku), aperture_size rozmiar macierzy splotu w operatorze Sobela, analogicznie do funkcji cvsobel. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/pic5.png" ; IplImage* obr_zrodlowy = 0; IplImage* obr_wyjsciowy = 0, * obr_szary = 0; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); // utworzenie obrazu wejściowego i konwersja // do kodowania z jednym kanałem obr_szary = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 1); cvcvtcolor(obr_zrodlowy, obr_szary, CV_BGR2GRAY); //utworzenie obrazu docelowego o // szerokości 6x większej obr_wyjsciowy = cvcreateimage(cvsize(6 * (obr_zrodlowy->width), obr_zrodlowy->height), IPL_DEPTH_32F, 1); // wywołanie funkcji cvcornereigenvalsandvecs(obr_szary, obr_wyjsciowy, 5, 3); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); //tutaj będą wartości i wektory własne do

98 96 Rozdział 5. Krawędzie i wierzchołki //dalszego wykorzystania, ale wyświetlić można cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvreleaseimage(&obr_szary); cvdestroyallwindows(); return(0); Uwagi dla użytkownika Szerokość obrazu wyjściowego musi być 6-krotnie większa od szerokości obrazu źródłowego. Funkcja działa jedynie dla obrazów z jednym kanałem koloru. Obraz wyjściowy musi być formatu 32-bitowego zmiennoprzecinkowego. Możliwe rozmiary maski splotu: 3, 5 i 7. Rozmiar bloku sąsiedztwa musi być zdefiniowany liczbą nieparzystą 3. Uwagi na temat algorytmu Dla każdego piksela z obrazu wejściowego brane jest pod uwagę sąsiedztwo S(p) rozmiaru block_size x block_size. Funkcja oblicza macierz kowariancji na podstawie pochodnych D x i D y na zadanym sąsiedztwie, zgodnie z zależnością: C = [ Dx 2 Dx D y Dx D y Dy 2 ], gdzie sumowanie odbywa się po bloku sąsiedztwa. Na tej podstawie znajduje wartości własne i wektory własne powyższej macierzy, które zapisywane są w obrazie wyjściowym w porządku (λ 1, λ 2, x 1, y 1, x 2, y 2 ), gdzie λ 1, λ 2 nieposortowane wartości własne macierzy C, (x 1, y 1 ) wektor własny odpowiadający λ 1, (x 2, y 2 ) wektor własny odpowiadający λ 2. Niezbędne pojęcia z zakresu algebry znaleźć można na przykład w [34], [15] cvcornermineigenval Funkcja oblicza najmniejszą wartość własną macierzy gradientu dla bloku sąsiedztwa zadanego rozmiaru. Najczęstsze zastosowanie detekcja wierzchołków.

99 5.2. Detekcja wierzchołków 97 Sposób wywołania void cvcornermineigenval(const CvArr* image, CvArr* eigenval, int block_size, int aperture_size = 3); image obraz źródłowy, eigenval obraz wyjściowy o rozmiarze identycznym z obrazem źródłowym, block_size rozmiar bloku sąsiedztwa, określany analogicznie jak dla funkcji cvcornereigenvalsandvecs, aperture_size rozmiar macierzy splotu w operatorze Sobela, analogicznie do funkcji cvsobel. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0; IplImage* obr_wyjsciowy = 0, * obr_szary = 0; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); // utworzenie obrazu wejściowego i konwersja // do kodowania z jednym kanałem obr_szary = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 1); cvcvtcolor(obr_zrodlowy, obr_szary, CV_BGR2GRAY); //utworzenie obrazu docelowego o //szerokości 6x większej obr_wyjsciowy = cvcreateimage( cvgetsize(obr_zrodlowy), IPL_DEPTH_32F, 1); // wywołanie funkcji cvcornermineigenval(obr_szary, obr_wyjsciowy, 7, 7);

100 98 Rozdział 5. Krawędzie i wierzchołki //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); //tutaj będą wartości i wektory własne do //dalszego wykorzystania, ale wyświetlić można cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvreleaseimage(&obr_szary); cvdestroyallwindows(); return(0); Uwagi dla użytkownika Funkcja działa jedynie dla obrazów z jednym kanałem koloru. Obraz wyjściowy musi być formatu 32-bitowego zmiennoprzecinkowego. Dopuszczalne rozmiary maski splotu: 3, 5 i 7. Rozmiar bloku sąsiedztwa musi być zdefiniowany liczbą nieparzystą 3. Uwagi na temat algorytmu Funkcja ta różni się od funkcji cvcornereigenvalsandvecs tym, że zwraca jedynie najmniejszą z wartości własnych, a więc min(λ 1, λ 2 ) w oznaczeniach analogicznych, jak w opisie cvcornereigenvalsandvecs. Niezbędna pojęcia z zakresu algebry znaleźć można na przykład w [34], [15] cvcornerharris Detektor wierzchołków Harrisa (Harris i Stephens). Sposób wywołania void cvcornerharris(const CvArr* image, CvArr* harris_responce, int block_size, int aperture_size = 3, double k = 0.04); image obraz źródłowy, harris_responce obraz wyjściowy tego samego rozmiaru co źródłowy,

101 5.2. Detekcja wierzchołków 99 block_size rozmiar bloku sąsiedztwa, analogicznie do funkcji cvcornereigenvalsandvecs, aperture_size rozmiar macierzy splotu w operatorze Sobela analogicznie do funkcji cvsobel, k parametr algorytmu Harrisa (wartości sugerowane w literaturze: 0,04 0,15). Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/pic5.png" ; IplImage* obr_zrodlowy = 0; IplImage* obr_wyjsciowy = 0, * obr_szary = 0; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); // utworzenie obrazu wejściowego i konwersja // do kodowania z jednym kanałem obr_szary = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 1); cvcvtcolor(obr_zrodlowy, obr_szary, CV_BGR2GRAY); //utworzenie obrazu docelowego o //szerokości 6x większej obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_32F, 1); // wywołanie funkcji cvcornerharris(obr_szary, obr_wyjsciowy, 5, 5, 0.04); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); //tutaj będą wartości i wektory własne do //dalszego wykorzystania, ale wyświetlić można cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy);

102 100 Rozdział 5. Krawędzie i wierzchołki c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvreleaseimage(&obr_szary); cvdestroyallwindows(); return(0); Uwagi dla użytkownika Funkcja działa jedynie dla obrazów z jednym kanałem koloru. Obraz wyjściowy musi być formatu 32-bitowego zmiennoprzecinkowego. Możliwe rozmiary maski splotu: 3, 5 i 7. Rozmiar bloku sąsiedztwa musi być zdefiniowany liczbą nieparzystą 3. Uwagi na temat algorytmu Funkcja realizuje algorytm detekcji wierzchołków Harrisa. Na początku dla każdego piksela obliczana jest macierz kowariancji gradientu M (podobnie jak w cvcornereigenvalsandvecs) na sąsiedztwie rozmiaru block_size x block_size. Dalej następuje obliczenie wartości wyrażenia opartego na wyznaczniku i śladzie macierzy M: det(m) k trace(m) 2. Wartości te zapisywane są w obrazie wyjściowym. Znalezienie wierzchołków polega na wyznaczeniu lokalnych maksimów wartośc pikseli obrazu wyjściowego. Podstawowe prace na temat algorytmu Harrisa to [14],[15] cvfindcornersubpix Funkcja znajduje dokładniejsze położenie wierzchołków. Sposób wywołania void cvfindcornersubpix(const CvArr* image, CvPoint2D32f* corners, int count, CvSize win, CvSize zero_zone, CvTermCriteria criteria); image obraz źródłowy, corners początkowe współrzędne wierzchołków (na wejściu), współrzędne poprawione (na wyjściu),

103 5.2. Detekcja wierzchołków 101 count liczba wierzchołków, win połowa rozmiaru okna obszar poszukiwań. Przykładowo, jeżeli zdefiniujemy rozmiar jako win=(5,5), wówczas otrzymujemy okno o wielkości = 11 11, zero_zone połowa rozmiaru martwej strefy pośrodku obszaru poszukiwań. W strefie tej nie jest wykonywane sumowanie w podanej formule (w celu uniknięcia sytuacji, gdy macierz autokorelacji staje się osobliwa). Ustawienie wartości na ( 1, 1) oznacza, że nie stosujemy martwej strefy. criteria kryteria stopu iteracyjnego algorytmu poszukiwania wierzchołków. Dopuszczalne kryteria to: maksymalna liczba iteracji albo zadana dokładność. W zależności od ustawienia tego parametru, możliwe jest zastosowanie wybranego kryterium lub połączenie obu. Kryterium iteracji: stała CV_TERMCRIT_ITER. Kryterium dokładności: stała CV_TERMCRIT_EPS. Oba kryteria: CV_TERMCRIT_ITER CV_TERMCRIT_EPS. Powiązania z innymi procedurami OpenCV Do wywołania funkcji konieczne jest utworzenie i wypełnienie obiektu (lub tablicy) typu CvPoint2D32f. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0; IplImage* obr_szary = 0; CvPoint2D32f* punkt = 0; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); // utworzenie obrazu wejściowego i konwersja // do kodowania z jednym kanałem obr_szary = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 1);

104 102 Rozdział 5. Krawędzie i wierzchołki cvcvtcolor(obr_zrodlowy, obr_szary, CV_BGR2GRAY); punkt = (CvPoint2D32f*)cvAlloc(1 * sizeof(cvpoint2d32f)); (*punkt).x = 185; (*punkt).y = 302; //wywołanie funkcji dla jednego wierzchołka, //bez martwego pola, przy obu kryteriach stopu cvfindcornersubpix(obr_szary, punkt, 1, cvsize(150, 150), cvsize(-1, -1), cvtermcriteria(cv_termcrit_iter CV_TERMCRIT_EPS, 50, 0.03)); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); //wypisanie nowego położenia wierzchołka printf("współrzędne: %f, %f.", (*punkt).x, (*punkt).y); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvfree(&punkt); cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_szary); cvdestroyallwindows(); return(0); Uwagi dla użytkownika Funkcja działa jedynie dla obrazów z jednym kanałem koloru. Uwagi na temat algorytmu Funkcja ta znajduje (z dokładnością do podpikseli) położenie wierzchołków lub radialny punkt siodłowy (jak pokazano na załączonym w dokumentacji rysunku). Subpikselowa dokładność oparta jest na obserwacji, że każdy wektor z centrum q do punktu p, położonego w sąsiedztwie q, jest ortogonalny do gradientu obrazu w punkcie p. Rozważmy wyrażenie: ɛ i = I T p i (q p i ), gdzie I pi jest gradientem obrazu w punkcie p i, leżącym w sąsiedztwie q. Wartość q może zostać znaleziona za pomocą minimalizacji ɛ i. Dla ɛ i przyrównanego do

105 5.2. Detekcja wierzchołków 103 zera, otrzymujemy: ( ) I pi Ip T i q i ( ) I pi Ip T i p i = 0, i gdzie sumowanie odbywa się po sąsiedztwie q, zadanym jako okno poszukiwań. Jeżeli oznaczymy pierwsze wyrażenie z gradientem jako G, natomiast drugie jako b, to otrzymamy: q = G 1 b. Algorytm ustala nowe centrum sąsiedztwa w tak znalezionym punkcie q i przeprowadza dalej iteracyjny proces, aż do spełnienia kryterium stopu cvgoodfeaturestotrack Wykrywa na obrazie bardziej wyraziste wierzchołki. Typowe zastosowanie śledzenie ruchu. Sposób wywołania void cvgoodfeaturestotrack(const CvArr* image, CvArr* eig_image, CvArr* temp_image, CvPoint2D32f* corners, int* corner_count, double quality_level, double min_distance, const CvArr* mask = NULL, int block_ = 3, int use_harris = 0, double k = 0.04); image obraz źródłowy, eig_image obraz pomocniczy w formacie 32-bit, tego samego rozmiaru co image. temp_image drugi obraz pomocniczy identyczny, jak eig_image, corners wykryte wierzchołki (parametr wyjściowy), corner_count maksymalna liczba wierzchołków (wejście), liczba wykrytych wierzchołków (wyjście), quality_level parametr ustalający minimalną dopuszczalną jakość wierzchołków mnożnik dla największej/najmniejszej wartości własnej, min_distance minimalna dopuszczalna odległość euklidesowa pomiędzy wykrytymi wierzchołkami,

106 104 Rozdział 5. Krawędzie i wierzchołki Rysunek Wynik wykrywania wierzchołków na obrazie Lena mask obszar poszukiwań wierzchołków. W przypadku maski NULL, algorytm działa na całym obrazie źródłowym, block_size rozmiar bloku sąsiedztwa dla wywoływanych przez funkcję metod cvcornermineigenval lub cvcornerharris, use_harris parametr określa czy używana jest funkcja cvcornermineigenval (dla zera), czy cvcornerharris w przypadku wartości niezerowej, k parametr algorytmu Harrisa, używany jedynie dla use_harris. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c, j, ile = 500; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, * obr_wyjsciowy = 0; IplImage* obr_szary = 0, * wlasne = 0, * obr_tymczasowy = 0; CvPoint2D32f* punkt = 0;

107 5.2. Detekcja wierzchołków 105 if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); // utworzenie obrazu wejściowego i konwersja do // kodowania z jednym kanałem obr_szary = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 1); cvcvtcolor(obr_zrodlowy, obr_szary, CV_BGR2GRAY); //utworzenie obrazów pomocniczych i // wyjściowego obr_wyjsciowy = cvcloneimage(obr_zrodlowy); wlasne = cvcreateimage(cvgetsize(obr_szary), 32, 1); obr_tymczasowy = cvcreateimage(cvgetsize(obr_szary), 32, 1); // alokacja pamięci do przechowywania // wykrytych wierzchołków punkt = (CvPoint2D32f*)cvAlloc(ile * sizeof(cvpoint2d32f)); // wywołanie funkcji z maksymalną iloscią // wierzchołków ile, działającej dla całego // obrazu cvgoodfeaturestotrack(obr_szary, wlasne, obr_tymczasowy, punkt, &ile, 0.01, 10, 0, 3, 0, 0.04); // zaznaczenie znalezionych wierzchołków //na obrazie w postaci kół for (j = 0; j < ile; j++) { cvcircle(obr_wyjsciowy, cvpointfrom32f(*(punkt + j)), 5, CV_RGB(0, 255, 0), -1, 8, 0); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvfree(&punkt);

108 106 Rozdział 5. Krawędzie i wierzchołki Rysunek Wykrywanie defektów algorytmem detekcji wierzchołków cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_szary); cvreleaseimage(&wlasne); cvreleaseimage(&obr_tymczasowy); cvreleaseimage(&obr_wyjsciowy); cvdestroyallwindows(); return(0); Uwagi dla użytkownika Funkcja działa jedynie dla obrazów z jednym kanałem koloru. Przykłady zastosowań w monitorowaniu jakości produkcji Na dwóch obrazach dalej pokazano dość nietypowe zastosowanie tej funkcji mianowicie użycie jej do detekcji defektów. Przykładami są znane już obrazy pasma miedzi i korozji. Dobierając odpowiednio paramtery algorytmu, możemy sterować wielkością wykrywanych defektów. Uwagi na temat algorytmu Funkcja cvgoodfeaturestotrack znajduje na obrazie wierzchołki o dużych wartościach własnych. W fazie początkowej, z wykorzystaniem jednej z funkcji cvcornermineigenval lub cvcornerharris, obliczana jest najmniejsza wartość własna dla każdego piksela obrazu źródłowego. Wynik tej operacji zapisywany

109 5.2. Detekcja wierzchołków 107 jest w eig_image. Następnie odbywa się odsianie wartości niemaksymalnych pozostają jedynie maxima lokalne na obszarach 3 x 3. Kolejny krok polega na odrzuceniu wierzchołków o najmniejszych wartościach własnych, a więc mniejszych niż quality_level max(eig_image(x,y)). W ostatnim kroku funkcja sprawdza warunki minimalnej dopuszczalnej odległości między znalezionymi wierzchołkami, pozostawiając, w przypadku zbyt blisko siebie umieszczonych, jedynie wierzchołki najmocniejsze.

110

111 Rozdział 6 Progowanie Progowaniu poświęcimy szczególnie dużo uwagi, gdyż ta prosta operacja jest nieoceniona jako składnik w bardziej złożonych zadaniach przetwarzania obrazów. Mimo że w rozdziale tym omówiono wiele wariantów progowania, to warto zaznaczyć, że i tak nie są to wszystkie jego odmiany. W pracy [30] opisano metodę progowania z histerezą, jako szczególnie użyteczną w zagadnieniach przetwarzania obrazów przemysłowych, w których poziom szarości defektu niewiele różni się od poziomu tła. Odsyłamy też Czytelnika do obszernej literatury, dotyczącej problemu doboru progu [18], [7]. Warto zaznaczyć, że podstawowym krokiem w doborze progu jest obliczenie histogramu poziomów szarości obrazu. Jeśli histogram ten ma postać dwóch, oddzielonych od siebie, maksimów, to jako wartość progu przyjmuje się połowę odległości ich położenia. Dodajmy, że biblioteka OpenCV zawiera procedury obliczania histogramu Funkcja cvthreshold Funkcja cvthreshold proguje obrazy, stosując stały poziom odniesienia. Jej typowe przeznaczenie, to otrzymywanie obrazu binarnego z obrazu w skali szarości lub usuwanie szumu, np. przez odfiltrowanie pikseli o zbyt małych lub zbyt dużych wartościach. Przewidziano 5 rodzajów obsługiwanego progowania. Sposób wywołania void cvthreshold(const CvArr + src, CvArr + dst, double threshold, double max_value, int threshold_type); src tablica wejściowa, np. zawierająca wejściowy obraz (pojedyncze kanały 8-bitowe z 32-bit liczb zmiennoprzecinkowych) dst tablica wyjściowa, musi być tego samego typu co src lub 8-bitowa. threshold wartość progu.

112 110 Rozdział 6. Progowanie Rysunek 6.1. Wynik progowania binarnego max_value wartość maksymalna, potrzeba przy użyciu typów progowania CV_THRESH_BINARY oraz CV_THRESH_BINARY_INV. threshold_type sposób progowania, patrz dalej Progowanie binarne CV_THRESH_BINARY; Dla wartości sygnału większej od wartości progu funkcja przyporządkowuje wartość max_value, w przeciwnym wypadku (gdy wartość sygnału jest mniejsza od wartości progu) wartość wynosi 0. Odwrócone progowanie binarne CV_THRESH_BINARY_INV; Dla wartości sygnału większej od wartości progu funkcja przyporządkowuje wartość 0, w przeciwnym wypadku (gdy wartość sygnału jest mniejsza od wartości progu) wartość max_value. Progowanie okrawające CV_THRESH_TRUNC;

113 6.1. Funkcja cvthreshold 111 Rysunek 6.2. Wynik odwróconego progowania binarnego Dla wartości sygnału większych od wartości progu przyporządkowywana jest wartość tego progu, natomiast dla wartości mniejszych od wartości progu, wartość sygnału nie jest zmieniana. Progowanie do zera Ten rodzaj progowania ma dwa warianty, opisane dalej. Progowanie proste CV_THRESH_TOZERO; Dla wartości sygnału większych od wartości progu przyporządkowywana jest wartość 0, natomiast dla wartości mniejszych od wartości progu, wartość sygnału nie jest zmieniana. Progowanie odwrotne CV_THRESH_TOZERO_INV: Dla wartości sygnału większych od wartości progu wartość sygnału nie jest zmieniana, natomiast dla wartości mniejszych od wartości progu przyporządkowywana jest wartość 0.

114 112 Rozdział 6. Progowanie Rysunek 6.3. Wynik progowania do zera Rysunek 6.4. Wynik progowania odwrotnego do zera

115 6.2. Przykłady zastosowań 113 Uwaga Funkcja oczekuje, by obraz wyjściowy był obrazem w skali szarości (podczas tworzenia obrazu ustawić IPL_DEPTH_8U) Przykłady zastosowań Dalej przedstawiamy proste przykłady wywołania procedury progowania i jej wariantów oraz wyniki testowania. W dalszej części tego podrozdziału zamieszczono wyniki zastosowania progowania do wykrywania defektów na podstawie obrazów przemysłowych Przykłady standardowe #include <stdio.h> #include <stdlib.h> #include <math.h> #include "cv.h" #include "highgui.h" int main() { IplImage + cvsourceimg = NULL; IplImage + cvprocimg = NULL; double threshold; double max_value; int threshold_type; /* Czynności wstępne */ /* Odczytaj obraz, wymuś konwersje na odcienie szarości */ cvsourceimg = cvloadimage("lena.jpg", 0); /* Otwórz okienka na obraz zarodkowy i wyświetl go*/ cvnamedwindow("source", 1); cvshowimage("source", cvsourceimg); /* Przygotowanie miejsca na obrazy */ cvprocimg = cvcreateimage(cvsize(cvsourceimg->width, cvsourceimg->height),

116 114 Rozdział 6. Progowanie IPL_DEPTH_8U, 1); /* Teraz możemy zając się przetwarzaniem */ threshold = 100; max_value = 255; threshold_type = CV_THRESH_TOZERO; //CV_THRESH_TRUNC;CV_THRESH_BINARY;CV_THRESH_TOZERO cvthreshold(cvsourceimg, cvprocimg, threshold, max_value, threshold_type); /* Wyświetlamy przygotowany obraz */ cvnamedwindow("dest", 1); cvshowimage("dest", cvprocimg); /* Czekamy na klawisz i kończymy */ cvwaitkey(0); cvdestroywindow("source"); cvdestroywindow("dest"); return(0); Test 1 Fragment kodu: for (i = 1; i < 255; i++) for (j = 0; j < 255; j++) { threshold = i; max_value = j; threshold_type = CV_THRESH_BINARY; cvthreshold(cvsourceimg, cvprocimg, threshold, max_value, threshold_type); wynik zwrócony przez time (bez wyświetlania obrazów pośrednich): real 0m29.037s user 0m29.006s sys 0m0.032s

117 6.2. Przykłady zastosowań 115 Test 2 Fragment kodu: for (i = 1; i < 255; i++) for (j = 0; j < 255; j++) { threshold = i; max_value = j; threshold_type = CV_THRESH_BINARY_INV; cvthreshold(cvsourceimg, cvprocimg, threshold, max_value, threshold_type); wynik zwrócony przez time (bez wyświetlania obrazów pośrednich): real 0m29.048s user 0m29.030s sys 0m0.020s Test 3 Fragment kodu: for (i = 1; i < 255; i++) for (j = 0; j < 255; j++) { threshold = i; max_value = j; threshold_type = CV_THRESH_TRUNC; cvthreshold(cvsourceimg, cvprocimg, threshold, max_value, threshold_type); trzeba zaznaczyć, iż ta wersja progowania nie wykorzystuje wartości max_value, jednak sprawdza, czy dla żadnej wartości nie wystąpi błąd. Wynik zwrócony przez time (bez wyświetlania obrazów pośrednich): real 0m29.339s user 0m29.298s sys 0m0.040s Test 4 Fragment kodu: for (i = 1; i < 255; i++) for (j = 0; j < 255; j++) {

118 116 Rozdział 6. Progowanie threshold = i; max_value = j; threshold_type = CV_THRESH_TOZERO; cvthreshold(cvsourceimg, cvprocimg, threshold, max_value, threshold_type); zaznaczmy, iż ta wersja progowania nie wykorzystuje wartości max_value. Wynik zwrócony przez time (bez wyświetlania obrazów pośrednich): real 0m29.388s user 0m29.350s sys 0m0.040s Test 5 Fragment kodu: for (i = 1; i < 255; i++) for (j = 0; j < 255; j++) { threshold = i; max_value = j; threshold_type = CV_THRESH_TOZERO_INV; cvthreshold(cvsourceimg, cvprocimg, threshold, max_value, threshold_type); zaznaczamy, iż ta wersja progowania nie wykorzystuje wartości max_value, jednak sprawdza czy dla każdej wartości program pracuje poprawnie. Wynik zwrócony przez time (bez wyświetlania obrazów pośrednich): real 0m28.990s user 0m28.946s sys 0m0.044s W ten sposób przetestowane zostały wszystkie możliwe kombinacje parametrów dla funkcji. Używając polecenia free -m nie stwierdzono wycieków pamięci. Uwagi dla użytkownika Należy pamiętać, by obraz wyjściowy był obrazem w skali szarości, gdyż takiej deklaracji wymaga ta funkcja.

119 6.3. Zastosowanie do wykrywania defektów 117 Rysunek 6.5. Fragment powierzchni pokrytej rdzą Rysunek 6.6. Stopień skorodowania wykryty za pomocą progowania z progiem Zastosowanie do wykrywania defektów Na rysunku 6.5 pokazano fragment metalowej powierzchni pokrytej rdzą. Stopień skorodowania nie jest jednakowy w poszczególnych częściach obrazu. Stosując różne wartości progu, możemy wykryć fragmenty o różnym stopniu skorodowania. Ilustrują to obrazy pokazane na rysunkach Zastosowanie progowania do wykrywania defektów na powierzchni pasma miedzi pokazano na rysunku 6.9 (obraz oryginalny) i 6.10 (obraz binarny). Wielkość wykrytych defektów można dobierać za pomocą wartości progu. Wykrywanie zbyt małych defektów może nie być korzystne, wówczas, gdy nie mają one wpływu na końcową jakość produktu.

120 118 Rozdział 6. Progowanie Rysunek 6.7. Stopień skorodowania wykryty za pomocą progowania z progiem 60 Rysunek 6.8. Stopień skorodowania wykryty za pomocą progowania z progiem 65

121 6.3. Zastosowanie do wykrywania defektów 119 Rysunek 6.9. Pasmo miedzi z defektami Rysunek Pasmo z defektami wykrytymi za pomocą progowania z progiem 96

122

123 Rozdział 7 Operacje morfologiczne Operacje morfologiczne są takim działem teorii przetwarzania obrazów, który ma dobrze sformalizowane i zrozumiałe podstawy matematyczne, a jednocześnie wyniki poszczególnych operacji można intuicyjnie przewidzieć. Te walory nie powinny jednak przesłaniać faktu, że o możliwości zastosowania operacji morfologicznych do przetwarzania obrazów w czasie rzeczywistym decyduje efektywna implementacja. Funkcje biblioteki OpenCV opisane w tym rozdziale zawierają podstawowe, najczęściej wykorzystywane operacje morfologiczne. Należą do nich: erozja, dylatacja i ich złożenia. W rozdziale tym nie przytoczono przykładów zastosowania operacji morfologicznych do przetwarzania obrazów przemysłowych. Nie oznacza to jednak, że operacji tych nie można w tym obszarze stosować. Wręcz przeciwnie, oddają one nieocenione usługi, na przykład, w pozbywaniu się z obrazów wykrytych obiektów, które albo nie są defektami, albo są defektami na tyle małymi, że nie będą mieć wpływu na jakość produktu końcowego. Podejście morfologiczne opisane jest dokładnie w wielu książkach [24], [18] Element strukturalny cvcreatestructuringelementex Funkcja tworzy element strukturalny typu IplConvKernel do przeprowadzania operacji morfologicznych i zwraca do niego wskaźnik. Sposób wywołania IplConvKernel* cvcreatestructuringelementex(int cols, int rows, int anchor_x,

124 122 Rozdział 7. Operacje morfologiczne int anchor_y, int shape, int* values = NULL); cols liczba kolumn w elemencie strukturalnym, rows liczba wierszy w elemencie strukturalnym, anchor_x względne przesunięcie wzdłuż osi x punktu zakotwiczenia, anchor_y względne przesunięcie wzdłuż osi y punktu zakotwiczenia, shape kształt elementu strukturalnego: CV SHAPE RECT: prostokątny CV SHAPE CROSS: krzyżowy; CV SHAPE ELLIPSE: eliptyczny; CV SHAPE CUSTOM: kształt zdefiniowany przez użytkownika. W tym przypadku parametr values określa maskę, a więc to, które piksele z sąsiedztwa będą brane pod uwagę. values wskaźnik do danych elementu strukturalnego (tylko dla CV_SHAPE_ CUSTOM), tablica reprezentująca punkty należące do niego. Niezerowe wartości jej elementów oznaczają, że należą one do definiowanego kształtu. W przypadku wskaźnika NULL, zakłada się, że wszystkie elementy mają wartość niezerową, oznaczając kształt prostokąta. Powiązania z innymi procedurami OpenCV Utworzony przez funkcję obiekt należy po użyciu usunąć za pomocą procedury cvreleasestructuringelement. Standardowe przykłady Patrz cverode. Uwagi na temat algorytmu Funkcja ta alokuje odpowiedni obszar pamięci a także wypełnia element typu IplConvKernel, mogący potem służyć jako element strukturalny do przeprowadzania operacji morfologicznych cvreleasestructuringelement Funkcja usuwa element strukturalny typu IplConvKernel. Sposób wywołania void cvreleasestructuringelement(iplconvkernel** element); element wskaźnik (podwójny) do elementu strukturalnego.

125 7.2. Erozja, dylatacja i ich kombinacje 123 Powiązania z innymi procedurami OpenCV Funkcja może zostać wywołana dla obiektów zainicjalizowanych funkcją cvcreatestructuringelementex. Standardowe przykłady Patrz cverode. Uwagi na temat algorytmu Funkcja usuwa element typu IplConvKernel, który już nie jest potrzebny. W przypadku wywołania na wskaźniku NULL, funkcja nie wykonuje żadnych operacji Erozja, dylatacja i ich kombinacje cverode Funkcja przeprowadza erozję obrazu, z użyciem zdefiniowanego wcześniej elementu strukturalnego. Sposób wywołania void cverode(const CvArr* src, CvArr* dst, IplConvKernel* element = NULL, int iterations = 1); src obraz źródłowy, dst obraz wyjściowy, element element strukturalny do wykonania erozji, w przypadku wartości NULL stosowany jest element będący prostokątem o rozmiarach 3 x 3, iterations liczba iteracji procesu erozji. Powiązania z innymi procedurami OpenCV Funkcja wymaga podania elementu strukturalnego typu IplConvKernel, utworzonego i wypełnionego funkcją cvcreatestructuringelementex. Standardowe przykłady #include <cv.h> #include <highgui.h>

126 124 Rozdział 7. Operacje morfologiczne int main(int argc, char** argv) { int c, x = 2; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, * obr_wyjsciowy = 0; IplConvKernel* element = 0; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu wyjściowego obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3); // utworzenie i wypełnienia elementu element = cvcreatestructuringelementex(x * 2 + 1, x * 2 + 1, x, x, CV_SHAPE_RECT, 0); //wywołanie funkcji do przeprowadzenia //dziesięciokrotnej erozji cverode(obr_zrodlowy, obr_wyjsciowy, element, 10); // wywołanie funkcji usuwającej element cvreleasestructuringelement(&element); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvdestroyallwindows(); return(0);

127 7.2. Erozja, dylatacja i ich kombinacje 125 Rysunek 7.1. Operacja erozji na obrazie Lena Uwagi na temat algorytmu Funkcja przeprowadza erozję obrazu z użyciem zdefiniowanego uprzednio elementu strukturalnego, określającego kształt sąsiedztwa piksela, w którym szukane jest minimum. Funkcja może działać w trybie in-place, gdzie obraz źródłowy jest równocześnie obrazem modyfikowanym. Liczba przeprowadzanych procesów erozji określa parametr iterations. W przypadku obrazów kolorowych, każdy kanał koloru jest przetwarzany oddzielnie cvdilate Funkcja przeprowadza dylatację obrazu z użyciem zdefiniowanego wcześniej elementu strukturalnego. Sposób wywołania void cvdilate(const CvArr* src, CvArr* dst, IplConvKernel* element = NULL, int iterations = 1); src obraz źródłowy, dst obraz wyjściowy,

128 126 Rozdział 7. Operacje morfologiczne Rysunek 7.2. Operacja dylatacji na obrazie Lena element element strukturalny do wykonania dylatacji, w przypadku wartości NULL stosowany jest element będący prostokątem o rozmiarach 3 x 3, iterations liczba iteracji procesu erozji. Powiązania z innymi procedurami OpenCV Funkcja wymaga podania elementu strukturalnego typu IplConvKernel, utworzonego i wypełnionego funkcją cvcreatestructuringelementex. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c, x = 2; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, * obr_wyjsciowy = 0; IplConvKernel* element = 0; if (argc > 1) { strcpy(nazwa, argv[1]);

129 7.2. Erozja, dylatacja i ich kombinacje 127 //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu wyjściowego obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3); // utworzenie i wypełnienia elementu element = cvcreatestructuringelementex(x * 2 + 1, x * 2 + 1, x, x, CV_SHAPE_RECT, 0); //wywołanie funkcji do przeprowadzenia // dziesięciokrotnej dylatacji cvdilate(obr_zrodlowy, obr_wyjsciowy, element, 10); // wywołanie funkcji usuwającej element cvreleasestructuringelement(&element); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy); cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvdestroyallwindows(); return(0); Uwagi na temat algorytmu Funkcja przeprowadza dylatację obrazu z użyciem zdefiniowanego elementu strukturalnego, określającego kształt sąsiedztwa piksela, w którym szukane jest maksimum. Funkcja może działać w trybie in-place, gdzie obraz źródłowy jest równocześnie obrazem modyfikowanym. Liczba przeprowadzanych procesów dylatacji określa parametr iterations. W przypadku obrazów kolorowych, każdy kanał koloru przetwarzany jest oddzielnie cvmorphologyex Przeprowadza zaawansowane operacje morfologiczne: domknięcia, otwarcia, obliczenia gradientu morfologicznego i filtracji morfologicznej.

130 128 Rozdział 7. Operacje morfologiczne Rysunek 7.3. Wynik wielokrotnego zastosowania operacji otwarcia do obrazu Lena Sposób wywołania void cvmorphologyex(const CvArr* src, CvArr* dst, CvArr* temp, IplConvKernel* element, int operation, int iterations = 1); src obraz źródłowy, dst obraz wyjściowy, temp obraz pomocniczy, wymagany w niektórych przypadkach, element element strukturalny, operation operacja morfologiczna, jedna z poniższych: CV MOP OPEN otwarcie, CV MOP CLOSE domknięcie, CV MOP GRADIENT gradient morfologiczny, CV MOP TOPHAT top hat, CV MOP BLACKHAT black hat, iterations liczba iteracji procesu morfologicznego.

131 7.2. Erozja, dylatacja i ich kombinacje 129 Powiązania z innymi procedurami OpenCV Funkcja wymaga podania elementu strukturalnego typu IplConvKernel, utworzonego i wypełnionego funkcją cvcreatestructuringelementex. Standardowe przykłady #include <cv.h> #include <highgui.h> int main(int argc, char** argv) { int c, x = 2; char * nazwa = { "obrazki/lena.jpg" ; IplImage* obr_zrodlowy = 0, * obr_wyjsciowy = 0, * obr_pomocniczy = 0; IplConvKernel* element = 0; if (argc > 1) { strcpy(nazwa, argv[1]); //zaladowanie obrazu wejściowego obr_zrodlowy = cvloadimage(nazwa, 1); //utworzenie obrazu wyjściowego obr_wyjsciowy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3); obr_pomocniczy = cvcreateimage(cvgetsize(obr_zrodlowy), IPL_DEPTH_8U, 3); // utworzenie i wypełnienia elementu element = cvcreatestructuringelementex(x * 2 + 1, x * 2 + 1, x, x, CV_SHAPE_RECT, 0); //wywołanie funkcji do przeprowadzenia //dziesięciokrotnej operacji morfologicznego otwarcia cvmorphologyex(obr_zrodlowy, obr_wyjsciowy, obr_pomocniczy, element, CV_MOP_OPEN, 10); // wywołanie funkcji usuwającej element cvreleasestructuringelement(&element); //wyświetlenie obrazów cvnamedwindow("obraz początkowy", 1); cvshowimage("obraz początkowy", obr_zrodlowy);

132 130 Rozdział 7. Operacje morfologiczne cvnamedwindow("obraz wyjściowy", 1); cvshowimage("obraz wyjściowy", obr_wyjsciowy); c = cvwaitkey(0); //zwolnienie pamięci i usunięcie okien cvreleaseimage(&obr_zrodlowy); cvreleaseimage(&obr_wyjsciowy); cvreleaseimage(&obr_pomocniczy); cvdestroyallwindows(); return(0); Uwagi na temat algorytmu Funkcja wykonuje zaawansowane operacje morfologiczne oparte na erozji i dylatacji. Otwarcie: dst = open(src, element) = dilate(erode(src, element), element) Domknięcie: dst = close(src, element) = erode(dilate(src, element), element) Gradient morfologiczny: dst = morph_grad(src, element) = dilate(src, element) - erode(src, element) Top hat : dst = tophat(src, element) = src - open(src, element) Black hat : dst = blackhat(src, element) = close(src, element) - src Obraz pomocniczy temp jest wymagany do operacji gradientu, oraz operacji top hat i black hat w trybie modyfikacji obrazu źródłowego. Implementowane tutaj algorytmy opisano, między innymi w [18], [36], [24], [22].

133 Rozdział 8 Detekcja ruchu i jej zastosowania W rozdziale tym przedstawiono algorytmy detekcji ruchu, które opierają się na pojęciu przepływu optycznego (por. [17], [23]). Zbadano i opisano dwa algorytmy tej grupy: metodę Lucas Kanade autorem tej części rozdziału jest Paweł Kiełbicki, metodę dopasowywania bloków autorem tej części rozdziału jest Marcin Sałata. Według koncepcji opisanej w raporcie: Ewaryst Rafajłowicz, Konstruowanie algorytmów sieciowych przetwarzania danych z kamery, Raport Instytutu Informatyki, Automatyki i Robotyki, Politechnika Wrocławska, 2008, pokazano, że algorytmy detekcji ruchu służyć mogą do wykrywania defektów w poruszającym się materiale, który powstaje w trakcie produkcji ciągłej, na przykład w procesie walcowania Informacje wprowadzające Pole ruchu Pole ruchu (ang. Motion Field) pokazane na rysunku 8.1 jest reprezentacją czysto geometryczną [4]. Definiuje się je jako pole wektorowe, które powstaje ze zrzutowania trójwymiarowej przestrzeni rzeczywistych wektorów ruchu na płaszczyznę obrazu (patrz [17]). Otrzymane przez nas pole wektorowe ma informację o składowej równoległej ruchu obiektów względem płaszczyzny obrazu. Nie ma natomiast informacji o składowej prostopadłej ruchu. Powoduje to pewne ograniczenie. Nie jest możliwe bowiem odtworzenie pierwotnej informacji rzeczywistych wektorów ruchu według informacji zawartej w polu ruchu. Przepływ optyczny (ang. optical flow, visual flow, optic flow, image velocity) przedstawiony na rysunku 8.2 jest to pole wektorowe podobnie jak pole ruchu, które umożliwia przekształcenie danego obrazu w sekwencji w kolejny jej obraz przez przemieszczenie obszarów pierwszego obrazu (dla których zostało określone

134 132 Rozdział 8. Detekcja ruchu i jej zastosowania Rysunek 8.1. Pole ruchu. Rzutowanie rzeczywistego wektora ruchu na płaszczyznę obrazu to pole), zgodnie z odpowiadającymi im wektorami pola na drugi obraz [17]. Reasumując, przepływ optyczny jest zbiorem translacji (w postaci pola), które przekształca obraz w sekwencji w następny obraz w sekwencji. Przepływ optyczny nie jest ściśle zdeterminowany. Metody wyznaczania przepływu optycznego Stworzono wiele metod wyznaczania przepływu optycznego. Można je podzielić na trzy główne grupy: metody gradientowe bazujące na analizie pochodnych (przestrzennych oraz czasowych) intensywności obrazu, metody w dziedzinie częstotliwości oparte na filtrowaniu informacji obrazowej w dziedzinie częstotliwości, metody korelacyjne bazujące na odpowiedniości obszarów obrazów.

135 8.1. Informacje wprowadzające 133 Rysunek 8.2. Przepływ optyczny: (a) obiekt w czasie t1; (b) obiekt w czasie t2; (c) przepływ optyczny wynikający z obrotu obiektu na rys. (a) i (b) Zastosowanie Optical Flow Od roku 1981, czyli pierwszych poważnych badań wykonanych przez Horna i Schuncka, nastąpił bardzo znaczący rozwój dziedzin wykorzystujących informacje zawarte w polu przepływu optycznego. Dziedzina ta ma zastosowanie, na przykład, w konwersji wideo standardu amerykańskiego NTSC na europejski PAL. W zadaniach nawigacji ruchomych obiektów przepływ optyczny stosuje się w celu wyodrębnienia istotnych cech środowiska oraz wykorzystania ich jako znaczników ruchu. Jason Rife użył dziedziny do śledzenia pęcherzyków powietrza na dnie oceanu. Również w medycynie nie można się obecnie obejść bez przepływu optycznego. Kardiologia wykorzystuje tę metodę do szacowania ruchów serca. Pole przepływu znajduje także zastosowanie do śledzenia pojazdów na autostradach oraz szacowania prędkości ruchu. W Polsce sama technologia związana z przepływem optycznym nie jest jeszcze aż tak rozwinięta jak w Stanach Zjednoczonych, gdzie od 10 lat stosuje się ją w kinematografii. Jest to najbardziej owocnie rozwijający się kierunek, powodujący wzrost efektów specjalnych w filmach. Obecnie na dużą skalę metoda przepływu optycznego obecna jest przy kompresji oraz konwersji wideo do dobrze znanych wszystkim formatów wideo MPEG. Wraz z rozwojem najnowszych programów, korzystających z metod przepływu optycznego, rośnie zapotrzebowanie na sprzęt mogący wykonywać bardziej skomplikowane obliczenia w jak najkrótszym czasie.

136 134 Rozdział 8. Detekcja ruchu i jej zastosowania 8.2. Przepływ optyczny metoda Lucas Kanade Funkcja cvcalcopticalflowlk Opis funkcji Funkcja oblicza przepływ optyczny dla każdego piksela, dlatego obrazy wyjściowe muszą mieć taki sam rozmiar jak wejściowe. Używanie równania przepływu optycznego dla grupy sąsiednich pikseli oraz założenie, że mają one takie same prędkości, redukuje obliczenia przepływu do rozwiązania liniowego systemu. W nieosobliwym systemie dla dwóch pikseli istnieje pojedyncze rozwiązanie. Jednakże mieszane równania dla liczby pikseli większej niż dwa jest bardziej efektywne. Rozwiązanie jest znajdowane z użyciem metody najmniejszych kwadratów. Równania są przeważnie ważone. Dalej przedstawiam używany, liniowy system dwuwymiarowy: x,y W (x, y)i x I y u + x,y W (x, y)i2 y v = x,y W (x, y)i yi t x,y W (x, y)i 2 xu + x,y W (x, y)i xi y v = x,y W (x, y)i x I t (8.1) Gdzie W (x, y) jest oknem Gaussa. Iteracyjne podejście do problemu może umożliwić uzyskanie lepszych wyników. Opis algorytmu Metoda Lucas Kanade przepływu optycznego została opracowana na podstawie następujących publikacji [1], [2], [23]. W implementacji opisywanej metody wyznaczenie przepływu optycznego odbywa się przez minimalizację funkcjonału ze względu na poszukiwaną prędkość optyczną v, opartego na ograniczeniu prędkości optycznej: I v + I t = 0 X Ω W 2 ( x)[ I v + I t ( x, t)] 2 (8.2) Gdzie W ( x) jest funkcją wagową okna i ( x, t) jest gradientem przestrzennym funkcji intensywności, I t ( x, t) jest pochodną cząstkową intensywności obrazu po czasie, x jest wektorem położenia punktu, a t jest momentem czasu. Tak skonstruowany funkcjonał 8.2 minimalizuje się z użyciem metody najmniejszych kwadratów [2]: v = (A T W 2 A) 1 A T W 2 b. (8.3)

137 8.2. Przepływ optyczny metoda Lucas Kanade 135 Gdzie dla n punktów należących do otoczenia (x i Ω) w momencie czasowym t: A = [ i ( x 1 ), i ( x 2 ),..., i ( x n )] T, W = diag[w ( x 1 ), W ( x 2 ),..., W ( x n )], b = (It ( x 1 ), I t ( x 2 ),..., I t ( x n )) T (8.4) Równanie (8.3) istnieje, gdy: [ W 2 A T W 2 ( x)i x 2 A = W 2 ( x)i x ( x)i y ( x) W 2 ( x)i x ( x)i y ( x) ] W 2 ( x)i 2 y (8.5) Gdzie wszystkie sumy są wyznaczane dla sąsiedztwa Ω. Algorytm, który realizuje metodę Lucas Kanade dzieli się na kilka faz. Umożliwia to zdefiniowanie postaci danych wejściowych i wyjściowych danej fazy. Dzięki takiemu sposobowi implementacji można modyfikować algorytm przez wymianę jednej z faz, nie ingerując przy tym w inną fazę. Jedyny warunek jaki musi być spełniony to zachowanie założeń względem danych wejściowych i wyjściowych. Fazy: wyliczenie pochodnych oraz ich iloczynów, następnie regularyzacja iloczynów pochodnych, będąca iloczynem wag oraz gradientów, wyznaczenie kryterium progowego. Danymi wejściowymi dla algorytmu są wartości pochodnych cząstkowych: I x = I x, I y = I y, I t = I t, (8.6) wyznaczone metodami różniczkowania numerycznego opisanymi przez Barrona [2]. Każda ramka jest konwolucją x, y oraz z jądrem o wymiarach 1x5 aby wyliczyć wartości pochodnych (8.6) dla każdego piksela. Opis faz: a) Pierwsza faza algorytmu polega na wyznaczeniu iloczynów odpowiednich pochodnych cząstkowych I 2 x, I 2 y, I x I y, I x I t, I y I t, które będą wykorzystane w kolejnej fazie algorytmu. Jest ona fazą pośrednią, która umożliwia dopasowanie danych wejściowych do potrzeb implementacji, ponieważ wykorzystywana

138 136 Rozdział 8. Detekcja ruchu i jej zastosowania w niej metoda najmniejszych kwadratów operuje właśnie na takich iloczynach pochodnych. Za dane wejściowe algorytmów gradientowych przyjmuje się wartości pochodnych cząstkowych. b) Kolejną z faz algorytmu jest konwolucja iloczynów gradientów z funkcją wagową okna. Ten etap umożliwia wyznaczenie współczynników, które są niezbędne do wyznaczenia prędkości optycznej: W 2 I 2 x, W 2 I 2 y, W 2 I x I y, W 2 I x I t, W 2 I y I t Funkcja wagowa okna jest jednowymiarowym filtrem [2], występująca dla każdego ze współczynników, kolejno w kierunkach pionowym i poziomym. c) Ostatnia faza implementacji algorytmu Lucas Kanade zaczyna się od wyznaczenia wartości własnych macierzy (8.5), wykorzystując poniższe zależności [23]. Dalej przedstawiony jest algorytm postępowania dla macierzy a, w celu wyznaczenia wartości własnych. a 11 a 12 W I 2 x W Ix I y A = = (8.7) a 21 a 22 W Ix I y det(a λi) = 0, W I 2 y (a 11 λ)(a 22 λ) (a 12 ) 2 = 0, = b 2 4ac, λ 1 = b 2a, λ 2 = b +, 2a (8.8) gdzie: a = 1, b = (a 11 + a 22 ), c = a 11 a 22 a Wyznaczone w taki sposób wartości własne wykorzystuje się w kryterium progowym. Kryterium dopuszczające wyznaczenie dwuwymiarowej prędkości optycznej ma postać: (λ 1 τ) oraz (λ 2 τ) (8.9) gdzie τ jest zmienną wartością progu. Kryterium dopuszczające wyznaczenie prędkości normalnej ma postać: (λ 1 τ) oraz (λ 2 < τ) (8.10)

139 8.2. Przepływ optyczny metoda Lucas Kanade 137 Jeżeli założenie 8.10 nie jest spełnione, prędkość optyczna nie jest obliczana. Ma ona wówczas wartość równą zeru. Zastosowanie wartości własnych w kryterium progowym wiąże się z odwróceniem macierzy niezbędnym do wyznaczenia rozwiązania. Wartości własne można uznać za rodzaj miary, która umożliwia określenie dokładności uzyskanego rozwiązania. Sposób wywołania funkcji void cvcalcopticalflowlk(iplimage *imga, IplImage *imgb, CvSize winsize, IplImage *velx, IplImage *vely); *imga obraz wejściowy, będący obrazem odniesienia, *imgb obraz wejściowy, porównywany z obrazem odniesienia, winsize rozmiar okna uśredniającego użytego do grupowania pikseli, *velx składowa pozioma optical flow, *vely składowa pionowa optical flow. Powiązania z innymi funkcjami Funkcja wymaga, aby obrazy wejściowe imga oraz imgb były typu GRAY. W przypadku gdy obrazy wejściowe są RGB, należy użyć funkcji: cvcvtcolor(cvarr* wejscie, CvArr* wyjscie, int flaga) graya = cvcreateimage(cvgetsize(frame1), IPL_DEPTH_8U, 1); Gdzie frame1 jest obrazem wejściowym, natomiast graya jest obrazem wejściowym do funkcji typu GRAY. cvcvtcolor(frame1, graya, CV_BGR2GRAY); Wymieniona funkcja przekształca obraz wejściowy do innej przestrzeni barw. Obsługiwane przestrzenie to: RGB, Grayscale, XYX, YCrCb, HSV, HLS, Lab, Luv. Obrazy velx i vely należy stworzyć funkcją: velx = cvcreateimage(cvgetsize(frame1), IPL_DEPTH_32F,1); vely = cvcreateimage(cvgetsize(frame1), IPL_DEPTH_32F,1); Rozmiar obrazów velx i vely zwracany jest przez funkcję cvgetsize. Przed wywołaniem funkcji cvcalcopticalflowlk należy odpowiednio przygotować obrazy wejściowe. Funkcji cvcvtcolor należy użyć przed każdym wywołaniem cvcalcopticalflowlk. Podczas wywoływania funkcji cvcalcopticalflowlk, rozmiar okna winsize jest typu CvSize. Rozmiar przekazujemy za pomocą funkcji: cvsize(w,h),

140 138 Rozdział 8. Detekcja ruchu i jej zastosowania oznaczającej prostokątny obszar, o początku w punkcie (0, 0), określony z dokładnością pikselową. W celu odszumienia obrazu wejściowego stosowano filtr Gaussa: cvsmooth(frame1, frame1, CV_GAUSSIAN, 7, 7, 1., 1.) Aby zobrazować wykonane operacje na obrazach, należy użyć następujących funkcji: cvnamedwindow(char *nazwa, int flaga) Funkcja tworzy okno o podanej nazwie, nazwa jest nastepnie używana do odwoływania się do okna. Jeżeli flaga=cv_window_autosize, okno automatycznie dostosowuje się do rozmiaru wyświetlanego obrazu. cvshowimage(const char* name, const CvArr* image) Funkcja pokazuje obraz w oknie, które wcześniej inicjujemy za pomocą funkcji cvnamedwindow. Nazwy okien w obu funkcjach muszą być takie same Przykłady standardowe #include "stdafx.h" #include <cv.h> #include <cxcore.h> #include <highgui.h> int dec = 10; double Lth = 5.0, Hth = 20.0; int main(int argc, char** argv) { IplImage *img1 = cvloadimage("sphere.1.jpg", 1); IplImage *img2 = cvloadimage("sphere.2.jpg", 1); cvsmooth(img1, img1, CV_GAUSSIAN, 7, 7, 1., 1.); cvsmooth(img2, img2, CV_GAUSSIAN, 7, 7, 1., 1.); int w = img1->width; int h = img1->height; IplImage *img1_8bit = cvcreateimage(cvsize(w, h), IPL_DEPTH_8U, 1); cvconvertimage(img1, img1_8bit); IplImage *img2_8bit = cvcreateimage(cvsize(w, h), IPL_DEPTH_8U, 1); cvconvertimage(img2, img2_8bit); IplImage *out_8bit = cvcreateimage(cvsize(w, h),

141 8.2. Przepływ optyczny metoda Lucas Kanade 139 IPL_DEPTH_8U, 1); cvfillimage(out_8bit, 1); CvMat *header1 = cvcreatematheader(h, w, CV_8UC1); CvMat *prev = cvgetmat(img1_8bit, header1); CvMat *header2 = cvcreatematheader(h, w, CV_8UC1); CvMat *curr = cvgetmat(img2_8bit, header2); CvMat* velx = cvcreatematheader(h, w, CV_32FC1); cvcreatedata(velx); CvMat* vely = cvcreatematheader(h, w, CV_32FC1); cvcreatedata(vely); #define USE_LK #ifdef USE_LK cvcalcopticalflowlk(prev, curr, cvsize(15, 15), velx, vely); #else #endif cvnamedwindow("x Optical Flow", CV_WINDOW_AUTOSIZE); cvnamedwindow("y Optical Flow", CV_WINDOW_AUTOSIZE); cvnamedwindow("pierwszy Obraz", CV_WINDOW_AUTOSIZE); cvnamedwindow("drugi Obraz", CV_WINDOW_AUTOSIZE); cvnamedwindow("vector", CV_WINDOW_AUTOSIZE); cvshowimage("x Optical Flow", velx); cvshowimage("y Optical Flow", vely); cvshowimage("pierwszy Obraz", prev); cvshowimage("drugi Obraz", curr); int i, j; int r = 1; double dx, dy, vel; for (i = 0; i < img1->height; i += dec) { for (j = 0; j < img1->width; j += dec) { dx = cvgetreal2d(velx, i, j); dy = cvgetreal2d(vely, i, j); vel = sqrt(dx * dx + dy * dy); if ((vel >= Lth) && (vel <= Hth)) { cvline(out_8bit, cvpoint(j, i), cvpoint(j + (int)dx, i + (int)dy), CV_RGB(255, 255, 255), 1, 8, 0); cvcircle(out_8bit, cvpoint(j + (int)dx, i + (int)dy),r, CV_RGB(255, 255, 255), 1, 8, 0);

142 140 Rozdział 8. Detekcja ruchu i jej zastosowania cvshowimage("vector", out_8bit); cvwaitkey(0); cvreleaseimage(&out_8bit); cvreleaseimage(&img1_8bit); cvreleaseimage(&img2_8bit); return(0); Dalej przedstawiony jest standardowy przykład wykrywania ruchu obracającej się sfery. Rysunki wizualizują zwracane przez funkcję składowe x oraz y przepływu optycznego, a także pole przepływu optycznego. Uwagi dla użytkownika W instrukcji OpenCV nie ma dokładnego opisu w jaki sposób wizualizować obliczone pole przepływu optycznego. Nie jest również sprecyzowany maksymalny rozmiar okna winsize. Funkcje testowano pod Windowsem przy użyciu Microsoft Visual Studio Uwagi na temat działania algorytmu Maksymalny rozmiar okna winsize w funkcji cvcalcopticalflowlk był ustawiany na cvsize(15,15). Gdy ustawiona została większa wartość, program przestawał działać. W celu wizualizacji przepływu optycznego wprowadziłem dodatkowe zmienne określające przedział prędkości, jakie chciałem wykrywać. W zastosowanym algorytmie nie występuje 3. faza, czyli decyzja o prędkości przepływu optycznego. W przypadku dwuwymiarowego układu liniowego, stosowane jest rozwiązanie metodą Kramera. W przypadku jednowymiarowego układu liczona jest prędkość zgodna z gradientem przepływu. Dalej przedstawiam kod wykorzystany do wizualizacji przepływu optycznego. double Lth = 5.0, Hth = 10.0; for (int i = 0; i < frame1->height; i += 20) { for (int j = 0; j < frame1->width; j += 20) { dx = cvgetreal2d(velx, i, j); //wektor przemieszczenia // po osi x dy = cvgetreal2d(vely, i, j); //wektor przemieszczenia // po osi y

143 8.2. Przepływ optyczny metoda Lucas Kanade 141 Rysunek 8.3. Przepływ optyczny dla przykładu obracającej sfery vel = sqrt(dx * dx + dy * dy); //wylicza predkość przepływu //optycznego Jeżeli wyliczona przez prędkość vel znajduje się w podanym przedziale, to program zwizualizuje wektor przemieszczenia punktu pomiędzy dwoma klatkami. CvScalar line_color; line_color = CV_RGB(255, 255, 255); cvline(graya, cvpoint(j, i), cvpoint(j + (int)dx, i + (int)dy), line_color, 1, CV_AA, 0); // rysuje wektor przemieszczenia piksela // pomiędzy dwoma klatkami obrazu.

144 142 Rozdział 8. Detekcja ruchu i jej zastosowania cvcircle(graya, cvpoint(j + (int)dx, i + (int)dy), r, CV_RGB(255, 255, 255), 1, 8, 0); Przykłady zastosowań w monitorowaniu jakości produkcji Dalej przedstawiony jest kod źródłowy programu wykorzystującego funkcję cvcalcopticalflowlk do wykrywania ruchu w sekwencji obrazów. #include "stdafx.h" #include <cv.h> #include <highgui.h> #include <math.h> #include <iostream> #include <conio.h> double Lth = 5.0, Hth = 10.0; using namespace std; int main(int argc, char** argv) { IplImage *graya = NULL; IplImage *grayb = NULL; IplImage *velx = NULL; IplImage *vely = NULL; int flag = 0; CvCapture* obraz = cvcapturefromfile("c:/bezfseg3crop.avi"); IplImage* frame1 = cvqueryframe(obraz); graya = cvcreateimage(cvgetsize(frame1), IPL_DEPTH_8U, 1); grayb = cvcreateimage(cvgetsize(frame1), IPL_DEPTH_8U, 1); velx = cvcreateimage(cvgetsize(frame1), 32, 1); vely = cvcreateimage(cvgetsize(frame1), 32, 1); while (frame1) { IplImage* frame1 = cvqueryframe(obraz); cvsmooth(frame1, frame1, CV_GAUSSIAN, 7, 7, 1., 1.); graya->origin = frame1->origin; grayb->origin = frame1->origin; cvcvtcolor(frame1, graya, CV_BGR2GRAY); if (flag == 0) { flag = 1; cvcopy(graya, grayb, NULL); else { double dx, dy, vel; cvcalcopticalflowlk(grayb, graya, cvsize(3, 3),

145 8.2. Przepływ optyczny metoda Lucas Kanade 143 velx, vely); for (int i = 0; i < frame1->height; i += 20) { for (int j = 0; j < frame1->width; j += 20) { dx = cvgetreal2d(velx, i, j); //wektor // przemieszczenia po osi x dy = cvgetreal2d(vely, i, j); //wektor //przemieszczenia po osi y vel = sqrt(dx * dx + dy * dy); //wylicza predkosc //przeplywu optycznego if ((vel >= Lth) && (vel <= Hth)) { int r = 1; CvScalar line_color; line_color = CV_RGB(255, 255, 255); cvline(graya, cvpoint(j,i), cvpoint(j + (int)dx, i + (int)dy), line_color, 1, CV_AA, 0); // rysuje linie (wektor laczacy ten sam // punkt ale na roznych klatkach) cvcircle(graya,cvpoint(j+(int)dx, i + (int)dy),r, CV_RGB(255, 255, 255), 1, 8, 0); cvcopy(graya, grayb, NULL); cvnamedwindow("x Optical Flow", CV_WINDOW_AUTOSIZE); cvnamedwindow("y Optical Flow", CV_WINDOW_AUTOSIZE); cvnamedwindow("optical Flow", CV_WINDOW_AUTOSIZE); cvshowimage("x Optical Flow", velx); cvshowimage("y Optical Flow", vely); cvshowimage("optical Flow", graya); cvwaitkey(30); return(0); Przedstawiamy efekty działania powyższego programu dla różnych wartości parametrów.

146 144 Rozdział 8. Detekcja ruchu i jej zastosowania Rysunek 8.4. Składowa x przepływu dla winsize (3,3) i zakresu prędkości (5,10) Rysunek 8.5. Składowa y przepływu dla winsize (3,3) i zakresu prędkości (5,10) 8.3. Metoda dopasowywania bloków cvcalcopticalflowbm Funkcja oblicza optical flow dla nachodzących na siebie bloków. Pola prędkości (ang. velocity fields) są mniejsze od oryginalnych obrazów (pola prędkości reprezentują bloki, a nie piksele). Dla każdego bloku z pierwszego obrazu funkcja stara się znaleźć podobny blok na drugim obrazie. Funkcja może szukać w sąsiedztwie oryginalnego bloku lub w przesuniętym obszarze (przesunięcie wylicza się na podstawie poprzedniego wywołania funkcji). Sposób wywołania void cvcalcopticalflowbm(iplimage *imga, IplImage *imgb, CvSize blocksize, CvSize shiftsize, CvSize maxrange, int useprevious, IplImage *velx, IplImage *vely);

147 8.3. Metoda dopasowywania bloków 145 Rysunek 8.6. Pole przepływu optycznego dla winsize (3,3) i zakresu prędkości (5,10) Rysunek 8.7. Składowa x przepływu dla winsize (3,3) i zakresu prędkości (10,20) *imga pierwszy obraz, 8-bitowy, 1-kanałowy *imgb drugi obraz, 8-bitowy, 1-kanałowy blocksize rozmiar bloku w pikselach shiftsize przesunięcie bloku w kolejnych inkrementacjach (w pikselach) maxrange maksymalny rozmiar (w pikselach) sąsiedztwa wokół bloku, które będzie przeszukiwane useprevious użyj poprzedniego (wejściowego) pola szybkości (ang.velocity field) *velx komponent x (poziomy) optical flow *vely komponent y (pionowy) optical flow Parametr useprevious określa sposób w jaki funkcja określi pozycję startową podczas przeszukiwania sąsiedztwa danego bloku na obrazie imgb. Jeśli ten parametr ustalimy na 0 funkcja zacznie przeszukiwanie w oryginalnej pozycji bloku. Natomiast gdy useprevious = 1 wówczas sąsiedztwo bloku będzie przesunięte według zależności (ustalane jest na podstawie poprzednich pól prędkości velx i vely): (velx(x0, y0), vely(x0, y0))

148 146 Rozdział 8. Detekcja ruchu i jej zastosowania Rysunek 8.8. Składowa y przepływu dla winsize (3,3) i zakresu prędkości (10,20) Rysunek 8.9. Pole przepływu optycznego dla winsize (3,3) i zakresu prędkości (10,20) Powiązania z innymi funkcjami Funkcja wymaga, aby obrazy wejściowe imga oraz imgb były typu GRAY. Czyli jeżeli obrazy wejściowe są RGB, należy użyć funkcji: obrazwejsciowydofunkcji = cvcreateimage(cvgetsize(obrazwejsciowy), IPL_DEPTH_8U, 1); cvcvtcolor(obrazwejsciowy, obrazwejsciowydofunkcji, CV_BGR2GRAY); Natomiast obrazy velx i vely należy stworzyć funkcją: velx = cvcreateimage(rozmiar, IPL_DEPTH_32F, 1); vely = cvcreateimage(rozmiar, IPL_DEPTH_32F, 1); Rozmiar obrazów velx i vely: rozmiar = cvsize(imga.width / blocksize.width, imga.height / blocksize.height);

149 8.3. Metoda dopasowywania bloków 147 Rysunek Składowa x przepływu dla winsize (15,15) i zakresu prędkości (10,20) Rysunek Składowa y przepływu dla winsize (15,15) i zakresu prędkości (10,20) Więc przed wywołaniem funkcji cvcalcopticalflowbm należy przygotować obrazy wejściowe. Funkcji cvcvtcolor należy użyć przed każdym wywołaniem cvcalc OpticalFlowBM. Podczas wywołania funkcji blocksize, shiftsize, maxrange są typu CvSize. Aby przekazać taki rozmiar można użyć funkcji: cvsize(x, y); Za przeszukiwanie sąsiedztw odpowiada funkcja icvcalcopticalflowbm_8u32fr, którą cvcalcopticalflowbm wywołuje. cvcalcopticalflowbm przetwarza parametry wejściowe i sprawdza je pod kątem poprawności danych. Standardowe przykłady Poniżej przedstawiam kod źródłowy programu wykorzystującego funkcję cv CalcOpticalFlowBM (na rys. 8.13, 8.14 i 8.15 widać efekty działania tej funkcji). Na rysunku 1 przedstawiono wynik działania dla prostej sekwencji obrazów (ruchome obiekty znacznie różnią się od tła). Natomiast na rysunkach 8.14 i 8.15

150 148 Rozdział 8. Detekcja ruchu i jej zastosowania Rysunek Pole przepływu dla winsize (15,15) i zakresu prędkości (10,20) przedstawiono wynik działania funkcji dla bardziej złożonej sekwencji (ruchome obiekty są podobne do tła). #include <cv.h> #include <highgui.h> #include <math.h> #include <conio.h> int main(int argc, char* argv[]) { IplImage* OriginalImage; IplImage* ProcessingImage; IplImage* graya; IplImage* grayb; IplImage* velx, *vely; CvCapture* filma = cvcapturefromfile(argv[1]); CvCapture* filmb = cvcapturefromfile(argv[1]); cvnamedwindow("main Window", 1); cvnamedwindow("vx", 1); cvnamedwindow("vy", 1); OriginalImage = cvqueryframe(filma); ProcessingImage = cvqueryframe(filmb); ProcessingImage = cvqueryframe(filmb); CvSize size = cvsize((originalimage->width) / 16, (OriginalImage->height) / 16); graya = cvcreateimage(cvgetsize(originalimage), IPL_DEPTH_8U, 1); grayb = cvcreateimage(cvgetsize(processingimage),

151 8.3. Metoda dopasowywania bloków 149 IPL_DEPTH_8U, 1); velx = cvcreateimage(size, IPL_DEPTH_32F, 1); vely = cvcreateimage(size, IPL_DEPTH_32F, 1); cvcvtcolor(originalimage, graya, CV_BGR2GRAY); cvcvtcolor(processingimage, grayb, CV_BGR2GRAY); while (ProcessingImage) { cvcvtcolor(processingimage, grayb, CV_BGR2GRAY); cvcvtcolor(originalimage, graya, CV_BGR2GRAY); cvcalcopticalflowbm(graya, grayb, cvsize(16, 16), cvsize(8, 8), cvsize(64, 64), 1, velx, vely); cvshowimage("vx", velx); cvshowimage("vy", vely); cvshowimage("main Window", ProcessingImage); cvwaitkey(30); OriginalImage = cvqueryframe(filma); ProcessingImage = cvqueryframe(filmb); return(0); Uwagi dla użytkownika Dokumentacja dostarczona przez Intel do tej funkcji jest dość skromna. Nie podano literatury, z jakiej korzystano podczas pisania tej funkcji. Uwagi na temat działania algorytmu Schemat skanowania sąsiedztwa pokazany jest na rysunku Krok 1 Porównaj blok z pozycji S z klatki odniesienia z blokiem z pozycji S z klatki badanej. Jeżeli dopasowanie dwóch bloków jest mniejsze od progu (jego wartość zależy od wielkości bloku i nie jest ustalana przez użytkownika), to STOP. W przeciwnym wypadku krok 2. Krok 2 Przejdź do następnej pozycji z obszaru skanowania i policz dopasowanie bloków. Powtarzaj krok 2 dopóki nie znajdziesz zadowalającego dopasowania lub nie przeszukasz całego sąsiedztwa. Krok 3 Zaznacz na velx i vely pozycję przesuniętego bloku.

152 150 Rozdział 8. Detekcja ruchu i jej zastosowania Rysunek Przykład użycia funkcji cvcalcopticalflowbm (prosta sekwencja) Zastosowania Wstęp Przedstawiony przykład dotyczy wykorzystania funkcji cvcalcopticalflow BM do wykrywania ruchomych bloków. Następnie na podstawie macierzy velx i vely zaznaczane są ruchome obiekty. Kod źródłowy #include <cv.h> #include <highgui.h> #include <math.h> #include <conio.h> #define sizei 500 #define sizej 500

153 8.3. Metoda dopasowywania bloków 151 Rysunek Zastosowanie funkcji cvcalcopticalflowbm (skomplikowana sekwencja) Rysunek Zastosowanie funkcji cvcalcopticalflowbm (skomplikowana sekwencja)

154 152 Rozdział 8. Detekcja ruchu i jej zastosowania Rysunek Schemat skanowania sąsiedztwa bloku S #define neighbours 3 void DrawMotionBlocks(IplImage *ProcFrame, int x, int y, int BlockSize) { int i, j; CvScalar s; s.val[0] = 255; for (i = 0; i < BlockSize; i++) { for (j = 0; j < BlockSize; j++) { cvset2d(procframe, x * BlockSize + i, y * BlockSize + j, s); void cvshowmotionblocks(iplimage* imga, IplImage* VelX, IplImage* VelY) { int i, j, hlp; CvScalar k; int MotionBlocks[sizeI][sizeJ]; for (i = 0; i < VelX->height; i++) { for (j = 0; j < VelX->width; j++) { MotionBlocks[i][j] = 0;

155 8.3. Metoda dopasowywania bloków 153 k = cvget2d(velx, i, j); if (k.val[0]!= 0) MotionBlocks[i][j] = 1; for (i = 0; i < VelY->height; i++) { for (j = 0; j < VelY->width; j++) { k = cvget2d(vely, i, j); if (k.val[0]!= 0) MotionBlocks[i][j] = 1; for (i = 0; i < VelX->height; i++) { for (j = 0; j < VelX->width; j++) { hlp = 0; if (MotionBlocks[i][j] == 1) { if (i - 1 >= 0 && j - 1 >= 0) { if (MotionBlocks[i - 1][j - 1] == 1) hlp++; if (MotionBlocks[i][j - 1] == 1) hlp++; if (MotionBlocks[i - 1][j] == 1) hlp++; if (i + 1 < VelX->height && j + 1 < VelX->width) { if (MotionBlocks[i + 1][j + 1] == 1) hlp++; if (MotionBlocks[i][j + 1] == 1) hlp++; if (MotionBlocks[i + 1][j] == 1) hlp++; if (i + 1 < VelX->height && j - 1 >= 0) { if (MotionBlocks[i + 1][j - 1] == 1) hlp++; if (i - 1 >= 0 && j + 1 < VelX->width) { if (MotionBlocks[i - 1][j + 1] == 1) hlp++;

156 154 Rozdział 8. Detekcja ruchu i jej zastosowania if (hlp >= neighbours) { DrawMotionBlocks(imgA, i, j, 10); int main(int argc, char* argv[]) { IplImage* OriginalImage; IplImage* ProcessingImage; IplImage* graya; IplImage* grayb; IplImage* velx, *vely; CvCapture* film = cvcapturefromfile("c:/bezfseg3crop.avi"); CvCapture* film2 = cvcapturefromfile("c:/bezfseg3crop.avi"); cvnamedwindow("processing", 1); OriginalImage = cvqueryframe(film); ProcessingImage = cvqueryframe(film2); ProcessingImage = cvqueryframe(film2); CvSize size = cvsize((originalimage->width) / 10, (OriginalImage->height) / 10); graya = cvcreateimage(cvgetsize(originalimage), IPL_DEPTH_8U, 1); grayb = cvcreateimage(cvgetsize(processingimage), IPL_DEPTH_8U, 1); velx = cvcreateimage(size, IPL_DEPTH_32F, 1); vely = cvcreateimage(size, IPL_DEPTH_32F, 1); cvcvtcolor(originalimage, graya, CV_BGR2GRAY); cvcvtcolor(processingimage, grayb, CV_BGR2GRAY); while (ProcessingImage) { cvcvtcolor(processingimage, grayb, CV_BGR2GRAY); cvcvtcolor(originalimage, graya, CV_BGR2GRAY); cvcalcopticalflowbm(graya, grayb, cvsize(10, 10),

157 8.3. Metoda dopasowywania bloków 155 Rysunek Klatka 52 i 53 Rysunek Klatka 54 i 55 cvsize(5, 5), cvsize(60, 60),0,velx, vely); cvshowmotionblocks(processingimage, velx, vely); cvshowimage("processing", ProcessingImage); cvwaitkey(30); OriginalImage = cvqueryframe(film); ProcessingImage = cvqueryframe(film2); getch(); return(0); Opis programu Na następnch rysunkach przedstawiono efekty działania programu (podano numer klatki filmu). Aby wyeliminować szumy, zastosowano następującą metodę: zaznaczamy blok jako ruchomy, jeśli przynajmniej trzy przylegające do niego bloki są ruchome. Przedstawiony przykład dotyczy wykrywania nieprawidłowości w wykonaniu blachy miedzianej.

158 156 Rozdział 8. Detekcja ruchu i jej zastosowania Rysunek Klatka 56 i 57 Rysunek Klatka 58 i 110 Rysunek Klatka 111 i 112 Rysunek Klatka 113 i 114

159 Rozdział 9 Bezcieniowa detekcja ruchu Algorytmy opisane w tym rozdziale przeznaczone są do detekcji ruchu. W odróżnieniu jednak od poprzedniego rozdziału, wykrywanie ruchomych obiektów odbywa się w trzech etapach. W pierwszej fazie wykrywane są te piksele, które znacząco zmieniły swoją wartość. W fazie drugiej następuje próba wykrycia wśród nich tych pikseli, które zmieniły swą wartość nie dlatego, że są odwzorowaniem ruchomego obiektu, lecz jego cienia. W etapie trzecim cień zostaje usunięty. Naszkicowany algorytm jest z natury rzeczy wolniejszy niż prostsze metody wykrywania ruchu. Nie oznacza to jednak, że nie może być on stosowany on-line. Jako przykład zastosowania pokazano wykrywanie pieszych na ulicy. Może być on także stosowany do wykrywania wad w produkcji wówczas, gdy kolejne produkty przemieszczające się na taśmie produkcyjnej rzucają cień, który może utrudniać precyzyjną ocenę ich rozmiarów. W odróżnieniu od zawartości pozostałych rozdziałów, które bazują na procedurach biblioteki OpenCV algorytmy opisane w tym rozdziale zostały zaprogramowane przez Autora tego rozdziału na podstawie metod opisanych w literaturze i zmodyfikowanych w wyniku własnych eksperymentów. Autor rozdziału dołożył starań, by napisane funkcje były zgodne, w sensie wejść i wyjść, z funkcjami biblioteki OpenCV MDetAllocateResources Alokuje i inicjalizuje zasoby niezbędne do przeprowadzenia procesu detekcji ruchu. Sposób wywołania int MDetAllocateResources(int width, int height); width szerokość obrazu wejściowego, height wysokość obrazu wejściowego.

160 158 Rozdział 9. Bezcieniowa detekcja ruchu Funkcja zwraca wartość 1 w przypadku powodzenia lub wartość 0 w przypadku błędu. Standardowe przykłady #include "mdet.h" // zainicjalizuj przechwytywanie obrazu z pliku wideo CvCapture *capture = cvcapturefromfile(argv[1]); // określ szerokość i wysokość strumienia wideo int width = (int)cvgetcaptureproperty(capture, CV_CAP_PROP_FRAME_WIDTH); int height = (int)cvgetcaptureproperty(capture, CV_CAP_PROP_FRAME_HEIGHT); // alokuj i~inicjalizuj zasoby if (MDetAllocateResources(width, height) == 0) { // sygnalizuj blad! exit(1); // przeprowadź proces detekcji Uwagi dla użytkownika Po zakończeniu procesu detekcji przydzielone zasoby należy zwolnić przez wywołanie funkcji MDetFreeResources MDetDetectMotion Przeprowadza proces detekcji ruchu z wykorzystaniem algorytmu z adaptacyjnym modelem tła. Opcjonalnie przeprowadza proces identyfikacji cieni wykrytych w procesie detekcji ruchu. Sposób wywołania void MDetDetectMotion(IplImage *inframe, IplImage *outframe, int threshold, int backgdupdateinterv, int motionupdateinterv, int useshadowfilter, float lncc2, float lstd2, float llow); *inframe obraz wejściowy typu IplImage o głębokości IPL_DEPTH_8U i jednym kanale na piksel, *outframe obraz wyjściowy typu IplImage o głębokości IPL_DEPTH_8U i jednym kanale na piksel,

161 9.2. MDetDetectMotion 159 threshold próg o wartościach z przedziału <0,255>. Jest to minimalna bezwzględna wartość różnicy jasności piksela obrazu wejściowego i piksela ramki modelu tła, powyżej ktorej piksel będzie traktowany jako ruchomy. Jego zmniejszenie powoduje zwiększenie czułości algorytmu detekcji ruchu, backgdupdateinterv próg energii tła o wartościach nieujemnych. Jest to minimalna liczba iteracji algorytmu (liczba wywołań funkcji MDetDetectMotion), w których piksel obrazu wejściowego musi być zaklasyfikowany jako piksel tła, aby odpowiadający mu piksel ramki modelu tła został uaktualniony. Parametr ten określa szybkość adaptacji ramki modelu tła dla nieruchomych części obserwowanej sceny. motionupdateinterv próg energii ruchu o wartościach > backgdupdateinterv. Jest to minimalna liczba iteracji algorytmu (liczba wywołań funkcji MDet- DetectMotion), w których piksel obrazu wejściowego musi być zaklasyfikowany jako piksel ruchu, aby odpowiadajacy mu piksel ramki modelu tła został uaktualniony. Parametr ten określa szybkość adaptacji ramki modelu tła dla ruchomych części obserwowanej sceny. useshadowfilter jeśli parametr ma wartość niezerową, dodatkowo przeprowadzany jest proces identyfikacji cieni. W innym przypadku trzy kolejne parametry nie są wykorzystywane. lncc2 kwadrat progu miary znormalizowanej kros-korelacji pomiędzy regionem 5 x 5 obrazu wejściowego oraz ramki modelu tła. Parametr o wartościach z przedziału <0,1>. Jego zmniejszenie powoduje zwiększenie liczby pikseli, które traktowane będą jako potencjalni kandydaci na piksele cienie. lstd2 kwadrat progu miary odchylenia standardowego stosunku pikseli z regionu 5 x 5 obrazu wejściowego do pikseli z regionu 5 x 5 ramki modelu tła. Parametr o wartościach nieujemnych. Zmniejszenie tego parametru powoduje bardziej restrykcyjne klasyfikowanie pikseli kandydatów jako piksele cienie. llow minimalna wartość stosunku piksela obrazu wejściowego do piksela ramki modelu tła. Parametr o wartościach z przedziału <0,1). Zwiększenie tego parametru powoduje bardziej restrykcyjne klasyfikowanie bardzo ciemnych i bardzo jasnych pikseli obrazu wejściowego jako piksele cienie. Standardowe przykłady #include "mdet.h" // zainicjalizuj przechwytywanie obrazu z pliku wideo CvCapture *capture = cvcapturefromfile(argv[1]); // określ szerokość i wysokość strumienia wideo int width =

162 160 Rozdział 9. Bezcieniowa detekcja ruchu (int)cvgetcaptureproperty(capture, CV_CAP_PROP_FRAME_WIDTH); int height = (int)cvgetcaptureproperty(capture, CV_CAP_PROP_FRAME_HEIGHT); // zaalokuj wejściowe i wyjściowe obrazy IplImage *input = cvcreateimage(cvsize(width, height), IPL_DEPTH_8U, 1); IplImage *output = cvcreateimage(cvsize(width, height), IPL_DEPTH_8U, 1); // alokuj i inicjalizuj zasoby if (MDetAllocateResources(width, height) == 0) { //sygnalizuj błąd! exit(1); // przeprowadź proces detekcji while (1) { // pobierz kolejny obraz ze strumienia wideo IplImage *tmp = cvqueryframe(capture); // przerwij jeśli koniec strumienia if (tmp == NULL) { break; // konwertuj obraz do formatu grayscale cvconvertimage(tmp, input, 1); // przeprowadź detekcje ruchu i filtracje cieni // z domyślnymi parametrami MDetDetectMotion(input, output, MDetDefaultThreshold, MDetDefaultBackgdUpdateInterv, MDetDefaultMotionUpdateInterv, 1, MDetDefaultLncc2, MDetDefaultLstd2, MDetDefaultLlow); // dalsze przetwarzanie (operacje morfologiczne, // wyświetlanie, etc)... // zwolnij zasoby detekcji MDetFreeResources();

163 9.2. MDetDetectMotion 161 // zwolnij strumień wideo cvreleasecapture(&capture); // zwolnij obrazy cvreleaseimage(&input); cvreleaseimage(&output); Uwagi dla użytkownika Przed pierwszym wywołaniem funkcji MDetDetectMotion należy zainicjalizować zasoby i określić rozmiar obrazu wejściowego z wykorzystaniem funkcji MDetAllocateResources. Po zakończeniu procesu detekcji ruchu należy zwolnić zaalokowane zasoby z wykorzystaniem funkcji MDetFreeResources. Zarówno obraz wejściowy, jak i wyjściowy powinien być zaalokowane przed wywołaniem funkcji MDetDetectMotion. Dozwolone są jedynie obrazy typu IplImage o głębokości IPL_DEPTH_8U i jednym kanale na piksel. Rozmiar obrazu wejściowego musi być zgodny z rozmiarem zadeklarowanym przez wywołanie funkcji MDetAllocateResources. Piksele obrazu wyjściowego, które uznane zostały za nieruchome, oznaczone są wartością MDetPixelBackground=0x00. Piksele, które uznane zostały za ruchome, oznaczone są wartością MDetPixelMotion=0xff. Jeśli uaktywniono identyfikacje cieni, ruchome piksele, które uznane zostały za piksele cienie, oznaczone są wartością MDetPixelShadow=0x60. W przypadku niskich wartości parametru threshold, obraz wyjściowy może być znacznie zaszumiony. W takim przypadku, należy zastosować operacje mor-

1 Temat: Wprowadzenie do biblioteki OpenCV

1 Temat: Wprowadzenie do biblioteki OpenCV Instrukcja Zaawansowane przetwarzanie obrazów 1 Temat: Wprowadzenie do biblioteki OpenCV Przygotował: mgr inż. Tomasz Michno 1 Wstęp 1.1 OpenCV - krótki wstęp OpenCV (Open Source Computer Vision) jest

Bardziej szczegółowo

Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych.

Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych. Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych. 1. Przygotowanie środowiska programistycznego. Zajęcia będą

Bardziej szczegółowo

Wykład VII. Programowanie. dr inż. Janusz Słupik. Gliwice, 2014. Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Wykład VII. Programowanie. dr inż. Janusz Słupik. Gliwice, 2014. Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik Wykład VII Wydział Matematyki Stosowanej Politechniki Śląskiej Gliwice, 2014 c Copyright 2014 Janusz Słupik Kompilacja Kompilator C program do tłumaczenia kodu źródłowego na język maszynowy. Preprocesor

Bardziej szczegółowo

1 Podstawy c++ w pigułce.

1 Podstawy c++ w pigułce. 1 Podstawy c++ w pigułce. 1.1 Struktura dokumentu. Kod programu c++ jest zwykłym tekstem napisanym w dowolnym edytorze. Plikowi takiemu nadaje się zwykle rozszerzenie.cpp i kompiluje za pomocą kompilatora,

Bardziej szczegółowo

Baltie 3. Podręcznik do nauki programowania dla klas I III gimnazjum. Tadeusz Sołtys, Bohumír Soukup

Baltie 3. Podręcznik do nauki programowania dla klas I III gimnazjum. Tadeusz Sołtys, Bohumír Soukup Baltie 3 Podręcznik do nauki programowania dla klas I III gimnazjum Tadeusz Sołtys, Bohumír Soukup Czytanie klawisza lub przycisku myszy Czytaj klawisz lub przycisk myszy - czekaj na naciśnięcie Polecenie

Bardziej szczegółowo

Wstęp do Programowania, laboratorium 02

Wstęp do Programowania, laboratorium 02 Wstęp do Programowania, laboratorium 02 Zadanie 1. Napisać program pobierający dwie liczby całkowite i wypisujący na ekran największą z nich. Zadanie 2. Napisać program pobierający trzy liczby całkowite

Bardziej szczegółowo

Podstawy programowania skrót z wykładów:

Podstawy programowania skrót z wykładów: Podstawy programowania skrót z wykładów: // komentarz jednowierszowy. /* */ komentarz wielowierszowy. # include dyrektywa preprocesora, załączająca biblioteki (pliki nagłówkowe). using namespace

Bardziej szczegółowo

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02 METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE Wykład 02 NAJPROSTSZY PROGRAM /* (Prawie) najprostszy przykład programu w C */ /*==================*/ /* Między tymi znaczkami można pisać, co się

Bardziej szczegółowo

Programowanie w języku Python. Grażyna Koba

Programowanie w języku Python. Grażyna Koba Programowanie w języku Python Grażyna Koba Kilka definicji Program komputerowy to ciąg instrukcji języka programowania, realizujący dany algorytm. Język programowania to zbiór określonych instrukcji i

Bardziej szczegółowo

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1 Podstawy programowania. Wykład Funkcje Krzysztof Banaś Podstawy programowania 1 Programowanie proceduralne Pojęcie procedury (funkcji) programowanie proceduralne realizacja określonego zadania specyfikacja

Bardziej szczegółowo

1. Przypisy, indeks i spisy.

1. Przypisy, indeks i spisy. 1. Przypisy, indeks i spisy. (Wstaw Odwołanie Przypis dolny - ) (Wstaw Odwołanie Indeks i spisy - ) Przypisy dolne i końcowe w drukowanych dokumentach umożliwiają umieszczanie w dokumencie objaśnień, komentarzy

Bardziej szczegółowo

Dodawanie grafiki i obiektów

Dodawanie grafiki i obiektów Dodawanie grafiki i obiektów Word nie jest edytorem obiektów graficznych, ale oferuje kilka opcji, dzięki którym można dokonywać niewielkich zmian w rysunku. W Wordzie możesz zmieniać rozmiar obiektu graficznego,

Bardziej szczegółowo

Podstawy programowania. Wykład 7 Tablice wielowymiarowe, SOA, AOS, itp. Krzysztof Banaś Podstawy programowania 1

Podstawy programowania. Wykład 7 Tablice wielowymiarowe, SOA, AOS, itp. Krzysztof Banaś Podstawy programowania 1 Podstawy programowania. Wykład 7 Tablice wielowymiarowe, SOA, AOS, itp. Krzysztof Banaś Podstawy programowania 1 Tablice wielowymiarowe C umożliwia definiowanie tablic wielowymiarowych najczęściej stosowane

Bardziej szczegółowo

1 Podstawy c++ w pigułce.

1 Podstawy c++ w pigułce. 1 Podstawy c++ w pigułce. 1.1 Struktura dokumentu. Kod programu c++ jest zwykłym tekstem napisanym w dowolnym edytorze. Plikowi takiemu nadaje się zwykle rozszerzenie.cpp i kompiluje za pomocą kompilatora,

Bardziej szczegółowo

Formaty obrazów rastrowych biblioteki PBM

Formaty obrazów rastrowych biblioteki PBM Formaty obrazów rastrowych biblioteki PBM Reprezentacja obrazu Obrazy pobierane z kamery, bądź dowolnego innego źródła, mogą być składowane na pliku dyskowym w jednym z wielu istniejących formatów zapisu

Bardziej szczegółowo

Jak napisać program obliczający pola powierzchni różnych figur płaskich?

Jak napisać program obliczający pola powierzchni różnych figur płaskich? Część IX C++ Jak napisać program obliczający pola powierzchni różnych figur płaskich? Na początku, przed stworzeniem właściwego kodu programu zaprojektujemy naszą aplikację i stworzymy schemat blokowy

Bardziej szczegółowo

Instrukcja dotycząca konwersji dokumentów LaTeX do plików w formacie RTF

Instrukcja dotycząca konwersji dokumentów LaTeX do plików w formacie RTF Instrukcja dotycząca konwersji dokumentów LaTeX do plików w formacie RTF 1. Wstęp Treści zawarte w tym dokumencie mogą być przydatne w przypadku konieczności dokonania konwersji dokumentów tworzonych z

Bardziej szczegółowo

Instrukcja obsługi programu Do-Exp

Instrukcja obsługi programu Do-Exp Instrukcja obsługi programu Do-Exp Autor: Wojciech Stark. Program został utworzony w ramach pracy dyplomowej na Wydziale Chemicznym Politechniki Warszawskiej. Instrukcja dotyczy programu Do-Exp w wersji

Bardziej szczegółowo

Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu.

Niezwykłe tablice Poznane typy danych pozwalają przechowywać pojedyncze liczby. Dzięki tablicom zgromadzimy wiele wartości w jednym miejscu. Część XIX C++ w Każda poznana do tej pory zmienna może przechowywać jedną liczbę. Jeśli zaczniemy pisać bardziej rozbudowane programy, okaże się to niewystarczające. Warto więc poznać zmienne, które mogą

Bardziej szczegółowo

Instrukcja dotycząca konwersji dokumentów LaTeX do plików w formacie RTF

Instrukcja dotycząca konwersji dokumentów LaTeX do plików w formacie RTF Instrukcja dotycząca konwersji dokumentów LaTeX do plików w formacie RTF 1. Wstęp Treści zawarte w tym dokumencie mogą być przydatne w przypadku konieczności dokonania konwersji dokumentów tworzonych z

Bardziej szczegółowo

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main. Część XVI C++ Funkcje Jeśli nasz program rozrósł się już do kilkudziesięciu linijek, warto pomyśleć o jego podziale na mniejsze części. Poznajmy więc funkcje. Szybko się przekonamy, że funkcja to bardzo

Bardziej szczegółowo

Rysowanie punktów na powierzchni graficznej

Rysowanie punktów na powierzchni graficznej Rysowanie punktów na powierzchni graficznej Tworzenie biblioteki rozpoczniemy od podstawowej funkcji graficznej gfxplot() - rysowania pojedynczego punktu na zadanych współrzędnych i o zadanym kolorze RGB.

Bardziej szczegółowo

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość 1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość 2. Poprawna definicja wskażnika b to: a) float *a, **b = &a; b) float

Bardziej szczegółowo

Wstęp do Informatyki i Programowania Laboratorium: Lista 0 Środowisko programowania

Wstęp do Informatyki i Programowania Laboratorium: Lista 0 Środowisko programowania Wstęp do Informatyki i Programowania Laboratorium: Lista 0 Środowisko programowania Przemysław Kobylański Wprowadzenie Każdy program w C musi zawierać przynajmniej funkcję o nazwie main(): Aby możliwe

Bardziej szczegółowo

VinCent Administrator

VinCent Administrator VinCent Administrator Moduł Zarządzania podatnikami Krótka instrukcja obsługi ver. 1.01 Zielona Góra, grudzień 2005 1. Przeznaczenie programu Program VinCent Administrator przeznaczony jest dla administratorów

Bardziej szczegółowo

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1 Podstawy programowania, Poniedziałek 30.05.2016, 8-10 Projekt, część 1 1. Zadanie Projekt polega na stworzeniu logicznej gry komputerowej działającej w trybie tekstowym o nazwie Minefield. 2. Cele Celem

Bardziej szczegółowo

5.4. Tworzymy formularze

5.4. Tworzymy formularze 5.4. Tworzymy formularze Zastosowanie formularzy Formularz to obiekt bazy danych, który daje możliwość tworzenia i modyfikacji danych w tabeli lub kwerendzie. Jego wielką zaletą jest umiejętność zautomatyzowania

Bardziej szczegółowo

etrader Pekao Podręcznik użytkownika Strumieniowanie Excel

etrader Pekao Podręcznik użytkownika Strumieniowanie Excel etrader Pekao Podręcznik użytkownika Strumieniowanie Excel Spis treści 1. Opis okna... 3 2. Otwieranie okna... 3 3. Zawartość okna... 4 3.1. Definiowanie listy instrumentów... 4 3.2. Modyfikacja lub usunięcie

Bardziej szczegółowo

Wstęp 7 Rozdział 1. OpenOffice.ux.pl Writer środowisko pracy 9

Wstęp 7 Rozdział 1. OpenOffice.ux.pl Writer środowisko pracy 9 Wstęp 7 Rozdział 1. OpenOffice.ux.pl Writer środowisko pracy 9 Uruchamianie edytora OpenOffice.ux.pl Writer 9 Dostosowywanie środowiska pracy 11 Menu Widok 14 Ustawienia dokumentu 16 Rozdział 2. OpenOffice

Bardziej szczegółowo

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie. Część XXII C++ w Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie. Ćwiczenie 1 1. Utwórz nowy projekt w Dev C++ i zapisz go na

Bardziej szczegółowo

Język C zajęcia nr 11. Funkcje

Język C zajęcia nr 11. Funkcje Język C zajęcia nr 11 Funkcje W języku C idea podprogramów realizowana jest wyłącznie poprzez definiowanie i wywołanie funkcji. Każda funkcja musi być przed wywołaniem zadeklarowana. Deklaracja funkcji

Bardziej szczegółowo

Temat 1: Podstawowe pojęcia: program, kompilacja, kod

Temat 1: Podstawowe pojęcia: program, kompilacja, kod Temat 1: Podstawowe pojęcia: program, kompilacja, kod wynikowy. Przykłady najprostszych programów. Definiowanie zmiennych. Typy proste. Operatory: arytmetyczne, przypisania, inkrementacji, dekrementacji,

Bardziej szczegółowo

Laboratorium Informatyka (I) AiR Ćwiczenia z debugowania

Laboratorium Informatyka (I) AiR Ćwiczenia z debugowania Laboratorium Informatyka (I) AiR Ćwiczenia z debugowania Krzysztof Kluza, Janusz Miller 1 Debugowanie Debugowanie, czy też po polsku odpluskiwanie, to proces polegający na kontrolowanym wykonaniu programu

Bardziej szczegółowo

Edytor tekstu OpenOffice Writer Podstawy

Edytor tekstu OpenOffice Writer Podstawy Edytor tekstu OpenOffice Writer Podstawy OpenOffice to darmowy zaawansowany pakiet biurowy, w skład którego wchodzą następujące programy: edytor tekstu Writer, arkusz kalkulacyjny Calc, program do tworzenia

Bardziej szczegółowo

Praktyka programowania projekt

Praktyka programowania projekt Praktyka programowania projekt Zadanie projektowe nr. 2 Gra PacMan K. M. Ocetkiewicz, T Goluch 19 listopada 2012 Plan prezentacji Opis 2 zadania projektowego Plan prezentacji Opis 2 zadania projektowego

Bardziej szczegółowo

GRAFIKA RASTROWA. WYKŁAD 2 Oprogramowanie i formaty plików. Jacek Wiślicki Katedra Informatyki Stosowanej

GRAFIKA RASTROWA. WYKŁAD 2 Oprogramowanie i formaty plików. Jacek Wiślicki Katedra Informatyki Stosowanej GRAFIKA RASTROWA WYKŁAD 2 Oprogramowanie i formaty plików Jacek Wiślicki Katedra Informatyki Stosowanej Oprogramowanie Na rynku istnieje wiele programów do tworzenia i przetwarzania grafiki rastrowej.

Bardziej szczegółowo

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Program, to lista poleceń zapisana w jednym języku programowania zgodnie z obowiązującymi w nim zasadami. Celem programu jest przetwarzanie

Bardziej szczegółowo

e-podręcznik dla seniora... i nie tylko.

e-podręcznik dla seniora... i nie tylko. Pliki i foldery Czym są pliki? Plik to w komputerowej terminologii pewien zbiór danych. W zależności od TYPU pliku może to być: obraz (np. zdjęcie z imienin, rysunek) tekst (np. opowiadanie) dźwięk (np.

Bardziej szczegółowo

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4 Dr inż. Dariusz JĘDRZEJCZYK Wskaźniki Dynamiczna alokacja pamięci Przykłady 11/3/2016 AGH, Katedra Informatyki Stosowanej i Modelowania 2 Wskaźnik to

Bardziej szczegółowo

Dr inż. Grażyna KRUPIŃSKA. D-10 pokój 227 WYKŁAD 7 WSTĘP DO INFORMATYKI

Dr inż. Grażyna KRUPIŃSKA. D-10 pokój 227 WYKŁAD 7 WSTĘP DO INFORMATYKI Dr inż. Grażyna KRUPIŃSKA Grazyna.Krupinska@fis.agh.edu.pl D-10 pokój 227 WYKŁAD 7 WSTĘP DO INFORMATYKI Wyrażenia 2 Wyrażenia w języku C są bardziej elastyczne niż wyrażenia w jakimkolwiek innym języku

Bardziej szczegółowo

EDYCJA TEKSTU MS WORDPAD

EDYCJA TEKSTU MS WORDPAD EDYCJA TEKSTU MS WORDPAD EDYCJA TEKSTU - MS WORDPAD WordPad (ryc. 1 ang. miejsce na słowa) to bardzo przydatny program do edycji i pisania tekstów, który dodatkowo dostępny jest w każdym systemie z rodziny

Bardziej szczegółowo

Menu Plik w Edytorze symboli i Edytorze widoku aparatów

Menu Plik w Edytorze symboli i Edytorze widoku aparatów Menu Plik w Edytorze symboli i Edytorze widoku aparatów Informacje ogólne Symbol jest przedstawieniem graficznym aparatu na schemacie. Oto przykład przekaźnika: Widok aparatu jest przedstawieniem graficznym

Bardziej szczegółowo

Pisząc okienkowy program w Matlabie wykorzystujemy gotowe obiekty graficzne, lub możemy tworzyć własne obiekty dziedzicząc już zdefiniowane.

Pisząc okienkowy program w Matlabie wykorzystujemy gotowe obiekty graficzne, lub możemy tworzyć własne obiekty dziedzicząc już zdefiniowane. MATLAB Co to jest? program komputerowy będący interaktywnym środowiskiem do wykonywania obliczeń naukowych i inżynierskich oraz do tworzenia symulacji komputerowych. Nazwa Nazwa programu pochodzi od angielskich

Bardziej szczegółowo

Instrukcja obsługi. Generatora CSV

Instrukcja obsługi. Generatora CSV Instrukcja obsługi Generatora CSV Spis treści: 1. Wstęp 2. Praca z programem Generator CSV 2.1. Rozpoczęcie pracy 2.2. Sprawdzanie docelowego pliku CSV 2.3 Korekta błędów w docelowym pliku CSV 2.3.1. Odnajdywanie

Bardziej szczegółowo

Expo Composer. www.doittechnology.pl 1. Garncarska 5 70-377 Szczecin tel.: +48 91 404 09 24 e-mail: info@doittechnology.pl. Dokumentacja użytkownika

Expo Composer. www.doittechnology.pl 1. Garncarska 5 70-377 Szczecin tel.: +48 91 404 09 24 e-mail: info@doittechnology.pl. Dokumentacja użytkownika Expo Composer Dokumentacja użytkownika Wersja 1.0 www.doittechnology.pl 1 SPIS TREŚCI 1. O PROGRAMIE... 3 Wstęp... 3 Wymagania systemowe... 3 Licencjonowanie... 3 2. PIERWSZE KROKI Z Expo Composer... 4

Bardziej szczegółowo

Ćwiczenia nr 2. Edycja tekstu (Microsoft Word)

Ćwiczenia nr 2. Edycja tekstu (Microsoft Word) Dostosowywanie paska zadań Ćwiczenia nr 2 Edycja tekstu (Microsoft Word) Domyślnie program Word proponuje paski narzędzi Standardowy oraz Formatowanie z zestawem opcji widocznym poniżej: Można jednak zmodyfikować

Bardziej szczegółowo

Podstawy programowania w języku C++

Podstawy programowania w języku C++ Podstawy programowania w języku C++ Część jedenasta Przetwarzanie plików amorficznych Konwencja języka C Autor Roman Simiński Kontakt roman.siminski@us.edu.pl www.us.edu.pl/~siminski Niniejsze opracowanie

Bardziej szczegółowo

Wprowadzenie do biblioteki klas C++

Wprowadzenie do biblioteki klas C++ Instrukcja laboratoryjna nr 7 Programowanie w języku C 2 (C++ poziom zaawansowany) Wprowadzenie do biblioteki klas C++ WxWidgets mgr inż. Lasota Maciej dr inż. Kaczmarek Tomasz dr inż. Wilk-Jakubowski

Bardziej szczegółowo

Struktura programu. Projekty złożone składają się zwykłe z różnych plików. Zawartość każdego pliku programista wyznacza zgodnie z jego przeznaczeniem.

Struktura programu. Projekty złożone składają się zwykłe z różnych plików. Zawartość każdego pliku programista wyznacza zgodnie z jego przeznaczeniem. Struktura programu Projekty złożone składają się zwykłe z różnych plików. Zawartość każdego pliku programista wyznacza zgodnie z jego przeznaczeniem. W ostatnich latach najbardziej używanym stylem oprogramowania

Bardziej szczegółowo

Po uruchomieniu programu nasza litera zostanie wyświetlona na ekranie

Po uruchomieniu programu nasza litera zostanie wyświetlona na ekranie Część X C++ Typ znakowy służy do reprezentacji pojedynczych znaków ASCII, czyli liter, cyfr, znaków przestankowych i innych specjalnych znaków widocznych na naszej klawiaturze (oraz wielu innych, których

Bardziej szczegółowo

Część 4 życie programu

Część 4 życie programu 1. Struktura programu c++ Ogólna struktura programu w C++ składa się z kilku części: część 1 część 2 część 3 część 4 #include int main(int argc, char *argv[]) /* instrukcje funkcji main */ Część

Bardziej szczegółowo

Diagnostyka obrazowa

Diagnostyka obrazowa Diagnostyka obrazowa Ćwiczenie pierwsze Zapoznanie ze środowiskiem przetwarzania obrazu ImageJ 1 Cel ćwiczenia Ćwiczenie ma na celu zapoznanie uczestników kursu Diagnostyka obrazowa ze środowiskiem przetwarzania

Bardziej szczegółowo

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 8. Karol Tarnowski A-1 p.

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 8. Karol Tarnowski A-1 p. Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni Wykład 8 Karol Tarnowski karol.tarnowski@pwr.edu.pl A-1 p. 411B Plan prezentacji Biblioteka GSL Na podstawie: https://www.gnu.org/software/gsl/doc/html/index.html

Bardziej szczegółowo

Układy VLSI Bramki 1.0

Układy VLSI Bramki 1.0 Spis treści: 1. Wstęp... 2 2. Opis edytora schematów... 2 2.1 Dodawanie bramek do schematu:... 3 2.2 Łączenie bramek... 3 2.3 Usuwanie bramek... 3 2.4 Usuwanie pojedynczych połączeń... 4 2.5 Dodawanie

Bardziej szczegółowo

Programowanie obiektowe

Programowanie obiektowe Programowanie obiektowe Laboratorium 1. Wstęp do programowania w języku Java. Narzędzia 1. Aby móc tworzyć programy w języku Java, potrzebny jest zestaw narzędzi Java Development Kit, który można ściągnąć

Bardziej szczegółowo

PROGRAMOWANIE w C prolog

PROGRAMOWANIE w C prolog PROGRAMOWANIE w C prolog dr inż. Jarosław Stańczyk Uniwersytet Przyrodniczy we Wrocławiu Wydział Biologii i Hodowli Zwierząt Katedra Genetyki 1 / jaroslaw.stanczyk@up.wroc.pl programowanie w c 17.10.2014

Bardziej szczegółowo

Jeśli chcesz łatwo i szybko opanować podstawy C++, sięgnij po tę książkę.

Jeśli chcesz łatwo i szybko opanować podstawy C++, sięgnij po tę książkę. Języki C i C++ to bardzo uniwersalne platformy programistyczne o ogromnych możliwościach. Wykorzystywane są do tworzenia systemów operacyjnych i oprogramowania użytkowego. Dzięki niskiemu poziomowi abstrakcji

Bardziej szczegółowo

Zaznaczanie komórek. Zaznaczenie pojedynczej komórki polega na kliknięciu na niej LPM

Zaznaczanie komórek. Zaznaczenie pojedynczej komórki polega na kliknięciu na niej LPM Zaznaczanie komórek Zaznaczenie pojedynczej komórki polega na kliknięciu na niej LPM Aby zaznaczyć blok komórek które leżą obok siebie należy trzymając wciśnięty LPM przesunąć kursor rozpoczynając od komórki

Bardziej szczegółowo

1. Umieść kursor w miejscu, w którym ma być wprowadzony ozdobny napis. 2. Na karcie Wstawianie w grupie Tekst kliknij przycisk WordArt.

1. Umieść kursor w miejscu, w którym ma być wprowadzony ozdobny napis. 2. Na karcie Wstawianie w grupie Tekst kliknij przycisk WordArt. Grafika w dokumencie Wprowadzanie ozdobnych napisów WordArt Do tworzenia efektownych, ozdobnych napisów służy obiekt WordArt. Aby wstawić do dokumentu obiekt WordArt: 1. Umieść kursor w miejscu, w którym

Bardziej szczegółowo

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania Celem ćwiczenia jest zapoznanie studentów z najprostszą dynamiczną strukturą

Bardziej szczegółowo

Programowanie w języku C++ Grażyna Koba

Programowanie w języku C++ Grażyna Koba Programowanie w języku C++ Grażyna Koba Kilka definicji: Program komputerowy to ciąg instrukcji języka programowania, realizujący dany algorytm. Język programowania to zbiór określonych instrukcji i zasad

Bardziej szczegółowo

LABORATORIUM 3 ALGORYTMY OBLICZENIOWE W ELEKTRONICE I TELEKOMUNIKACJI. Wprowadzenie do środowiska Matlab

LABORATORIUM 3 ALGORYTMY OBLICZENIOWE W ELEKTRONICE I TELEKOMUNIKACJI. Wprowadzenie do środowiska Matlab LABORATORIUM 3 ALGORYTMY OBLICZENIOWE W ELEKTRONICE I TELEKOMUNIKACJI Wprowadzenie do środowiska Matlab 1. Podstawowe informacje Przedstawione poniżej informacje maja wprowadzić i zapoznać ze środowiskiem

Bardziej szczegółowo

Diagnostyka obrazowa

Diagnostyka obrazowa Diagnostyka obrazowa Ćwiczenie pierwsze Wstęp do środowiska przetwarzania obrazu ImageJ 1. Cel ćwiczenia Ćwiczenie ma na celu zapoznanie uczestników kursu Diagnostyka obrazowa ze środowiskiem przetwarzania

Bardziej szczegółowo

/* dołączenie pliku nagłówkowego zawierającego deklaracje symboli dla wykorzystywanego mikrokontrolera */ #include <aduc834.h>

/* dołączenie pliku nagłówkowego zawierającego deklaracje symboli dla wykorzystywanego mikrokontrolera */ #include <aduc834.h> Szablon programu: /* dołączenie pliku nagłówkowego zawierającego deklaracje symboli dla wykorzystywanego mikrokontrolera */ #include /* opcjonalne: deklaracja typów o rozmiarze jednego i dwóch

Bardziej szczegółowo

Projekt współfinansowany ze środków Unii Europejskiej w ramach Europejskiego Funduszu Społecznego

Projekt współfinansowany ze środków Unii Europejskiej w ramach Europejskiego Funduszu Społecznego Projekt graficzny z metamorfozą (ćwiczenie dla grup I i II modułowych) Otwórz nowy rysunek. Ustal rozmiar arkusza na A4. Z przybornika wybierz rysowanie elipsy (1). Narysuj okrąg i nadaj mu średnicę 100

Bardziej szczegółowo

Wymagania edukacyjne z informatyki dla klasy szóstej szkoły podstawowej.

Wymagania edukacyjne z informatyki dla klasy szóstej szkoły podstawowej. Wymagania edukacyjne z informatyki dla klasy szóstej szkoły podstawowej. Dział Zagadnienia Wymagania podstawowe Wymagania ponadpodstawowe Arkusz kalkulacyjny (Microsoft Excel i OpenOffice) Uruchomienie

Bardziej szczegółowo

Lokalizacja jest to położenie geograficzne zajmowane przez aparat. Miejsce, w którym zainstalowane jest to urządzenie.

Lokalizacja jest to położenie geograficzne zajmowane przez aparat. Miejsce, w którym zainstalowane jest to urządzenie. Lokalizacja Informacje ogólne Lokalizacja jest to położenie geograficzne zajmowane przez aparat. Miejsce, w którym zainstalowane jest to urządzenie. To pojęcie jest używane przez schematy szaf w celu tworzenia

Bardziej szczegółowo

Nagrywamy podcasty program Audacity

Nagrywamy podcasty program Audacity Pobieranie i instalacja Program Audacity jest darmowym zaawansowanym i wielościeżkowym edytorem plików dźwiękowych rozpowszechnianym na licencji GNU GPL. Jest w wersjach dla systemów typu Unix/Linux, Microsoft

Bardziej szczegółowo

Kurs walut. Specyfikacja projektu. Marek Zając 2013-12-16

Kurs walut. Specyfikacja projektu. Marek Zając 2013-12-16 Kurs walut Specyfikacja projektu Marek Zając 2013-12-16 Spis treści 1. Podsumowanie... 2 1.1 Wstęp... 2 1.2 Projekt interfejsu... 2 1.2.1 Rozmiar głównego okna... 2 2. Słownik pojęć... 2 2.1 Definicja

Bardziej szczegółowo

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1 Podstawy programowania. Wykład 6 Wskaźniki Krzysztof Banaś Podstawy programowania 1 Adresy zmiennych Język C pozwala na operowanie adresami w pamięci stąd, między innymi, kwalifikowanie C jako języka relatywnie

Bardziej szczegółowo

Księgarnia PWN: Andrzej Jaskulski - AutoCAD 2010/LT Podstawy projektowania parametrycznego i nieparametrycznego

Księgarnia PWN: Andrzej Jaskulski - AutoCAD 2010/LT Podstawy projektowania parametrycznego i nieparametrycznego Księgarnia PWN: Andrzej Jaskulski - AutoCAD 2010/LT2010+. Podstawy projektowania parametrycznego i nieparametrycznego Spis treści 1. Koncepcja i zawartość podręcznika...11 1.1. Zawartość programowa...11

Bardziej szczegółowo

SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE

SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE WINDOWS 1 SO i SK/WIN 006 Wydajność systemu 2 SO i SK/WIN Najprostszym sposobem na poprawienie wydajności systemu, jeżeli dysponujemy zbyt małą ilością pamięci RAM

Bardziej szczegółowo

Podstawy Programowania C++

Podstawy Programowania C++ Wykład 3 - podstawowe konstrukcje Instytut Automatyki i Robotyki Warszawa, 2014 Wstęp Plan wykładu Struktura programu, instrukcja przypisania, podstawowe typy danych, zapis i odczyt danych, wyrażenia:

Bardziej szczegółowo

asix4 Podręcznik użytkownika Drajwer OPC Podręcznik użytkownika

asix4 Podręcznik użytkownika Drajwer OPC Podręcznik użytkownika Podręcznik użytkownika Drajwer OPC Podręcznik użytkownika Dok. Nr PLP4048 Wersja: 13-12-2005 Podręcznik użytkownika asix4 ASKOM i asix to zastrzeżone znaki firmy ASKOM Sp. z o. o., Gliwice. Inne występujące

Bardziej szczegółowo

FAQ Systemu EKOS. 1. Jakie są wymagania techniczne dla stanowiska wprowadzania ocen?

FAQ Systemu EKOS. 1. Jakie są wymagania techniczne dla stanowiska wprowadzania ocen? 27.06.11 FAQ Systemu EKOS 1. Jakie są wymagania techniczne dla stanowiska wprowadzania ocen? Procedura rejestracji ocen wymaga podpisywania protokołów (w postaci wypełnionych formularzy InfoPath Forms

Bardziej szczegółowo

Adobe InDesign lab.1 Jacek Wiślicki, Paweł Kośla. Spis treści: 1 Podstawy pracy z aplikacją Układ strony... 2.

Adobe InDesign lab.1 Jacek Wiślicki, Paweł Kośla. Spis treści: 1 Podstawy pracy z aplikacją Układ strony... 2. Spis treści: 1 Podstawy pracy z aplikacją... 2 1.1 Układ strony... 2 strona 1 z 7 1 Podstawy pracy z aplikacją InDesign jest następcą starzejącego się PageMakera. Pod wieloma względami jest do niego bardzo

Bardziej szczegółowo

6. Algorytmy ochrony przed zagłodzeniem dla systemów Linux i Windows NT.

6. Algorytmy ochrony przed zagłodzeniem dla systemów Linux i Windows NT. WYDZIAŁ: GEOLOGII, GEOFIZYKI I OCHRONY ŚRODOWISKA KIERUNEK STUDIÓW: INFORMATYKA STOSOWANA RODZAJ STUDIÓW: STACJONARNE I STOPNIA ROK AKADEMICKI 2014/2015 WYKAZ PRZEDMIOTÓW EGZAMINACYJNYCH: I. Systemy operacyjne

Bardziej szczegółowo

Zmienne, stałe i operatory

Zmienne, stałe i operatory Zmienne, stałe i operatory Przemysław Gawroński D-10, p. 234 Wykład 2 4 marca 2019 (Wykład 2) Zmienne, stałe i operatory 4 marca 2019 1 / 21 Outline 1 Zmienne 2 Stałe 3 Operatory (Wykład 2) Zmienne, stałe

Bardziej szczegółowo

Język ludzki kod maszynowy

Język ludzki kod maszynowy Język ludzki kod maszynowy poziom wysoki Język ludzki (mowa) Język programowania wysokiego poziomu Jeśli liczba punktów jest większa niż 50, test zostaje zaliczony; w przeciwnym razie testu nie zalicza

Bardziej szczegółowo

Podstawy informatyki. Elektrotechnika I rok. Język C++ Operacje na danych - wskaźniki Instrukcja do ćwiczenia

Podstawy informatyki. Elektrotechnika I rok. Język C++ Operacje na danych - wskaźniki Instrukcja do ćwiczenia Podstawy informatyki Elektrotechnika I rok Język C++ Operacje na danych - wskaźniki Instrukcja do ćwiczenia Katedra Energoelektroniki i Automatyki Systemów Przetwarzania Energii AGH Kraków 2017 Tematyka

Bardziej szczegółowo

Transformacja współrzędnych geodezyjnych mapy w programie GEOPLAN

Transformacja współrzędnych geodezyjnych mapy w programie GEOPLAN Transformacja współrzędnych geodezyjnych mapy w programie GEOPLAN Program GEOPLAN umożliwia zmianę układu współrzędnych geodezyjnych mapy. Można tego dokonać przy udziale oprogramowania przeliczającego

Bardziej szczegółowo

Szybkie tworzenie grafiki w GcIde

Szybkie tworzenie grafiki w GcIde Szybkie tworzenie grafiki w GcIde Opracował: Ryszard Olchawa Poniższy opis dotyczy aplikacji okienkowej w systemie Windows lub Linux bazującej na obiektowej bibliotece rofrm stworzonej w środowisku GcIde.

Bardziej szczegółowo

Instrukcja do ćwiczeń nr 4 typy i rodzaje zmiennych w języku C dla AVR, oraz ich deklarowanie, oraz podstawowe operatory

Instrukcja do ćwiczeń nr 4 typy i rodzaje zmiennych w języku C dla AVR, oraz ich deklarowanie, oraz podstawowe operatory Instrukcja do ćwiczeń nr 4 typy i rodzaje zmiennych w języku C dla AVR, oraz ich deklarowanie, oraz podstawowe operatory Poniżej pozwoliłem sobie za cytować za wikipedią definicję zmiennej w informatyce.

Bardziej szczegółowo

Temat: Organizacja skoroszytów i arkuszy

Temat: Organizacja skoroszytów i arkuszy Temat: Organizacja skoroszytów i arkuszy Podstawowe informacje o skoroszycie Excel jest najczęściej wykorzystywany do tworzenia skoroszytów. Skoroszyt jest zbiorem informacji, które są przechowywane w

Bardziej szczegółowo

Lab 9 Podstawy Programowania

Lab 9 Podstawy Programowania Lab 9 Podstawy Programowania (Kaja.Gutowska@cs.put.poznan.pl) Wszystkie kody/fragmenty kodów dostępne w osobnym pliku.txt. Materiały pomocnicze: Wskaźnik to specjalny rodzaj zmiennej, w której zapisany

Bardziej szczegółowo

Pliki. Informacje ogólne. Obsługa plików w języku C

Pliki. Informacje ogólne. Obsługa plików w języku C Pliki Informacje ogólne Plik jest pewnym zbiorem danych, zapisanym w systemie plików na nośniku danych (np. dysku twardym, pendrive, płycie DVD itp.). Może posiadać określone atrybuty, a odwołanie do niego

Bardziej szczegółowo

ECDL/ICDL Przetwarzanie tekstów Moduł B3 Sylabus - wersja 5.0

ECDL/ICDL Przetwarzanie tekstów Moduł B3 Sylabus - wersja 5.0 ECDL/ICDL Przetwarzanie tekstów Moduł B3 Sylabus - wersja 5.0 Przeznaczenie sylabusa Dokument ten zawiera szczegółowy sylabus dla modułu ECDL/ICDL Przetwarzanie tekstów. Sylabus opisuje zakres wiedzy i

Bardziej szczegółowo

Instalacja programu Warsztat 3 w sieci

Instalacja programu Warsztat 3 w sieci Instalacja programu Warsztat 3 w sieci (proszę uważnie przeczytać do końca) Spis treści 1 Przed instalacją...2 2 Przeprowadzanie po raz pierwszy instalacji sieciowej...3 2.1 Dane umieszczone na jednej

Bardziej szczegółowo

Programowanie niskopoziomowe

Programowanie niskopoziomowe W. Complak, J.Kniat, M. Antczak, K. Kwarciak, G. Palik, A. Rybarczyk, Ł. Wielebski Materiały Programowanie niskopoziomowe http://www.cs.put.poznan.pl/arybarczyk/c_w_0.pdf Spis treści 1. Instalacja środowiska

Bardziej szczegółowo

Ćwiczenie: JavaScript Cookies (3x45 minut)

Ćwiczenie: JavaScript Cookies (3x45 minut) Ćwiczenie: JavaScript Cookies (3x45 minut) Cookies niewielkie porcje danych tekstowych, które mogą być przesyłane między serwerem a przeglądarką. Przeglądarka przechowuje te dane przez określony czas.

Bardziej szczegółowo

Podstawy programowania. Wykład: 9. Łańcuchy znaków. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Podstawy programowania. Wykład: 9. Łańcuchy znaków. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD Podstawy programowania Wykład: 9 Łańcuchy znaków 1 dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD Rodzaje plików Dane przechowywane w pliku mogą mieć reprezentację binarną (taką samą, jak

Bardziej szczegółowo

System operacyjny Linux

System operacyjny Linux Paweł Rajba pawel.rajba@continet.pl http://kursy24.eu/ Zawartość modułu 2 Instalacja opensuse Przygotowanie do instalacji Konfiguracja instalacji Zakończenie instalacji Instalacja oprogramowania Program

Bardziej szczegółowo

Języki i metodyka programowania. Wprowadzenie do języka C

Języki i metodyka programowania. Wprowadzenie do języka C Literatura: Brian W. Kernighan, Dennis M. Ritchie Język Ansi C, Wydawnictwa Naukowo - Techniczne, 2007 http://cm.bell-labs.com/cm/cs/cbook/index.html Scott E. Gimpel, Clovis L. Tondo Język Ansi C. Ćwiczenia

Bardziej szczegółowo

ANALIZA I INDEKSOWANIE MULTIMEDIÓW (AIM)

ANALIZA I INDEKSOWANIE MULTIMEDIÓW (AIM) ANALIZA I INDEKSOWANIE MULTIMEDIÓW (AIM) LABORATORIUM 5 - LOKALIZACJA OBIEKTÓW METODĄ HISTOGRAMU KOLORU 1. WYBÓR LOKALIZOWANEGO OBIEKTU Pierwszy etap laboratorium polega na wybraniu lokalizowanego obiektu.

Bardziej szczegółowo

1. Wprowadzanie danych z klawiatury funkcja scanf

1. Wprowadzanie danych z klawiatury funkcja scanf 1. Wprowadzanie danych z klawiatury funkcja scanf Deklaracja int scanf ( const char *format, wskaźnik, wskaźnik,... ) ; Biblioteka Działanie stdio.h Funkcja scanf wczytuje kolejne pola (ciągi znaków),

Bardziej szczegółowo

Grafika rastrowa (bitmapa)-

Grafika rastrowa (bitmapa)- Grafika komputerowa Grafika rastrowa Grafika rastrowa (bitmapa)- sposób zapisu obrazów w postaci prostokątnej tablicy wartości, opisujących kolory poszczególnych punktów obrazu (prostokątów składowych).

Bardziej szczegółowo

Kolumna Zeszyt Komórka Wiersz Tabela arkusza Zakładki arkuszy

Kolumna Zeszyt Komórka Wiersz Tabela arkusza Zakładki arkuszy 1 Podstawowym przeznaczeniem arkusza kalkulacyjnego jest najczęściej opracowanie danych liczbowych i prezentowanie ich formie graficznej. Ale formuła arkusza kalkulacyjnego jest na tyle elastyczna, że

Bardziej szczegółowo