Wstęp do programowania z użyciem OpenCV

Streszczenie:

Celem tego dokumentu jest umożliwienie szybkiego rozpoczęcia pracy z biblioteką OpenCV bez przedzierania się przez wielką dokumentację biblioteki. Jeśli zrozumiesz zamieszczone tu podstawy, będziesz w stanie wyszukiwać informacje w dokumentacji OpenCV na niezbędnym poziomie.

Zawartość

 

 

 

Wstęp

Opis OpenCV

  • Ogólny opis biblioteki
    • Open source computer vision library in C/C++.
    • Zoptymalizowana i przeznaczona do aplikacji typu real-time.
    • Niezależna od systemu, sprzętu ani menadżera okienek.
    • Ładowanie, zapisywanie i rozsyłanie Generic image/video.
    • Nisko i wysokopoziomowe API.
    • Provides interface to Intel's Integrated Performance Primitives (IPP) with processor specific optimization (Intel processors).

  • Właściwości:
    • Przetwarzanie danych obrazowych (allocation, zwalnianie, kopiowanie, ustawienia, konwersja).
    • Obraz oraz wideo I/O (plik lub wejście z kamery, wyjściowy plik obraz/video).
    • Operacje na macierzach i wektorach oraz procedury algebry liniowej (iloczyny, solvers, wartości własne [eigenvalues], SVD [rozkład wg wartości osobliwych]).
    • Różne dynamiczne struktury danych (listy, queues, sets, drzewa, grafy).
    • Podstawowe przetwarzanie obrazu (filtrowanie, wykrywanie krawędzi, wykrywanie narożników, próbkowanie i interpolacja, zmiana kolorów, operacje morfologiczne, histogramy, piramidy obrazów).
    • Analiza strukturalna (connected components, przetwarzanie konturów, distance transform, various moments, dopasowanie wzorców, transformata Hough'a, aproksymacja wielokątami, dopasowanie linii, dopasowanie elipsy, triangulacja Delaunay [Delone]). Tutaj przykład triangulacji na płaszczyźnie
    • Kalibracja kamery (wyszukiwanie i śledzenie wzorów kalibracyjnych, kalibracja, fundamental matrix estimation, homography estimation, stereo correspondence).
    • Analiza ruchu (optical flow, motion segmentation, śledzenie).
    • Rozpoznawanie obrazów (eigen-methods, HMM).
    • Prosty GUI (wyświetlanie obrazu/wideo, obsługa klawiatury i myszki, paski przewijania).
    • Image labeling (linia, conic, wielokąt, rysowanie tekstów)

  • Moduły OpenCV:
    • cv - Główne funkcje OpenCV.
    • cvaux - Funkcje pomocnicze (eksperymentalne) OpenCV.
    • cxcore - Wsparcie struktur danych i algebry liniowej.
    • highgui - Funkcje GUI.

Zasoby

  • Podręczniki:
    • <opencv-root>/docs/index.htm

  • Zasoby sieciowe:
    • Official webpage: http://www.intel.com/technology/computing/opencv/

    • Pobieranie oprogramowania: http://sourceforge.net/projects/opencvlibrary/

  • Książki:
    • Open Source Computer Vision Library by Gary R. Bradski, Vadim Pisarevsky, and Jean-Yves Bouguet, Springer, 1st ed. (June, 2006).

  • Przykładowe programy do przetwarzania wideo (znajdują się w: <opencv-root>/samples/c/):
    • śledzenie koloru: camshiftdemo
    • śledzenie punktu: lkdemo
    • motion segmentation: motempl
    • wykrywanie krawędzi: laplace

  • Przykładowe programy do przetwarzania obrazów (znajdują się w: <opencv-root>/samples/c/):
    • wykrywanie krawędzi: edge
    • segmentation: pyramid_segmentation
    • morphologia: morphology
    • histogramy: demhist
    • distance transform: distrans
    • ellipse fitting: fitellipse

Konwencja nazewnicza OpenCV

  • Konwencja nazewnicza funkcji:
        cvActionTargetMod(...)
    
        Action = the core functionality (tj. set, create)
        Target = the target image area (tj. contour, polygon)
        Mod    = opcjonalne modyfikatory (tj. typ argumentu)
    

  • Typy danych tablicowych:
        CV_<bit_depth>(S|U|F)C<number_of_channels>
    
        S = całkowitoliczbowa ze znakiem (Signed)
        U = całkowitoliczbowa bez znaku (Unsigned)
        F = zmiennoprzecinkowa (Float) 
    
        E.g.: CV_8UC1 oznacza 8-bitową, single-channel macierz bez znaku, 
              CV_32FC2 oznacza 32-bitową, two channels macierz zmiennoprzecinkową.
    

  • Typy danych obrazowych:
        IPL_DEPTH_<bit_depth>(S|U|F)
    
        E.g.: IPL_DEPTH_8U oznacza obraz 8-bitowy bez znaku.
              IPL_DEPTH_32F oznacza obraz 32-bitowy zmiennoprzecinkowy.
    

  • Pliki nagłówkowe:
        #include <cv.h>
        #include <cvaux.h>
        #include <highgui.h>  
        #include <cxcore.h>   // niekoniecznie - zawarty w cv.h
    

Polecenia kompilacji

  • Linux:
    g++ hello-world.cpp -o hello-world \
        -I /usr/local/include/opencv -L /usr/local/lib  \
        -lm -lcv -lhighgui -lcvaux
    

  • Windows:
    W parametrach projektu należy ustawić ścieżkę do plików nagłówkowych OpenCV oraz
    ścieżkę dostępu do plików bibliotecznych OpenCV.
    

Przykładowy program w C

////////////////////////////////////////////////////////////////////////////////
//
// hello-world.cpp
//
// To jest prosty, przykładowy program wykorzystujący OpenCV. Program odczytuje
// obraz z pliku, odwraca go, wyświetla obraz wynikowy na ekranie. 
//
////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <cv.h>
#include <highgui.h>


int main(int argc, char *argv[])
{
  IplImage* img = 0; 
  int height,width,step,channels;
  uchar *data;
  int i,j,k;

  if(argc<2){
    printf("Usage: main <image-file-name>\n\7");
    exit(0);
  }

  // ładowanie obrazu  
  img=cvLoadImage(argv[1]);
  if(!img){
    printf("Could not load image file: %s\n",argv[1]);
    exit(0);
  }

  // pobieranie danych obrazu
  height    = img->height;
  width     = img->width;
  step      = img->widthStep;
  channels  = img->nChannels;
  data      = (uchar *)img->imageData;
  printf("Processing a %dx%d image with %d channels\n",height,width,channels); 

  // tworzenie okna
  cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE); 
  cvMoveWindow("mainWin", 100, 100);

  // odwracanie obrazu 
  for(i=0;i<height;i++) for(j=0;j<width;j++) for(k=0;k<channels;k++)
    data[i*step+j*channels+k]=255-data[i*step+j*channels+k];

  // wyświetlanie obrazu
  cvShowImage("mainWin", img );

  // oczekiwanie na naciśnięcie dowolnego klawisza
  cvWaitKey(0);

  // usunięcie obrazu z pamięci
  cvReleaseImage(&img );
  return 0;
}


Λ Do góry


Polecenia GUI

Zarządzanie okienkiem

  • Tworzenie i pozycjonowanie okna:
      cvNamedWindow("win1", CV_WINDOW_AUTOSIZE); 
      cvMoveWindow("win1", 100, 100); // offset względem lewego, górnego narożnika ekranu
    

  • Ładowanie obrazu:
      IplImage* img=0; 
      img=cvLoadImage(fileName);
      if(!img) printf("Nie mozna zaladowac obrazu: %s\n",fileName);
    

  • Wyświetlenie obrazu:
      cvShowImage("win1",img);
    

    Może wyświetlić kolorowy albo czarno-biały ( byte/float) obraz. Obraz bajtowy zawiera wartości z zakresu [0...255]. Obraz zmiennoprzecinkowy zawiera wartości z przedziału [0...1]. Obraz kolorowy zawiera dane w porządku BGR.

  • Zamknięcie okna:
      cvDestroyWindow("win1");
    

  • Skalowanie okna:
      cvResizeWindow("win1",100,100); // nowa szerokość/wysokość w pikselach
    

Obsługa wejść

  • Obsługa zdarzeń myszki:
    • Definiowanie obsługi myszki:
        void mouseHandler(int event, int x, int y, int flags, void* param)
        {
          switch(event){
            case CV_EVENT_LBUTTONDOWN:
              if(flags & CV_EVENT_FLAG_CTRLKEY) 
                printf("Left button down with CTRL pressed\n");
              break;
      
            case CV_EVENT_LBUTTONUP:
              printf("Left button up\n");
              break;
          }
        }
      
        x,y:   współrzędne w pikselach względem lewego, górnego narożnika ekranu
      
        zdarzenie: CV_EVENT_LBUTTONDOWN,   CV_EVENT_RBUTTONDOWN,   CV_EVENT_MBUTTONDOWN,
                   CV_EVENT_LBUTTONUP,     CV_EVENT_RBUTTONUP,     CV_EVENT_MBUTTONUP,
                   CV_EVENT_LBUTTONDBLCLK, CV_EVENT_RBUTTONDBLCLK, CV_EVENT_MBUTTONDBLCLK,
                   CV_EVENT_MOUSEMOVE:
      
        flagi: CV_EVENT_FLAG_CTRLKEY, CV_EVENT_FLAG_SHIFTKEY, CV_EVENT_FLAG_ALTKEY,
               CV_EVENT_FLAG_LBUTTON, CV_EVENT_FLAG_RBUTTON,  CV_EVENT_FLAG_MBUTTON
      

    • Rejestrowanie obsługi:
        mouseParam=5;
        cvSetMouseCallback("win1",mouseHandler,&mouseParam);
      

  • Obsługa zdarzeń klawiatury:
    • Klawiatura nie ma obsługi zdarzeń.

    • Odczytaj klawiaturę bez zatrzymywania:
        int key;
        key=cvWaitKey(10); // czekaj 10ms na dane
      

    • Odczytaj klawiaturę ze wstrzymywaniem:
        int key;
        key=cvWaitKey(0); // czekaj na dane do skutku 
      

    • Główna pętla zdarzeń klawiatury:
        while(1){
          key=cvWaitKey(10);
          if(key==27) break;
      
          switch(key){
            case 'h':
              ...
              break;
            case 'i':
              ...
              break;
          }
        }
      

  • Obsługa pasków przewijania:
    • Definiowanie obsługi pasków przewijania:
        void trackbarHandler(int pos)
        {
          printf("Trackbar position: %d\n",pos);
        }
      

    • Rejestrowanie obsługi:
        int trackbarVal=25;
        int maxVal=100;
        cvCreateTrackbar("bar1", "win1", &trackbarVal ,maxVal , trackbarHandler);
      

    • Odczytaj bieżące położenie paska przewijania:
        int pos = cvGetTrackbarPos("bar1","win1");
      

    • Ustaw położenie paska przewijania:
        cvSetTrackbarPos("bar1", "win1", 25);
      


Λ Do góry


Podstawowe struktury danych OpenCV

Struktury danych obrazowych

  • IPL image:
    IplImage
      |-- int  nChannels;     // Number of color channels (1,2,3,4)
      |-- int  depth;         // Pixel depth in bits: 
      |                       //   IPL_DEPTH_8U, IPL_DEPTH_8S, 
      |                       //   IPL_DEPTH_16U,IPL_DEPTH_16S, 
      |                       //   IPL_DEPTH_32S,IPL_DEPTH_32F, 
      |                       //   IPL_DEPTH_64F
      |-- int  width;         // image width in pixels
      |-- int  height;        // image height in pixels
      |-- char* imageData;    // pointer to aligned image data
      |                       // Note that color images are stored in BGR order
      |-- int  dataOrder;     // 0 - interleaved color channels, 
      |                       // 1 - separate color channels
      |                       // cvCreateImage can only create interleaved images
      |-- int  origin;        // 0 - top-left origin,
      |                       // 1 - bottom-left origin (Windows bitmaps style)
      |-- int  widthStep;     // size of aligned image row in bytes
      |-- int  imageSize;     // image data size in bytes = height*widthStep
      |-- struct _IplROI *roi;// image ROI. when not NULL specifies image
      |                       // region  to be processed.
      |-- char *imageDataOrigin; // pointer to the unaligned origin of image data
      |                          // (needed for correct image deallocation)
      |
      |-- int  align;         // Alignment of image rows: 4 or 8 byte alignment
      |                       // OpenCV ignores this and uses widthStep instead
      |-- char colorModel[4]; // Color model - ignored by OpenCV
    

Macierze i wektory

  • Macierze:
    CvMat                      // 2D array
      |-- int   type;          // elements type (uchar,short,int,float,double) and flags
      |-- int   step;          // full row length in bytes
      |-- int   rows, cols;    // dimensions
      |-- int   height, width; // alternative dimensions reference
      |-- union data;
          |-- uchar*  ptr;     // data pointer for an unsigned char matrix
          |-- short*  s;       // data pointer for a short matrix
          |-- int*    i;       // data pointer for an integer matrix
          |-- float*  fl;      // data pointer for a float matrix
          |-- double* db;      // data pointer for a double matrix
    
    
    CvMatND                    // N-dimensional array
      |-- int   type;          // elements type (uchar,short,int,float,double) and flags
      |-- int   dims;          // number of array dimensions
      |-- union data;
      |   |-- uchar*  ptr;     // data pointer for an unsigned char matrix
      |   |-- short*  s;       // data pointer for a short matrix
      |   |-- int*    i;       // data pointer for an integer matrix
      |   |-- float*  fl;      // data pointer for a float matrix
      |   |-- double* db;      // data pointer for a double matrix
      |
      |-- struct dim[];        // information for each dimension
          |-- size;            // number of elements in a given dimension
          |-- step;            // distance between elements in a given dimension
    
    
    CvSparseMat // SPARSE N-dimensional array
    

  • Tablice ogólne:
    CvArr*     // Used only as a function parameter to specify that the
               // function accepts arrays of more than a single type, such
               // as: IplImage*, CvMat* or even CvSeq*. The particular array 
               // type is determined at runtime by analyzing the first 4
               // bytes of the header of the actual array.
    

  • Skalary:
    CvScalar
      |-- double val[4]; //4D wektor
    

    Funkcja inicjująca:

    CvScalar s = cvScalar(double val0, double val1=0, double val2=0, double val3=0);
    

    Przykład:

    CvScalar s = cvScalar(20.0);
    s.val[0]=10.0;
    

    Zauważ, że funkcja inicjująca ma taką samą nazwę jak struktura danych, ale zaczyna się od małej litery. To nie jest konstruktor w rozumieniu C++.

Inne struktury danych

  • Punkty:
    CvPoint      p = cvPoint(int x, int y);
    CvPoint2D32f p = cvPoint2D32f(float x, float y);
    CvPoint3D32f p = cvPoint3D32f(float x, float y, float z);
    
    Przykład:
    p.x=5.0;
    p.y=5.0;
    

  • Wymiary prostokąta:
    CvSize       r = cvSize(int width, int height);
    CvSize2D32f  r = cvSize2D32f(float width, float height);
    

  • Wymiary prostokąta z ofsetem:
    CvRect       r = cvRect(int x, int y, int width, int height);
    


Λ Do góry


Praca z obrazami

Alokacja i zwalnianie obrazów

  • Alokacja obrazu:
    IplImage* cvCreateImage(CvSize size, int depth, int channels);
    
      rozmiar:  cvSize(width,height);
    
      głębokość: głębia kolorów w bitach: IPL_DEPTH_8U, IPL_DEPTH_8S, IPL_DEPTH_16U,
        IPL_DEPTH_16S, IPL_DEPTH_32S, IPL_DEPTH_32F, IPL_DEPTH_64F
    
      kanały: Liczba kanałów na piksel. Mogą być 1, 2, 3 lub 4. Kanały są z przeplotem. 
        Zazwyczaj rozkład danych dla obrazu kolorowego jest następujący
        b0 g0 r0 b1 g1 r1 ...
    

    Przykłady:

    // Alokacja 1-kanałowego obrazu z danymi bajtowymi
    IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); 
    
    // Alokacja  3-kanałowego obrazu z danymi float
    IplImage* img2=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
    

  • Zwalnianie obrazu:
    IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); 
    cvReleaseImage(&img);
    

  • Powielanie obrazu:
    IplImage* img1=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1); 
    IplImage* img2;
    img2=cvCloneImage(img1);
    

  • Określanie/pobieranie rozmiarów fragmentu obrazu:
    void  cvSetImageROI(IplImage* image, CvRect rect);
    void  cvResetImageROI(IplImage* image);
    vRect cvGetImageROI(const IplImage* image);
    
    Większość funkcji OpenCV wspiera obsługę rozmiarów (ROI - region of interest).
    

  • Określanie/pobieranie liczby kamałów:
    void cvSetImageCOI(IplImage* image, int coi); // 0=all
    int cvGetImageCOI(const IplImage* image);
    

    Większość funkcji OpenCV NIE WSPIERA określania liczby kanałów (COI - channel of interest).

Odczytywanie i zapisywanie obrazów

  • Odczytanie obrazu z pliku:
      IplImage* img=0; 
      img=cvLoadImage(fileName);
      if(!img) printf("Nie można załadować pliku: %s\n",fileName);
    
      Obsługiwane formaty: BMP, DIB, JPEG, JPG, JPE, PNG, PBM, PGM, PPM,
                               SR, RAS, TIFF, TIF
    

    Ładowany obraz domyślnie jest traktowany jako 3-kanałowy obraz kolorowy. Może to być zmienione przez zastosowanie:

      img=cvLoadImage(fileName,flag);
    
      flag: >0 the loaded image is forced to be a 3-channel color image
            =0 the loaded image is forced to be a 1 channel grayscale image
            <0 the loaded image is loaded as is (with number of channels in the file).
    

  • Zapis obrazu do pliku:
      if(!cvSaveImage(outFileName,img)) printf("Nie mozna zapisac: %s\n",outFileName);
    

    Format pliku wyjściowego jest określony przez rozszerzenie nazwy pliku.

Dostęp do elementów obrazu Accessing image elements

  • Załóżmy, że potrzebujesz uzyskać dostęp do punktu o współrzędnych i,j (wiersz, kolumna) należącego do kanału k. Wskaźnik wiersza i należy do przedziału [0, wysokość-1]. Wskaźnik kolumny j należy do przedziału [0, szerokość-1]. Wskaźnik kanału k należy do przedziału [0, liczba_kanałów-1]. 

  • Dostęp pośredni: (podstawowy, ale nieefektywny dostęp do obrazów dowolnego typu)

    • For a single-channel byte image:
      IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
      CvScalar s;
      s=cvGet2D(img,i,j); // get the (i,j) pixel value
      printf("intensity=%f\n",s.val[0]);
      s.val[0]=111;
      cvSet2D(img,i,j,s); // set the (i,j) pixel value
      

    • For a multi-channel float (or byte) image:
      IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
      CvScalar s;
      s=cvGet2D(img,i,j); // get the (i,j) pixel value
      printf("B=%f, G=%f, R=%f\n",s.val[0],s.val[1],s.val[2]);
      s.val[0]=111;
      s.val[1]=111;
      s.val[2]=111;
      cvSet2D(img,i,j,s); // set the (i,j) pixel value
      

  • Dostęp bezpośredni: (Dostęp efektywny, aleEfficient access, ale podatny na błędy)

    • For a single-channel byte image:
      IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
      ((uchar *)(img->imageData + i*img->widthStep))[j]=111;
      

    • For a multi-channel byte image:
      IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
      ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B
      ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G
      ((uchar *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R
      

    • For a multi-channel float image:
      IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
      ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 0]=111; // B
      ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 1]=112; // G
      ((float *)(img->imageData + i*img->widthStep))[j*img->nChannels + 2]=113; // R
      

  • Dostęp bezpośredni z użyciem wskaźnika: (Uproszczony i efektywny dostęp przy założeniu ograniczeń)

    • For a single-channel byte image:
      IplImage* img  = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
      int height     = img->height;
      int width      = img->width;
      int step       = img->widthStep/sizeof(uchar);
      uchar* data    = (uchar *)img->imageData;
      data[i*step+j] = 111;
      

    • For a multi-channel byte image:
      IplImage* img  = cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
      int height     = img->height;
      int width      = img->width;
      int step       = img->widthStep/sizeof(uchar);
      int channels   = img->nChannels;
      uchar* data    = (uchar *)img->imageData;
      data[i*step+j*channels+k] = 111;
      

    • For a multi-channel float image (assuming a 4-byte alignment):
      IplImage* img  = cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
      int height     = img->height;
      int width      = img->width;
      int step       = img->widthStep/sizeof(float);
      int channels   = img->nChannels;
      float * data    = (float *)img->imageData;
      data[i*step+j*channels+k] = 111;
      

  • Direct access using a c++ wrapper: (Simple and efficient access)

    • Define a c++ wrapper for single-channel byte images, multi-channel byte images, and multi-channel float images:
      template<class T> class Image
      {
        private:
        IplImage* imgp;
        public:
        Image(IplImage* img=0) {imgp=img;}
        ~Image(){imgp=0;}
        void operator=(IplImage* img) {imgp=img;}
        inline T* operator[](const int rowIndx) {
          return ((T *)(imgp->imageData + rowIndx*imgp->widthStep));}
      };
      
      typedef struct{
        unsigned char b,g,r;
      } RgbPixel;
      
      typedef struct{
        float b,g,r;
      } RgbPixelFloat;
      
      typedef Image<RgbPixel>       RgbImage;
      typedef Image<RgbPixelFloat>  RgbImageFloat;
      typedef Image<unsigned char>  BwImage;
      typedef Image<float>          BwImageFloat;
      

    • For a single-channel byte image:
      IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,1);
      BwImage imgA(img);
      imgA[i][j] = 111;
      

    • For a multi-channel byte image:
      IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_8U,3);
      RgbImage  imgA(img);
      imgA[i][j].b = 111;
      imgA[i][j].g = 111;
      imgA[i][j].r = 111;
      

    • For a multi-channel float image:
      IplImage* img=cvCreateImage(cvSize(640,480),IPL_DEPTH_32F,3);
      RgbImageFloat imgA(img);
      imgA[i][j].b = 111;
      imgA[i][j].g = 111;
      imgA[i][j].r = 111;
      

Konwersja obrazu

  • Zamiana na czarno-biały lub kolorowy, jednobajtowy obraz:
    cvConvertImage(src, dst, flags=0);
    
      src = float/byte grayscale/color image
      dst = byte grayscale/color image
      flags = CV_CVTIMG_FLIP     (flip vertically)
              CV_CVTIMG_SWAP_RB  (swap the R and B channels)
    

  • Zamiana obrazu kolorowego na czarno-biały:


    Zastosowanie konwersji OpenCV:

    cvCvtColor(cimg,gimg,CV_BGR2GRAY); // cimg -> gimg
    


    Zastosowanie bezpośredniej konwersji:

    for(i=0;i<cimg->height;i++) for(j=0;j<cimg->width;j++) 
      gimgA[i][j]= (uchar)(cimgA[i][j].b*0.114 + 
                           cimgA[i][j].g*0.587 + 
                           cimgA[i][j].r*0.299);
    

  • Konwersja pomiędzy przestrzeniami kolorów:

    cvCvtColor(src,dst,code); // src -> dst
    
      code    = CV_<X>2<Y>
      <X>/<Y> = RGB, BGR, GRAY, HSV, YCrCb, XYZ, Lab, Luv, HLS
    
    np. : CV_BGR2GRAY, CV_BGR2HSV, CV_BGR2Lab
    

Polecenia rysowania

  • Rysuj prostokąt:
    // narysuj prostokąt o czerwonych krawędziach i grubości 1 
    //pomiędzy punktami (100,100) i (200,200)
    cvRectangle(img, cvPoint(100,100), cvPoint(200,200), cvScalar(255,0,0), 1);
    

  • Rysuj okrąg:
    // narysuj okrąg o środku w (100,100) i promieniu 20. Użyj zielonej linii o grubości 1
    cvCircle(img, cvPoint(100,100), 20, cvScalar(0,255,0), 1);
    

  • Rysuj odcinek:
    // narysuj odcinek o grubości 1 pomiędzy (100,100) and (200,200)
    cvLine(img, cvPoint(100,100), cvPoint(200,200), cvScalar(0,255,0), 1);
    

  • Rysuj linię łamaną:
    CvPoint  curve1[]={10,10,  10,100,  100,100,  100,10};
    CvPoint  curve2[]={30,30,  30,130,  130,130,  130,30,  150,10};
    CvPoint* curveArr[2]={curve1, curve2};
    int      nCurvePts[2]={4,5};
    int      nCurves=2;
    int      isCurveClosed=1;
    int      lineWidth=1;
    
    cvPolyLine(img,curveArr,nCurvePts,nCurves,isCurveClosed,cvScalar(0,255,255),lineWidth);
    

  • Rysuj wypełniony wielokąt:
    cvFillPoly(img,curveArr,nCurvePts,nCurves,cvScalar(0,255,255));
    

  • Dodaj tekst:
    CvFont font;
    double hScale=1.0;
    double vScale=1.0;
    int    lineWidth=1;
    cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX|CV_FONT_ITALIC, hScale,vScale,0,lineWidth);
    
    cvPutText (img,"My comment",cvPoint(200,400), &font, cvScalar(255,255,0));
    

    Inne dostępne kroje czcionek:

    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,
    


Λ Do góry


Działania na macierzach

Alokacja i zwalnianie macierzy

  • Ogólne:
    • OpenCV has a C interface to matrix operations. There are many alternatives that have a C++ interface (which is more convenient) and are as efficient as OpenCV.
    • Vectors are obtained in OpenCV as matrices having one of their dimensions as 1.
    • Matrices are stored row by row where each row has a 4 byte alignment.

  • Alokacja macierzy:
    CvMat* cvCreateMat(int rows, int cols, int type);
    
      type: Type of the matrix elements. Specified in form
      CV_<bit_depth>(S|U|F)C<number_of_channels>.  E.g.: CV_8UC1 oznacza
      8-bitową bez znaku macierz jednokanałową, CV_32SC2 oznacza 32-bitową ze znakiem
      macierz z dwoma kanałami.
    
      Przykład:
      CvMat* M = cvCreateMat(4,4,CV_32FC1);
    

  • Zwalnianie macierzy:
    CvMat* M = cvCreateMat(4,4,CV_32FC1);
    cvReleaseMat(&M);
    

  • Powielanie macierzy:
    CvMat* M1 = cvCreateMat(4,4,CV_32FC1);
    CvMat* M2;
    M2=cvCloneMat(M1);
    

  • Inicjalizacja macierzy:
    double a[] = { 1,  2,  3,  4,
                   5,  6,  7,  8,
                   9, 10, 11, 12 };
    
    CvMat Ma=cvMat(3, 4, CV_64FC1, a);
    

    Zamiennie:

    CvMat Ma;
    cvInitMatHeader(&Ma, 3, 4, CV_64FC1, a);
    

  • Initialize a matrix to identity:
    CvMat* M = cvCreateMat(4,4,CV_32FC1);
    cvSetIdentity(M); // does not seem to be working properly
    

Udostępnianie elementów macierzy

  • Załóżmy, że potrzebujesz uzyskać dostęp do (i,j) komórki 2-wymiarowej tablicy zmiennoprzecinkowej.

  • Dostęp pośredni do elementów tablicy:
    cvmSet(M,i,j,2.0); // Set M(i,j)
    t = cvmGet(M,i,j); // Get M(i,j)
    

  • Bezpośredni dostęp do elementów macierzy przyjmując zapis 4-bajtowy:
    CvMat* M    = cvCreateMat(4,4,CV_32FC1);
    int n       = M->cols;
    float *data = M->data.fl;
    
    data[i*n+j] = 3.0;
    

  • Direct matrix element access assuming possible alignment gaps:
    CvMat* M    = cvCreateMat(4,4,CV_32FC1);
    int   step  = M->step/sizeof(float);
    float *data = M->data.fl;
    
    (data+i*step)[j] = 3.0;
    

  • Direct matrix element access of an initialized matrix:
    double a[16];
    CvMat Ma = cvMat(3, 4, CV_64FC1, a);
    a[i*4+j] = 2.0; // Ma(i,j)=2.0;
    

Operacje na macierzach/wektorach

  • Operacje macierz-macierz:
    CvMat *Ma, *Mb, *Mc;
    cvAdd(Ma, Mb, Mc);      // Ma+Mb   -> Mc
    cvSub(Ma, Mb, Mc);      // Ma-Mb   -> Mc
    cvMatMul(Ma, Mb, Mc);   // Ma*Mb   -> Mc
    

  • Podstawowe operacje na macierzach:
    CvMat *Ma, *Mb, *Mc;
    cvMul(Ma, Mb, Mc);      // Ma.*Mb  -> Mc
    cvDiv(Ma, Mb, Mc);      // Ma./Mb  -> Mc
    cvAddS(Ma, cvScalar(-10.0), Mc); // Ma.-10 -> Mc
    

  • Iloczyn wektorów:
    double va[] = {1, 2, 3};
    double vb[] = {0, 0, 1};
    double vc[3];
    
    CvMat Va=cvMat(3, 1, CV_64FC1, va);
    CvMat Vb=cvMat(3, 1, CV_64FC1, vb);
    CvMat Vc=cvMat(3, 1, CV_64FC1, vc);
    
    double res=cvDotProduct(&Va,&Vb); // dot product:   Va . Vb -> res
    cvCrossProduct(&Va, &Vb, &Vc);    // cross product: Va x Vb -> Vc
    end{verbatim}
    

    Note that Va, Vb, Vc, must be 3 element vectors in a cross product.


  • Operacje na pojedynczych macierzach:
    CvMat *Ma, *Mb;
    cvTranspose(Ma, Mb);      // transpose(Ma) -> Mb (nie może transponować na samą siebie)
    CvScalar t = cvTrace(Ma); // trace(Ma) -> t.val[0] 
    double d = cvDet(Ma);     // det(Ma) -> d
    cvInvert(Ma, Mb);         // inv(Ma) -> Mb
    

  • Inhomogeneous linear system solver:
    CvMat* A  = cvCreateMat(3,3,CV_32FC1);
    CvMat* x  = cvCreateMat(3,1,CV_32FC1);
    CvMat* b  = cvCreateMat(3,1,CV_32FC1);
    cvSolve(&A, &b, &x);    // solve (Ax=b) for x
    

  • Eigen analysis (of a symmetric matrix):
    CvMat* A  = cvCreateMat(3,3,CV_32FC1);
    CvMat* E  = cvCreateMat(3,3,CV_32FC1);
    CvMat* l  = cvCreateMat(3,1,CV_32FC1);
    cvEigenVV(&A, &E, &l);  // l = eigenvalues of A (descending order)
                            // E = corresponding eigenvectors (rows)
    

  • Singular value decomposition:
    CvMat* A  = cvCreateMat(3,3,CV_32FC1);
    CvMat* U  = cvCreateMat(3,3,CV_32FC1);
    CvMat* D  = cvCreateMat(3,3,CV_32FC1);
    CvMat* V  = cvCreateMat(3,3,CV_32FC1);
    cvSVD(A, D, U, V, CV_SVD_U_T|CV_SVD_V_T); // A = U D V^T
    

    The flags cause U and V to be returned transposed (does not work well without the transpose flags).


Λ Do góry


Praca z sekwencjami wideo

Przechwytywanie ramki z sekwencji wideo

  • OpenCV wspiera przechwytywanie obrazów z kamery lub pliku wideo (AVI).

  • Inicjalizacja przechwytywania z kamery:
    CvCapture* capture = cvCaptureFromCAM(0); // przechwytywanie z urządzenia wideo #0
    

  • Inicjalizacja przechwytywania z pliku:
    CvCapture* capture = cvCaptureFromAVI("infile.avi");
    

  • Przechwycenie ramki:
    IplImage* img = 0; 
    if(!cvGrabFrame(capture)){              // przechwycenie ramki 
      printf("Could not grab a frame\n\7");
      exit(0);
    }
    img=cvRetrieveFrame(capture);           // retrieve the captured frame
    

    W celu symultanicznego uzyskania obrazów z różnych kamer, w pierwszej kolejności pobierz obraz z każdej kamery. Odśwież przechwycone obrazy dopiero po całkowitym ich pobraniu.

  • Zwalnianie źródła obrazu:
    cvReleaseCapture(&capture);
    

    Note that the image captured by the device is allocated/released by the capture function. Nie ma konieczności jawnego zwalniania źródła.

Pobieranie/ustawianie informacji o ramce

  • Pobieranie informacji o urządzeniu przechwytującym:
    cvQueryFrame(capture); // this call is necessary to get correct 
                           // capture properties
    int frameH    = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);
    int frameW    = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
    int fps       = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);
    int numFrames = (int) cvGetCaptureProperty(capture,  CV_CAP_PROP_FRAME_COUNT);
    

    Całkowita liczba ramek jest związana tylko z plikiem wideo. Nie działa poprawnie.

  • Pobieranie informacji o ramce:
    float posMsec   =       cvGetCaptureProperty(capture, CV_CAP_PROP_POS_MSEC);
    int posFrames   = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES);
    float posRatio  =       cvGetCaptureProperty(capture, CV_CAP_PROP_POS_AVI_RATIO);
    

    Get the position of the captured frame in [msec] with respect to the first frame, or get its index where the first frame starts with an index of 0. The relative position (ratio) is 0 in the first frame and 1 in the last frame. This ratio is valid only for capturing images from a file.

  • Ustawianie indeksu pierwszej przechwytywanej ramki:
    // start capturing from a relative position of 0.9 of a video file
    cvSetCaptureProperty(capture, CV_CAP_PROP_POS_AVI_RATIO, (double)0.9);
    

    Stosuje się tylko do przechwytywania z pliku. It does not seem to be working properly.

Zapisywanie pliku wideo

  • Inicjalizacja zapisywania wideo:
    CvVideoWriter *writer = 0;
    int isColor = 1;
    int fps     = 25;  // lub 30
    int frameW  = 640; // 744 - kamery firewire
    int frameH  = 480; // 480 - kamery firewire
    writer=cvCreateVideoWriter("out.avi",CV_FOURCC('P','I','M','1'),
                               fps,cvSize(frameW,frameH),isColor);
    

    Inne dostępne kody kodeków:

    CV_FOURCC('P','I','M','1')    = MPEG-1 
    CV_FOURCC('M','J','P','G')    = motion-jpeg (nie działa zbyt dobrze)
    CV_FOURCC('M', 'P', '4', '2') = MPEG-4.2 
    CV_FOURCC('D', 'I', 'V', '3') = MPEG-4.3 
    CV_FOURCC('D', 'I', 'V', 'X') = MPEG-4 
    CV_FOURCC('U', '2', '6', '3') = H263 
    CV_FOURCC('I', '2', '6', '3') = H263I 
    CV_FOURCC('F', 'L', 'V', '1') = FLV1 
    

    Podanie kodu kodeka o wartości -1 spowoduje otwarcie okna wyboru kodeka (w Windows).

  • Zapisywanie pliku wideo:
    IplImage* img = 0; 
    int nFrames = 50;
    for(i=0;i<nFrames;i++){
      cvGrabFrame(capture);          // capture a frame
      img=cvRetrieveFrame(capture);  // retrieve the captured frame
      cvWriteFrame(writer,img);      // add the frame to the file
    }
    

    Aby obserwować przechwytywane ramki w trakcie przechwytywania, dodaj następujące do pętli:

    cvShowImage("mainWin", img); 
    key=cvWaitKey(20);           // czekaj 20 ms
    

    Uwaga, bez opóźnienia 20ms przechwycone sekwencje nie są poprawnie wyświetlone.

  • Zwalnianie zapisywania wideo:
    cvReleaseVideoWriter(&writer);
    

Λ Do góry


Gady Agam

Department of Computer Science
Illinois Institute of Technology

January 27, 2006


Tekst oryginalny znajduje się na www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/index.html