Diamo per scontato che arrivati a questo punto siate riusciti ad installare per bene Eclipse e Opencv (su Windows o su Linux) e siate pronti all'utilizzo.
Al momento in cui scrivo questo articolo, OpenCV è arrivata alla sua versione 2.4.2; le librerie dinamiche che potete trovare sono:
- core: libreria principale di OpenCV; contiene tutte le strutture dati e le funzioni di base per lavorare sulle immagini.
- imgproc: come dice il nome stesso, libreria con le funzioni di Image Processing; ciò significa che se dovete applicare un filtro ad una immagine o una trasformazione geometrica, questa è la libreria che dovete linkare.
- highgui: definisce una serie di funzioni per l'I/O e per visualizzare su finestre le immagini o un video; si occupa in pratica della parte user-interface; recentemente sono state aggiunte alcune funzionalità legate alle librerie QT.
- video: contiene le funzioni di analisi video.
- objdetect: se avete bisogno di funzioni per l'Object Detection all'interno di video o immagini, questa è la libreria che fa per voi.
- ml: libreria con alcune funzioni di Machine Learning che possono essere applicate ad un insieme di immagini.
- gpu: volete sfruttare al meglio la vostra workstation? Fate lavorare anche il processore grafico con le funzioni di questa libreria.
- features2d: contiene tutte le funzioni per estrarre descrittori dalle immagini per effettuare confronti tra queste a seconda delle caratteristiche selezionate.
- legacy: la cantina di OpenCV; contiene tutte le funzioni ormai deprecate.
- contrib: modulo che contiene funzionalità recentemente aggiunte alla libreria, ma che devono essere ancora stabilizzate (da usare a vostro rischio e pericolo insomma).
- stitching: contiene funzioni per combinare più immagini per produrre effetti come le foto panoramiche o ad alta risoluzione.
- calib3d: libreria con i metodi per la calibrazione delle telecamere e per la ricostruzione 3D.
Per utilizzare le funzionalità di questi moduli, il procedimento è quello spiegato alla fine degli articoli di configurazione.
Adesso, per cominciare a vedere le funzioni di base di OpenCV, diamo un'occhiata al codice seguente:
#include <stdio.h> #include <stdlib.h> #include <opencv/cv.h> #include <opencv/highgui.h> int main(int argc, char* argv[]) { IplImage* img = cvLoadImage( "es1.jpg" ); if (img == NULL) { fprintf(stderr, "Immagine non selezionata"); exit(-1); } cvNamedWindow( "PrimoEsempio", CV_WINDOW_AUTOSIZE ); cvShowImage("PrimoEsempio", img); cvWaitKey('q'); cvReleaseImage( &img ); cvDestroyWindow( "PrimoEsempio" ); return 0; }
La prima struttura dati da esaminare è IplImage, contenuta in cv.h e quindi in core. Un oggetto della classe IplImage deriva dalla classe CvArr e contiene attributi e funzioni per la gestione di un'immagine. Tra gli attributi principali troviamo width e height i quali definiscono la risoluzione dell'immagine, nChannels che ci indica il numero di canali dell'immagine (1 se in scala di grigi, 3 se RGB, per esempio) e depth che invece specifica la profondità, intesa come numero di bit attribuiti ad ogni pixel per descrivere il colore; ma l'attributo più importante di tutti è imageData che contiene la vera e propria informazione dell'immagine (alla fine di questo articolo sarà spiegato come accedere ai suoi elementi).
Un oggetto IplImage è associato ad una specifica immagine. Per attribuirgli un'immagine è utilizzata la funzione cvLoadImage() che prende in ingresso come argomento il path di locazione dell'immagine che vogliamo caricare.
Dopo aver controllato che l'immagine caricata esista, utilizziamo una funzione della libreria highgui per creare una finestra. cvNamedWindow() ha come parametri principali una stringa che identifica la finestra (che vedrete visualizzata sulla barra del titolo) ed un parametro qui settato a CV_WINDOW_AUTOSIZE che fa in modo che le dimensioni della finestra siano dettate dalle dimensioni dell'immagine visualizzata.
Con cvShowImage() mostriamo nella finestra identificata dalla sua stringa l'immagine che passiamo come secondo argomento (sottoforma di puntatore a CvArr). In questo codice la finestra rimane sul video finchè non premete il tasto q; ciò è realizzato grazie alla funzione cvWaitKey() la quale mette in attesa il programma finchè non è premuto il tasto indicato come parametro tramite char o tramite il suo codice ASCII.
A questo punto il nostro semplice codice si avvia verso il viale del tramonto, ma prima di terminare è MOLTO IMPORTANTE che rilasciate gli oggetti che avete allocato, siano questi CvArr o Finestre. Le due funzioni che si occupano di questo sono cvReleaseImage() e cvDestroyWindow(). Ricordatevi sempre di pulire tutto quanto prima di terminare l'esecuzione del programma.
Per creare un'immagine senza che questa sia presente da qualche parte in memoria (procedimento che può servire se c'è bisogno di un'immagine di appoggio su cui lavorare), si usa la funzione cvCreateImage(); ad esempio se volessimo creare una generica immagine 100px per 100px, a 3 canali, con 8 bit di profondità, l'istruzione sarebbe questa:
IplImage *img = cvCreateImage(cvSize(100, 100), IPL_DEPTH_8U, 3);
CvSize è una classe di core formata da due soli attributi, height e width, che definisce un rettangolo di pixel delle dimensioni definite dai valori dei suoi due attributi.
Concludiamo questa introduzione con un esempio di codice per accedere ai singoli pixel di un'immagine, le cui informazioni, ricordiamo, sono contenute nell'attributo imageData di IplImage.
// questo codice è da inserire nel precedente, // prima della chiamata alla funzione cvWaitKey() int r,g,b; uchar* data = (uchar *) img->imageData; if(img->nChannels==3){ for (int y = 0; y < (img)->height; y ++) for (int x = 0; x < (img)->width; x ++) { r=data[y * img->widthStep + x * img->nChannels + 0]; g=data[y * img->widthStep + x * img->nChannels + 1]; b=data[y * img->widthStep + x * img->nChannels + 2]; std::cout << "red: " << r << " green: " << g << " blue: " << b; } } else if (img->nChannels==1){ for (int y = 0; y < (img)->height; y ++) for (int x = 0; x < (img)->width; x ++) { g=data[y * img->widthStep + x ]; std::cout << "gray: " << g << endl; } }
Vedete come per accedere ai valori dei pixel si usa un metodo diretto poichè OpenCV gestisce ogni immagine come fosse un array monodimensionale. L'attributo widthstep di IplImage definisce la dimensione in bytes relativa al passo con il quale sono allineate le righe.
In generale, a seconda del numero di canali dell'immagine indicato da nChannels, per accedere al pixel (i,j) si avrà:
i*widthStep + j*nChannels + k
con i che varia tra [0, height-1], j che varia tra [0, width-1] e k appartenente a [0, nChannels-1].
