Introduzione Le Strutture Dati Una Introduzione a OpenCV Prof. Michele Scarpiniti Dipartimento di Ingegneria dell’Informazione, Elettronica e Telecomunicazioni “Sapienza” Università di Roma http://ispac.diet.uniroma1.it/scarpiniti/index.htm [email protected] M. Scarpiniti Una Introduzione a OpenCV 1 / 53 Introduzione Le Strutture Dati 1 Introduzione Introduzione I primi passi 2 Le Strutture Dati Gestione delle matrici L’Istogramma M. Scarpiniti Una Introduzione a OpenCV 2 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Introduzione Introduzione M. Scarpiniti Una Introduzione a OpenCV 3 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Introduzione L’obiettivo di queste slides è di introdurre ed illustrare il funzionamento di un utile e potente framework per la gestione dei dispositivi video, noto come OpenCV. OpenCV è una libreria open-source, scritta in C, per lo streaming video real-time ovvero la computer vision e gira sotto Windows, Linux e Mac OS X. Maggiori informazioni possono essere reperite al link http://opencv.willowg com/wiki/ da cui è anche possibile scaricare l’intero codice in C++. M. Scarpiniti Una Introduzione a OpenCV 4 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Introduzione: la computer vision La computer vision è una trasformazione dei dati provenienti da una fotocamera o videocamera verso una decisione o una loro nuova rappresentazione. Una tale trasformazione può essere effettuata per uno scopo qualsiasi. E’ anche possibile inserire nei dati, alcune informazioni riguardanti il contesto in cui si opera. M. Scarpiniti Una Introduzione a OpenCV 5 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Introduzione: storia di OpenCV Il framework OpenCV nasce da una iniziativa dell’Intel, mentre lavorava su miglioramenti delle loro CPU per applicazioni intensive, ad esempio raytracing in tempo reale e proiezione 3D. Uno degli addetti della Intel, aveva notato che in motle Università, tra cui il MIT Media Lab, avevano messo su un’infrastruttura per la computer vision, il cui codice era passato da studente a studente. A tal proposito si decise di iniziare a progettare, a partire da questo codice, un framework per la computer vision per i processori Intel. Il primo avvio di tale progetto, con la collaborazione di un team Intel russo, fu nel 1999. La prima release ufficiale di OpenCV risale, invece, al 2006. Nel 2011 è stata rilasciata la versione 2.2.0, che supporta anche Android. Ora è disponibile la release 3.0. M. Scarpiniti Una Introduzione a OpenCV 6 / 53 Introduzione Le Strutture Dati Introduzione I primi passi OpenCV e le IPP Per velocizzare OpenCV è possibile utilizzare la libreria IPP (Intel Performance Primitives). Infatti OpenCV è basato, internamente, su tali librerie in quanto molti programmatori Intel ne fanno un forte uso. Le IPP sono delle librerie altamente ottimizzate, che agiscono direttamente a livello delle micro-istruzioni del processore, evitando qualsiasi perdita di tempo. Se le IPP sono installate, OpenCV le rileverà in automatico e le includerà al momento della compilazione, per ottimizzare al massimo il codice. Cosı̀ se, ad esempio è richiesto il calcolo di una FFT, verrà utilizzata la funzione definita nelle IPP anzichè quella nativa di OpenCV. Per verificare se le IPP sono installate e determinare la release di OpenCV in uso, si può utilizzare il seguente codice char * libraries ; char * modules ; c vG et M od ul eI n fo (0 , & libraries , & modules ) ; printf ( " Libraries : % s / nModules : % s / n " , libraries , modules ) ; M. Scarpiniti Una Introduzione a OpenCV 7 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Installare OpenCV Dopo aver scaricato e configurato (ad esempio attraverso l’utilizzo del software CMake (http://www.cmake.org/)) OpenCV è possibile aprire con Microsoft Visual C++ il relativo file di soluzione e compilare il tutto. Il risultato della compilazione è una serie di librerie, che dovranno essere incluse nel codice che verrà scritto. Le relative librerie dinamiche *.dll, andranno distribuite insieme al programma compilato. Nella cartella bin verranno compilati, inoltre, i numerosi esempi inclusi nel framework, attraverso i quali è possibile scrivere facilmente un elevato numero di applicazioni. Nella cartella docs è invece possibile consultare un’abbondante documentazione in formato html oppure in formato pdf. E’ anche reperibile una documentazione Wiki, all’indirizzo http://opencvlibrary.SourceForge. net. M. Scarpiniti Una Introduzione a OpenCV 8 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Struttura di OpenCV La struttura di OpenCV consta delle seguenti 6 parti: 1 CXCORE: contiene la definizione di tutte le strutture dati e le funzioni per gestire immagini e video. 2 CV: contiene tutte le funzioni per l’elaborazione e l’analisi delle immagini, la calibrazione e il tracking. 3 ML (Machine Learning): contiene molte funzioni sul Machine Learning e il pattern recognition, quali il clustering e la classificazione. 4 HighGUI: contiene le definizioni delle interfacce utenti (GUI). 5 CVCAM: contiene le interfacce per le webcam. 6 CVAUX: contiene algoritmi sperimentali per scopi diversi, ad esempio: segmentazione, sottrazione del background, modelli HMM, ecc. M. Scarpiniti Una Introduzione a OpenCV 9 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Struttura di OpenCV La struttura di OpenCV precedente può essere riassunta nella schematizzazione seguente. CV MLL CXCORE HighGUI CVCAM CVAUX M. Scarpiniti Una Introduzione a OpenCV 10 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Aprire una foto con OpenCV Per aprire una foto, è possibile utilizzare il seguente codice: # include " highgui . h " int main ( int argc , char ** argv ) { IplImage * img = cvLoadImage ( argv [1]) ; cvNamedWindow ( " Esempio1 " , C V _ W I N D O W _ A U T O S I Z E ) ; cvShowImage ( " Esempio1 " , img ) ; cvWaitKey (0) ; cvRe leaseIma ge (& img ) ; c vD es tr o yW in do w ( " Esempio1 " ) ; } Tutte le funzioni utilizzate in questo script, sono definite nel file di header highgui.h. M. Scarpiniti Una Introduzione a OpenCV 11 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Aprire una foto con OpenCV La funzione chiave del precedente script è IplImage * img = cvLoadImage ( " nome " ) ; che legge una stringa e carica in una matrice img, di tipo IplImage, tutti i pixel dell’immagine. Tale funzione determina in automatico il tipo di file e alloca la memoria necessaria per contenere l’immagine (numero di righe, di colonne e di colori). I formati supportati sono: BMP, DIB, JPEG, JPE, PNG, PBM, PGM, PPM, SR, RAS e TIFF. Tale funzione restituisce il puntatore alla struttura allocata, che contiene, oltre ai dati, anche le informazioni relative dell’immagine. M. Scarpiniti Una Introduzione a OpenCV 12 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Aprire una foto con OpenCV Per visualizzare la foto è necessario creare una finestra in cui collocarla. A tal proposito, si utilizza la funzione cvNamedWindow ( " Esempio1 " , C V _ W I N D O W _ A U T O S I Z E ) ; che crea la finestra e la nomina come ‘‘Esempio1’’. Il secondo argomento (CV WINDOW AUTOSIZE) determina le dimensioni della figura. In questo caso, la finestra sarà adattata alle dimensioni dell’immagini. Al contrario è possibile inserire il valore 0: in questo caso la finestra ha una dimensione standard e l’immagine sarà scalata alle dimensioni della finestra. Per visualizzara l’immagine img nella finestra ‘‘Esempio1’’, si utilizza quindi, la funzione cvShowImage ( " Esempio1 " , img ) ; Ovviamente la finestra ‘‘Esempio1’’ deve essere create precedentemente la chiamata di cvShowImage(). M. Scarpiniti Una Introduzione a OpenCV 13 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Aprire una foto con OpenCV Per mettere in attesa il programma fino a che non si prema un tasto, si utilizza il comando cvWaitKey (0) ; L’argomento 0 (o un numero negativo) significa che si aspetta la pressione di un tasto. Al contrario, se si inserisce un numero positivo, il programma aspetta, in millisecondi, il tempo indicato. Quando viene premuto il tasto, bisogna rilasciare la memoria occupata e porre il puntatore all’immagine img a NULL. Queste operazioni sono eseguite dal comando cvRe leaseIma ge (& img ) ; Infine bisogna distruggere la finestra creata, e deallocare la memoria eventualmente occupata, utilizzando c vD es tr o yW in do w ( " Esempio1 " ) ; M. Scarpiniti Una Introduzione a OpenCV 14 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Creare e salvare una foto con OpenCV Per creare uno spazio di memoria che contenga un’immagine, è possibile utilizzare il comando seguente: IplImage * image = cvCreateImage ( CvSize size , int depth , int channels ) ; Viene restituito un puntatore ad una strutture di tipo IplImage. Viene richiesto, al contrario, la dimensione dell’immagine in size (come larghezza - altezza), in numero di bit (in depth) e il numero di canali per pixel in channels (1, 2, 3, o 4). Per salvare un’immagine, si utilizza invece int cvSaveImage ( char * filename , CvArr * image ) ; che prende in ingresso il nome del file e il puntatore all’immagine da salvare. Restituisce 1 se il salvataggio è andato a buon fine, 0 altrimenti. M. Scarpiniti Una Introduzione a OpenCV 15 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Aprire un video con OpenCV Per aprire un video, è possibile utilizzare il seguente codice: # include " highgui . h " int main ( int argc , char ** argv ) { cvNamedWindow ( " Esempio2 " , C V _ W I N D O W _ A U T O S I Z E ) ; CvCapture * capture = c v C r e a t e F i l e C a p t u r e ( argv [1]) ; IplImage * frame ; while (1) { frame = cvQueryFrame ( capture ) ; if (! frame ) break ; cvShowImage ( " Esempio2 " , frame ) ; char c = cvWaitKey (33) ; if ( c == 27) break ; } c v R e l e a s e C a p t ur e (& capture ) ; c vD es tr o yW in do w ( " Esempio2 " ) ; } M. Scarpiniti Una Introduzione a OpenCV 16 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Aprire un video con OpenCV Anche qui si crea un finestra attraverso la funzione cvNamedWindow(). La funzione principale, quella che carica il file video, è la seguente CvCapture * capture = c v C r e a t e F i l e C a p t u r e ( " nome_video " ) ; Tale funzione carica un file video di tipo AVI e restituisce un puntatore capture a idonea struttura CvCapture. Tale puntatore è quindi passato alla funzione frame = cvQueryFrame ( capture ) ; che restituisce il frame corrente del video in un’immagine, descritta dal puntatore frame alla struttura IplImage. Tale frame è quindi visualizzato come immagine cvShowImage ( " Esempio2 " , frame ) ; M. Scarpiniti Una Introduzione a OpenCV 17 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Aprire un video con OpenCV Ogni 33 ms (cvWaitKey(33)) viene letto un nuovo frame e visualizzato, ripetendo all’infinito il ciclo while(1) char c = cvWait (33) ; Si esce dal ciclo quando viene letto il carattere con codice ASCII pari a 27, ovvero il tasto Esc. Viene quindi rilasciata la memoria attraverso il comando c v R e l e a s e C a p t ur e (& capture ) ; e infine distrutta la finestra con c vD es t ro yW in d ow ( " Esempio2 " ) ; M. Scarpiniti Una Introduzione a OpenCV 18 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Leggere da WebCam con OpenCV Vediamo il codice per ottenere le immagini da una webcam. # include " cv . h " # include " highgui . h " int main ( int argc , char ** argv ) { cvNamedWindow ( " Esempio3 " , C V _ W I N D O W _ A U T O S I Z E ) ; CvCapture * capture ; if ( argc ==1) { capture = c v C r e a t e C a m e r a C a p t u r e ( 0 ) ; } else { capture = c v C r e a t e F i l e C a p t u r e ( argv [1] ) ; } assert ( capture != NULL ) ; IplImage * frame ; M. Scarpiniti Una Introduzione a OpenCV 19 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Leggere da WebCam con OpenCV while (1) { frame = cvQueryFrame ( capture ) ; if ( ! frame ) break ; cvShowImage ( " Esempio3 " , frame ) ; char c = cvWaitKey (10) ; if ( c == 27 ) break ; } c v R e l e a s e C a p t u re (& capture ) ; c vDes tr o yW in do w ( " Esempio3 " ) ; } Dopo aver al solito creato una finestra con cvNamedWindow(), si crea un puntatore capture alla struttura dati CvCapture. Il video da webcam viene creato attraverso la funzione capture = c v C r e a t e C a m e r a C a p t u r e ( 0 ) ; M. Scarpiniti Una Introduzione a OpenCV 20 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Leggere da WebCam con OpenCV Se, al contrario, al programma precedente passo il nome di un file, viene letto il video con quel nome. Il resto del programma è identico al caso del filmato. Ogni 10 ms (cvWaitKey(10)) viene letto un frame dal puntatore capture, con frame = cvQueryFrame ( capture ) ; e quindi mostrato nella finestra cvShowImage ( " Esempio3 " , frame ) ; Infine, quando viene premuto il tasto Esc (codice ASCII 27 ), viene rilasciata la memoria (cvReleaseCapture(&capture)) e distrutta la finestra (cvDestroyWindow(‘‘Esempio3’’)). M. Scarpiniti Una Introduzione a OpenCV 21 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Scrivere un file video con OpenCV Nella presente slide, si cercherà di descrivere un codice per la scrittura su file AVI. # include " cv . h " # include " highgui . h " # include < stdio .h > int main ( int argc , char * argv [] ) { cvNamedWindow ( " Esempio4 " , C V _ W I N D O W _ A U T O SI Z E ) ; cvNamedWindow ( " Log_Polar " , C V _ W I N D O W _ A U T O S I Z E ) ; CvCapture * capture = c v C r e a t e F i l e C a p t u r e ( argv [1] ) ; if (! capture ) { return -1; } IplImage * bgr_frame = cvQueryFrame ( capture ) ; double fps = c v G e t C a p t u r e P r o p e r t y ( capture , C V _C AP _P R OP _F PS ) ; CvSize size = cvSize ( ( int ) c v G e t C a p t u r e P r o p e r t y ( capture , CV_CAP_PROP_FRAME_WIDTH ), ( int ) c v G e t C a p t u r e P r o p e r t y ( capture , CV_CAP_PROP_FRAME_HEIGHT ) ); M. Scarpiniti Una Introduzione a OpenCV 22 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Scrivere un file video con OpenCV CvVideoWriter * writer = c v C r e a t e V i d e o W r i t e r ( argv [2] , CV_FOURCC ( ’D ’ , ’X ’ , ’V ’ , ’0 ’) , fps , size ) ; IplImage * log polar_fr ame = cvCreateImage ( size , IPL_DEPTH_8U , 3 ); while ( ( bgr_frame = cvQueryFrame ( capture ) ) != NULL ) { cvShowImage ( " Esempio4 " , bgr_frame ) ; cvLogPolar ( bgr_frame , logpolar_frame , cvPoint2D32f ( bgr_frame - > width /2 , bgr_frame - > height /2) , 40 , C V_ IN TE R _L IN EA R + C V _ W A R P _ F I L L _ O U T L I E R S ) ; cvShowImage ( " Log_Polar " , l ogpolar _frame ) ; M. Scarpiniti Una Introduzione a OpenCV 23 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Scrivere un file video con OpenCV cvWriteToAVI ( writer , lo gpolar_ frame ) ; char c = cvWaitKey (10) ; if ( c == 27 ) break ; } c v R e l e a s e V i d e o W r i t e r ( & writer ) ; cvRe leaseIma ge ( & bgr_frame ) ; cvRe leaseIma ge ( & logp olar_fra me ) ; c v R e l e a s e C a p t u re ( & capture ) ; c vDes tr o yW in do w ( " Esempio4 " ) ; c vDes tr o yW in do w ( " Log_Polar " ) ; Il codice precedente carica e visualizza (nella finestra ‘‘Esempio4’’) un video letto da file AVI. Contemporaneamente questo video verrà convertito in un formato logaritmico-polare, visualizzato nella finestra ‘‘Log Polar’’ e scritto su file, sempre di tipo AVI. M. Scarpiniti Una Introduzione a OpenCV 24 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Scrivere un file video con OpenCV La funzione chiave del programma precedente è la seguente CvVideoWriter * writer = c v C r e a t e V i d e o W r i t e r ( argv [2] , CV_FOURCC ( ’D ’ , ’X ’ , ’V ’ , ’0 ’) , fps , size ) ; che restituisce un puntatore writer alla struttura CvVideoWriter. Tale funzione accetta 4 parametri in ingresso: 1 il nome del file da scrivere (letto da linea di comando) argv[2]; 2 il codec video con cui sarà compresso lo stream CV FOURCC(); 3 il numero di frames per secondo fps; 4 la dimensionalità delle immagini (3 = a colori) size. M. Scarpiniti Una Introduzione a OpenCV 25 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Scrivere un file video con OpenCV: i codec OpenCV supporta i seguenti tipi di codec video: Codici Descrizione CV FOURCC(’P’,’I’,’M’,’1’) MPEG-1 codec motion-jpeg codec CV FOURCC(’M’,’J’,’P’,’G’) CV FOURCC(’M’, ’P’, ’4’, ’2’) MPEG-4.2 codec CV FOURCC(’D’, ’I’, ’V’, ’3’) MPEG-4.3 codec CV FOURCC(’D’, ’I’, ’V’, ’X’) MPEG-4 codec (Dvix) CV FOURCC(’D’, ’X’, ’V’, ’0’) DVix vers 5 codec CV FOURCC(’X’, ’V’, ’I’, ’D’) Xvid codec CV FOURCC(’U’, ’2’, ’6’, ’3’) H263 codec CV FOURCC(’I’, ’2’, ’6’, ’3’) H263I codec CV FOURCC(’H’, ’2’, ’6’, ’4’) H264 codec CV FOURCC(’F’, ’L’, ’V’, ’1’) FLV1 codec M. Scarpiniti Una Introduzione a OpenCV 26 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Scrivere un file video con OpenCV La trasformazione logaritmico-polare dell’immagine avviene attraverso il comando: cvLogPolar ( bgr_frame , logpolar_frame , cvPoint2D32f ( bgr_frame - > width /2 , bgr_frame - > height /2) , 40 , C V_ IN TE R _L IN EA R + C V _ W A R P _ F I L L _ O U T L I E R S ) ; I primi due argomenti (bgr frame e logpolar frame) sono le immagini di origine e destinazione della trasformazione logaritmico-polare, descritta dalle seguenti trasformazioni: (x, y ) → (log r , θ), p −yc in cui r = (x − xc )2 + (y − yc )2 e θ = arctan yx−x e (xc , yc ) è il punto centrale c dell’immagine di partenza. Le coordinate di tale punto vengono passate alla precedente funzione come terzo parametro. Il quarto parametro è un fattore di scala che seleziona la regione di interesse nella visualizzazione del nuovo dominio. Infine il quinto parametro seleziona il metodi di interpolazione utilizzato. M. Scarpiniti Una Introduzione a OpenCV 27 / 53 Introduzione Le Strutture Dati Introduzione I primi passi Scrivere un file video con OpenCV A questo punto il frame appena trasformato viene salvato nella struttura puntata da writer, attraverso cvWriteToAVI ( writer , l ogpolar_ frame ) ; Dopo la scrittura di tutti i frame, viene distrutto il puntatore alla struttura video, tramite c v R e l e a s e V i d e o W r i t e r (& writer ) ; Infine viene rilasciata la memoria e distrutte le finestre: cvRe leaseIma ge ( & bgr_frame ) ; cvRe leaseIma ge ( & logpo lar_fra me ) ; c v R e l e a s e C a p t ur e ( & capture ) ; c vD es tr o yW in do w ( " Esempio4 " ) ; c vD es tr o yW in do w ( " Log_Polar " ) ; M. Scarpiniti Una Introduzione a OpenCV 28 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Le Strutture Dati Le Strutture Dati M. Scarpiniti Una Introduzione a OpenCV 29 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma I tipi elementari OpenCV utilizza le matrici per memorizzare immagini e frame. All’interno di tali strutture troviamo i tipi elementari di punto, dimensione, rettangolo, che vengono definiti come descritto nella seguente tabella. Struttura CvPoint CvPoint2D32f CvPoint3D32f CvSize CvRect CvScalar Contenuto int x, y float x, y flaot x, y, z int width, height int x, y, width, height double val[4] Descrizione Punto in un’immagine Punto in R2 Punto in R3 Dimensioni di un’immagine Porzione di un’immagine Valore RGBA Cosı̀ se si vuole disegnare un rettangolo (cvRectangle()) nell’immagine puntata da myImg, si utilizzerà la chiamata cvRectangle ( myImg , cvPoint (5 ,10) , cvPoint (20 ,30) , cvScalar (255 ,255 ,255) ) ; M. Scarpiniti Una Introduzione a OpenCV 30 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma La struttura CvMat La struttura fondamentale è la CvMat, che può essere definita come typedef struct CvMat { int type ; int step ; int * refcount ; // per uso interno union { uchar * ptr ; short * s ; int * i ; float * fl ; double * db ; } data ; union { int rows ; int height ; }; union { int cols ; int width ; }; } CvMat ; M. Scarpiniti Una Introduzione a OpenCV 31 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma La struttura CvMat Per creare un elemento di tipo CvMat è possibile eseguire il comando: cvMat * cvCreateMat ( int rows , int cols , int type ) ; E’ comunque possibile creare solamente l’header o i dati di una struttura CvMat: c v C r e a t e M a t H e a d e r ( int rows , int cols , int type ) ; cvCreateData ( int rows , int cols , int type ) ; o clonare una matrice mat2 = cvCloneMat ( CvMat * mat1 ) ; Infine, per deallocare la memoria, si utilizza cvReleaseMat ( CvMat ** mat ) ; M. Scarpiniti Una Introduzione a OpenCV 32 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma La struttura IplImage La struttura dati fondamentale per gestire le immagini è la IplImage, definita come segue: typedef struct _IplImage { int nSize ; int ID ; int nChannels ; int alphaChannel ; int depth ; char colorModel [4]; char channelSeq [4]; int dataOrder ; int origin ; int align ; int width ; int height ; struct _IplROI * roi ; struct _IplImage * maskROI ; void * imageId ; struct _IplTileInfo * tileInfo ; int imageSize ; char * imageData ; int widthStep ; int BorderMode [4]; int BorderConst [4]; char * imageDataOrigin ; } IplImage ; M. Scarpiniti Una Introduzione a OpenCV 33 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma La struttura IplImage Il valore del numero di bit, descritti dalla variabile depth, può assumere una delle seguenti alternative Macro Tipo di pixel IPL DEPTH 8U intero unsigned a 8 bit IPL DEPTH 8S intero signed a 8 bit IPL DEPTH 16S intero signed a 16 bit IPL DEPTH 32S intero signed a 32 bit IPL DEPTH 32F float singola precisione a 32 bit IPL DEPTH 64F float doppia precisione a 64 bit M. Scarpiniti Una Introduzione a OpenCV 34 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Operazioni sulle immagini Sulle immagini, che sono rappresentate da matrici in OpenCV è possibile utilizzare un insieme di oltre cento funzioni predefinite, che permettono di sommare, sottrare, ruotare, determinare quantità statistiche, norme, ecc. L’utilizzo di tali funzioni è abbastanza immediato. Per maggiori informazioni a riguardo, si rimanda alla guida di OpenCV, nonché a [1] e [2]. Vengono poi messe a disposizione alcune funzioni per disegnare figure più o meno elementari su una determinata finestra contenete un’immagine. Ad esempio: linee, cerchi, ellissi, poligoni e testo. Anche queste funzioni sono di utilizzo abbastanza immediato. Nel seguito vedremo alcune funzioni molto utili nelle applicazioni. M. Scarpiniti Una Introduzione a OpenCV 35 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Operazioni sulle immagini: il resize E’ possibile operare un’operazione di resize su una determinata immagine, attraverso la funzione void cvResize ( const CvArr * src , cvArr * dst , int interpolation = CV _I N TE R_ LI N EA R ); Nella precedente funzione src è l’immagine originaria mentre dst è la nuova struttura di dimensioni opportune che conterrà l’immagine con le nuove dimensioni. Poiché i pixel dell’immagine originale dovranno essere interpolati, è possibile stabilire il metodo di interpolazione attraverso il terzo parametro interpolation, le cui opzioni sono descritte nella seguente tabella: Interpolazione CV INTER NN CV INTER LINEAR CV INTER AREA CV INTER CUBIC M. Scarpiniti Metodo Pixel più vicino Bilineare Media su un’area Bicubica Una Introduzione a OpenCV Descrizione Il nuovo pixel assume il valore del pixel più vicino Interpolazione bilineare Il pixel è sostituito con la media dell’area coperta dai v Interpolazione bicubica 36 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Operazioni sulle immagini: la convoluzione Essenziale per il filtraggio di immagini è l’operazione di convoluzione bidimensionale, ottenuta attraverso la funzione void cvFilter2D ( const CvArr * src , cvArr * dst , const CvMat * kernel , cvPoint anchor = cvPoint ( -1 , -1) ); Nella precedente funzione src è l’immagine originaria mentre dst è la nuova struttura di dimensioni opportune che conterrà l’immagine filtrata. kernal è una matrice contenente la risposta impulsiva del filtro. Il quarto parametro, anchor, è opzionale è indica il punto in cui centrare il filtro bidimensionale. L’opzione di default è il centro della matrice kernel. M. Scarpiniti Una Introduzione a OpenCV 37 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Operazioni sulle immagini: la DFT E’ possibile valuare la DFT bidimensionale I (kx , ky ) = NX y −1 x −1 N X nx =0 ny 2πj 2πj I (nx , ny ) exp − kx nx exp − ky ny , Nx Ny =0 attraverso la funzione void cvDFT ( const CvArr * cvArr * int int ); src , dst , flags nonzero_rows = 0 Nella precedente funzione src è l’immagine originaria mentre dst è la nuova struttura di dimensioni opportune che conterrà l’immagine in frequenza. flags è un parametro che seleziona la trasformata diretta (CV DXT FORWARD) e inversa (CV DXT INVERSE). L’ultimo parametro, nonzero rows, serve per gestire lo zero padding. Utilizzando la precedente funzione è possibile implementare la convoluzione tra due immagine come prodotto delle relative DFT. M. Scarpiniti Una Introduzione a OpenCV 38 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma L’istogramma di un’immagine Poiché moltissimi algoritmi di image processing si basano sul concetto di istogramma, diviene essenziale saper lavorare con questi ultimi in OpenCV. La struttura che contiene l’istogramma è definita come segue typedef struct CvHistogram { int type ; CvArr * bins ; float thresh [ CV_MAX_DIM ][2]; // for uniform histograms float ** thresh2 ; // for nonuniform histograms CvMatND mat ; // embedded matrix for array histograms } CvHistogram ; Nella precedente struttura, type indica il tipo di istogramma, ovvero se mono-dimensionale o multi-dimensionale; bins contiene i bin dell’istogramma. Le matrici thresh e thresh2 sono le soglie utilizzate per creare l’istogramma, nel caso uniforme e non uniforme, rispettivamente. Infine, mat contiene i valori dell’istogramma. M. Scarpiniti Una Introduzione a OpenCV 39 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma L’istogramma di un’immagine Dopo aver definita la struttura CvHistogram è possibile creare un istogramma attraverso CvHistogram * cvCreateHist ( int dims , int * sizes , int type , float ** ranges = NULL , int uniform = 1 ); Nella precedente funzione, dims indica il numero di dimensioni dell’istogramma. sizes è un vettore di interi lungo quanto il numero di dimensioni, che indicano il numero di bin da assegnare a ciascuna dimensione. type indica il tipo di istogramma, ovvero se multidimensionale (CV HIST ARRAY) o di tipo sparso (CV HIST SPARSE). La variabile ranges denota i limiti dell’istogramma, mentre la variabile booleana uniform indica se stiamo utilizzando un istogramma uniforme (valore positivo) oppure no (valore 0). M. Scarpiniti Una Introduzione a OpenCV 40 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Manipolare un istogramma Esistono alcune utili funzioni che consentono di manipolare un istogramma, precedentemente creato. Precisamente cvNormalizeHist( CvHistogram* hist, double factor ); che consente di normalizzare un istogramma di un fattore factor; cvThreshHist( CvHistogram* hist, double thresh ); che consente di applicare una soglia thresh; void cvCopyHist( const CvHistogram* src, CvHistogram** dst ); permette di copiare un istogramma contenuto in src nella nuova variabile dst. void c v G e t M i n M a x H i s t V a l u e ( const CvHistogram * hist , float * min_value , float * max_value , int * min_idx = NULL , int * max_idx = NULL ) ; consente di ottenere il valore minimo min value e il valore massimo max value di un istogramma hist. Le variabili min idx e max idx servono nel caso di istogrammi multi-dimensionali. M. Scarpiniti Una Introduzione a OpenCV 41 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Manipolare un istogramma E ancora: void cvCalcHist ( IplImage ** CvHistogram * int const CvArr * image , hist , accumulate = 0 , mask = NULL ) ; consente di calcolare automaticamente l’istogramma hist di una immagine image. Il parametro accumulate, se non zero, consente di mantenere in memoria l’istogramma. mask consente di escludere alcuni pixel dal calcolo dell’istogramma. void cvEqual izeHist ( const CvArr * src , CvArr * dst ) ; consente di equalizzare un’immagine migliorandone il contrasto, in modo tale che l’immagine risultante dst abbia un istogramma più piatto dell’immagine di partenza src. M. Scarpiniti Una Introduzione a OpenCV 42 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Manipolare un istogramma Infine, è fondamentale la seguente funzione void cvCompareHist ( const CvHistogram * hist1 , const CvHistogram * hist2 , int method ); che consente di paragonare due istogrammi. La variabile method descrive la particolare distanza utilizzata per paragonare i due istogrammi. I possibili valori sono riassunti nella seguente tabella Metodo Descrizione Espressione CV COMP CORREL Correlazione dcorr (H1 , H2 ) = P CV COMP CHISQR CV COMP INTERSECT Chi-Quadro Intersezione CV COMP BHATTACHARYYA Battacharria qPi (H1 (i)−mH1 )(H2 (i)−mH2 ) i (H1 (i)−mH1 ) 2 (H (i)−m )2 2 H2 P (H (i)−H (i))2 dchi (H1 , H2 ) = i H1 (i)+H2 (i) 1 2 P dint (H1 , H2 ) = r 2 (i)) i min (H1 (i), H√ P H (i)H (i) dBhatt (H1 , H2 ) = 1 − i √P 1 P2 i M. Scarpiniti Una Introduzione a OpenCV H1 (i)· i H2 (i) 43 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Back Projection Con Back Projection si intende una tecnica con la quale si cerca di capire quanto alcuni pixel di un’immagine o alcune aree di un’immagine abbiano un istogramma simile ad un istogramma di riferimento. Il primo scopo è raggiunto attraverso la funzione void c v C a l c B a c k P r o j e c t ( IplImage ** image , CvArr * back_project , const CvHistogram * hist ); in cui image è l’immagine da analizzare, back project contiene i valori dell’istogramma dell’immagine image e hist contiene l’istogramma di riferimento. M. Scarpiniti Una Introduzione a OpenCV 44 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Back Projection Nel secondo caso, siamo interessati ad una regione di pixel, che magari appartengono ad un oggetto noto. Infatti, applicando una finestra mobile ad una data immagine, è possibile determinare in quali posizione l’istogramma della finestra è simile a quello di riferimento: in questi casi, infatti, è altamente possibile che la regione di analisi appartiene all’oggetto cercato. Tale funzione è definita come segue: void c v C a l c B a c k P r o j e c t P a t c h ( IplImage ** image , CvArr * dst , CvSize patch_size , CvHistogram * hist , int method , float factor ); in cui image è l’immagine da analizzare, dst conterrà l’istogramma valutato, patch size è l’ampiezza della finestra mobile, hist è l’istogramma di riferimento, method è il metodo con cui è valutata la distanza tra i due istogramma e, infine, factor è il fattore di normalizzazione. M. Scarpiniti Una Introduzione a OpenCV 45 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Template Matching Una tecnica simile alla Back Projection, ma non basata sull’istogramma, è il Template Matching. Essa è basata sul far scorrere una piccola immagine target su un’altra immagine da analizzare, al fine di capire se il target sia contenuta o meno nell’immagine data. La funzione che implementa tale operazione è void c vM at ch T em pl at e ( const CvArr * image , const CvArr * templ , CvArr * result , int method ); in cui image è l’immagine da analizzare, templ è l’immagine target, result è l’immagine risultato e method rappresenta l’algoritmo di calcolo dell’immagine risultante, elencato nella seguente tabella (con relativa versione normalizzata). Metodo CV TM SQDIFF CV TM CCORR CV TM CCOEFF M. Scarpiniti Descrizione Metodo della differenza quadratica Metodo della correlazione Metodo del coefficiente di correlazione Una Introduzione a OpenCV Metodo CV TM CV TM CV TM Normalizzato SQDIFF NORMED CCORR NORMED CCOEFF NORMED 46 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma La calibrazione Un passo fondamentale affinché il tutto funzioni correttamente, nel caso di utilizzo una web-camera, è la procedura di calibrazione. In pratica la calibrazione è effettuata identificando prima i bordi di una scacchiera che viene mostrata alla camera e quindi invocando una funzione per la calibrazione. M. Scarpiniti Una Introduzione a OpenCV 47 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma La calibrazione Le due funzioni precedenti sono, rispettivamente: int c v F i n d C h e s s b o a r d C o r n e r s ( const void * image , CvSize pattern_size , CvPoint2D32f * corners , int * corner_count = NULL , int flags = CV_CALIB_CB_ADAPTIVE_THRESH ); void c v C a l i b r a t i o n C a m e r a 2 ( CvMat * object_points , CvMat * image_points , int * point_counts , CvSize image_size , CvMat * intrinsic_matrix , CvMat * distorsion_coeffs , CvMat * r o t a t i o n _ v e c t o r s = NULL , CvMat * t r a n s l a t i o n _ v e c t o r s = NULL , int flags = 0 ); Si rimanda a [1] per il significato di tutti i parametri. M. Scarpiniti Una Introduzione a OpenCV 48 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Il Machine Learning OpenCV mette a disposizione una libreria per il Machine Learning , in cui sono contenuti molti algoritmi utili nelle applicazioni. Di seguito sono elencati gli algoritmi messi a disposizione: Mahalanobis; Haar Classifier; K-means; Face detector; Bayes Classifier; Expectation Maximization (EM); Binary decision trees; K-nearest neighbors; Boosting; Multilayer Perceptron (MLP); Random trees; Support Vector Machines (SVM). Di seguito esamineremo in dettaglio un paio di algoritmi significativi. M. Scarpiniti Una Introduzione a OpenCV 49 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Il K-means L’algoritmo K-means si applica attraverso la seguente funzione void cvKMeans2 ( const CvArr * int CvArr * CvTe rmCriter ia ); samples , cluster_count , labels , termcrit in cui samples è un array multidimensionale su cui applicare il K-means, cluster count è il numero di cluster, labels è un array contenete l’indice del cluster relativo e termcrit è il criterio di stop utilizzato. M. Scarpiniti Una Introduzione a OpenCV 50 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Il Face Detector OpenCV mette a disposizione un potente algoritmo di face detection, basato su un classificatore di Haar e proposto da Viola & Jones. Tutte le caratteristiche sono state precedentemente apprese e salvate in un file distribuito con OpenCV. La funzione per invocare il face detector è la seguente CvSeq∗ c v H a a r D e t e c t O b j e c t s ( c o n s t CvArr∗ CvHaarClassifierCascade∗ CvMemstorage∗ double int int CvSize ); image , cascade , storage , scale factor min neighbors flags min size = = = = 1.1 , 3, 0, cvSize (0 ,0) in cui image è l’immagine a scala di grigi i cui cercare le facce, cascade contiene le caratteristiche del classificatore, storage è un buffur utilizzato dall’algoritmo, scale factor è un fattore di scale che indica quanto elevato è il salto tra una scala e la successiva, min neighbors indica il numero di detection contemporanee affinché venga stabilito che effettivamente ci sia una faccia. flags permette di eliminare alcune ragioni dell’immagine dalla ricerca e, infine, min size indica la dimensione più piccola in cui effettuare la ricerca. M. Scarpiniti Una Introduzione a OpenCV 51 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Il Face Detector A questo punto è possibile disegnare un rettangolo o un cerchio intorno alla faccia o alle facce individuate dalla funzione cvHaarDetectObjects(), per avere una rappresentazione grafica intuitiva del numero effettivo di facce individuate. M. Scarpiniti Una Introduzione a OpenCV 52 / 53 Introduzione Le Strutture Dati Gestione delle matrici L’Istogramma Bibliografia G. Bradski, A. Kaehler. Learnin OpenCV: Computer Vision with the OpenCV Library. O’Reilly, 2008. R. Laganière. OpenCV 2 Computer Vision - Application Programming Cookbook. PACKT Publishing,2011. H. Schildt. La Guida completa C. McGraw Hill, 2003. P. Viola and M. J. Jones. Rapid Object Detecting Using a Boosted cascade of Simple Features. IEEE CVPR, 2001. P. Viola and M. J. Jones. Robust Real-time Face Detection. International journal of Computer Vision, Vol. 57, pp. 137–154, 2004. M. Scarpiniti Una Introduzione a OpenCV 53 / 53