Bones gent!
Aquesta entrada la dedicaré a fer un petit tutorial d’iniciació a la llibreria OpenCV per a C. Aquesta llibreria desenvolupada per Intel es completament lliure i està encarada al tractament d’imatges, de fet el seu nom complet és Open Computer Vision Library (Llibreria Oberta de Visió per Ordinador) i és realment potent i optimitzada.
Però no us penseu que aquesta llibreria tan sols ens ofereix eines per voltar imatges, canviar els colors o retallar-les, sinó que a més, ofereix capçaleres per control de xarxes neuronals i altres algoritmes per a la detecció d’objectes, moviments, cares… I si recordem que un vídeo no es més que una successió d’imatges, la llibreria OpenCV també permet el tractament de dades de vídeo podent modificar cadascun dels píxels de cada fotograma. Increíble!
Realment, el potencial d’OpenCV radica en la seva senzilla aplicació per a la intel·ligència artificial i el reconeixement de patrons, però com això encara es una mica lluny per als nouvinguts he decidit començar amb un simple reproductor de vídeo o webcam amb llenguatge C, on podrem veure fàcilment com rescatar imatges, fer alguna petita transformació i mostrar-les per pantalla a una velocitat adequada. Tot això amb dos úniques llibreries, OpenCV i la estàndard de C de entrada/sortida.
Abans de començar, recordo però que aquest tutorial no et servirà per aprendre C, sinò com a iniciació a OpenCV, i per tant necessitaràs tenir abans uns coneixements intermitjos del llenguatge. Jo vaig començar aprenent C amb “Aprenda ANSI C como si estuviera en primero“. Si encara no estàs iniciat en el món de la programació es bo començar amb llenguatges senzills i interpretats com és Python, amb molta documentació i realment potent.

Be doncs, amb aquesta preliminar introducció comencem amb el tutorial:
Instal·lació de la llibreria OpenCV
OpenCV s’ofereix tant per a sistemes tipus Unix (GNU/Linux i MacOS) com per a Microsoft Windows. En aquest tutorial s’explicarà amb més detall l’instal·lació sota GNU/Linux doncs és el S.O. que utilitzo i amb el que em trobo familiaritzat.
Per a aquells que utilitzen en les seves distribucions GNU/Linux sistemes de paquets i repositoris com .deb o .rpm i apt-get o yum la instal·lació es pot realitzar fàcilment ja sigui des de la línia de comandes o amb un entorn gràfic. Els paquets necessaris son: libcv-dev i libhighgui-dev
En un sistema deb com Ubuntu la instal·lació es pot realitzar executant la següent comanda a la terminal: sudo apt-get install libhighgui-dev
Ja que libhighgui-dev depèn de libcv-dev
El programa d’exemple ha estat desenvolupat amb la versió 2.0.0. que es troba als repositoris oficials d’Ubuntu 10.4, la més recent en aquesta data és la 2.1.0. Si es vol realitzar el tutorial amb aquesta versió es poden seguir les instruccions d’instal·lació de http://opencv.willowgarage.com/wiki/InstallGuide. Us demanarà resoldre algunes dependències com gtk, libjpeg, ffmpeg… Recomano que seguiu la instal·lació descrita en aquest tutorial si us voleu estalviar cert temps, mal de caps i possibles incompatibilitats després.
Per als usuaris de Microsoft Windows, crec, no ho sé a ciència certa, amb l’instalador potser en teniu prou. Si no és així, per favor referiu-vos a les instruccions d’instal·lació oficials. Per a MacOS seguiu les instruccions: http://opencv.willowgarage.com/wiki/Mac_OS_X_OpenCV_Port
Descàrrega del programa d’exemple
Us deixo dos enllaços als arxius comprimits (tar.gz i zip) amb el codi d’exemple que utilitzarem en aquest tutorial:
- reproductorcv.tar.gz (Mediafire)
- reproductorcv.zip (Mediafire)
Veureu que dintre d’aquests arxius hi ha quatre fitxers:
- Llicència GPL, sentiu-vos lliures de modificar i compartir el programa (gpl-3.0.txt)
- Codi font del programa, el que realment interessa (reproductor.c)
- Executable del programa, i686 32 bits (reproductor)
- Makefile per a la compilació en entorns Unix (Makefile)
Començaré detallant el codi font del reproductor i posteriorment passaré a explicar com compilar i executar l’aplicació.
El codi font
El fitxer reproductor.c comença amb una breu descripció del programa i els termes legals de la llicència GPL v.3, això no té més transcendència, anem al que realment importa.
Capçaleres
Les capçaleres necessàries per realitzar les tasques del reproductor són bàsicament <cv.h> i <highgui.h>. La <stdio.h> està inclosa per poder mostrar un missatge d’error en cas de fallada, però no és una capçalera transcendental. A continuació faré una breu descripció de les capçaleres importants:
<cv.h> Inclou tots els tipus de dades i funcions per al tractament d’imatges, pràcticament tot el potencial d’OpenCV radica en aquesta llibreria i això la converteix en la més important. Tot el que et puguis imaginar que pots fer a una fotografia es realitza amb funcions incloses en aquesta capçalera: retallar, voltar, contrastar, combinar, generar, formatar, colorejar…
<highgui.h> Aquesta està orientada a propiciar d’una manera fàcil i ràpida finestres per a la visualització d’imatges generades amb <cv.h> i l’obtenció i salvació d’imatges i vídeos. L’estil de les finestres s’adapta al predeterminat del sistema on corre el programa, per exemple, en gnome serà de tipus gtk, en KDE serà Qt i en MacOS Cocoa. A més, inclou altres funcions útils com la manipulació de temps d’espera i detecció d’events de ratolí i teclat com veure’m.
Bé, anem a la festa de casa int main(int argc, char* argv[]), quin nom més extrany…
Variables
El primer que em de fer és declarar les variables que necessitarem durant l’execució del programa, importants per al funcionament bàsicament en son tres:
IplImage *frame: Aquesta inicialitza un punter a una estructura de dades IplImage, és la forma bàsica d’OpenCV de representar qualsevol tipus d’imatge, ja sigui RGB, escala de grisos, blanc i negre… En aquest cas, “frame” serà un fotograma del vídeo o de la Webcam, el fotograma actual, i serà el que es mostrarà per pantalla, després s’actualitzarà i es mostrarà el següent, d’aquesta forma obtindrem la seqüència de fotogrames que necessitem.
CvCapture *video: Aquesta inicialitza un punter a una estructura de dades CvCapture, és la forma bàsica d’OpenCV d’obtenir i rescatar dades d’un vídeo, ja pot ser un arxiu local com un vídeo provinent de la Webcam, d’aquesta estructura em podem treure dades essencials com el fotograma actual, fotogrames per segon, nombre de fotogrames… La majoria de tipus de variable d’OpenCV segueixen la nomenclatura d’aquesta, del tipus Cv(nom), IplImage és una de les poques excepcions.
int fps: Servirà per salvar els fotogrames per segon del vídeo o la Webcam i així realitzar els càlculs necessaris per adaptar el reproductor a la velocitat de successió de la seqüència. Per exemple, una pel·lícula sol reproduir-se a 24 fps, mentre que la Webcam del meu portàtil funciona a 100 fps.
La variable char key salvarà les tecles que espitxem, i en cas de que una d’aquestes sigui “ESC” finalitzarà el programa.
Funcions
El programa comença amb un condicional if-else que simplement verifica si l’usuari ha introduït algun argument al programa, si és així aquest argument hauria de ser una ruta a un arxiu de vídeo, si no n’ha introduït cap la font de vídeo serà la Webcam.
video = cvCaptureFromFile(argv[1]): Aquesta funció rescata el vídeo indicat en el seu argument (tipus cadena de caràcters), que ha de ser evidentment una ruta cap a l’arxiu. Això permet preparar a l’estructura vídeo per realitzar el flux de la pel·lícula.
fps = (int)cvGetCaptureProperty(video, CV_CAP_PROP_FPS): Aquesta ens permet obtenir les dades del tipus d’estructura CvCapture. Els seus arguments són dos: El punter a l’estructura, en aquest cas video, que conté el flux de la pel·lícula i un identificador de la propietat, en aquest cas CV_CAP_PROP_FPS, que indica la dada que volem obtenir, es dedueix que la dada que obtenim amb aquest identificador són els fps del vídeo. Fem un cast a int perquè el valor que retorna es de tipus double.
video = cvCaptureFromCAM(-1): Aquesta funció és molt pareguda a l’anterior, però enlloc d’obtenir el flux de un arxiu de vídeo ho fa de la Webcam indicada en l’argument. Un -1 indica que no importa quina càmera sigui, per exemple quan tan sols n’hi ha una, els nombres de 0 cap endavant indiquen l’índex de la càmera quan n’hi ha més d’una.
El següent pas és crear la finestra per visualitzar el flux de vídeo:
cvNamedWindow(“aitorkun”, CV_WINDOW_AUTOSIZE): Crea i mostra una finestra amb el nom donat al primer argument i la propietat del segon, de totes formes, l’única opció suportada fins ara és CV_WINDOW_AUTOSIZE que ajusta les dimensions de la finestra al seu contingut. Per a referir-se en properes funcions a aquesta finestra es fa mitjançant el nom donat al primer argument, en aquest cas “aitorkun”.
Fet això entrem al loop principal del programa que genera la seqüència d’imatges:
frame = cvQueryFrame(video): Obtenim el fotograma actual del flux de vídeo indicat en l’argument i el desem a l’estructura de dades IplImage *frame.
cvFlip(frame, NULL, 1): Aquesta funció es pròpia de <cv.h> i el que realitza es un gir de la imatge donada al primer argument. El segon argument indica la estructura de dades de destí, per exemple una altra IplImage, en el nostre cas, però, amb el valor NULL indiquem que volem desar la imatge voltada a la mateixa variable “frame” sobreescrivint l’anterior. Per al tercer argument els valors positius indiquen un gir horitzontal, un valor 0 indica gir vertical i valors negatius un gir tant vertical com horitzontal.
cvShowImage(“aitorkun”, frame): Molt fàcil, aquesta funció mostra la imatge “frame” dintre la finestra “aitorkun”, és a dir, el primer argument indica la finestra sobre la que es mostra la imatge del segon argument.
key = cvWaitKey(1000/fps): En el nostre cas aquesta funció realitza una “doble funció”. Per una banda funciona de temporitzador per pausar l’execució del programa durant el temps indicat en el seu argument (en milisegons), i per l’altra ens retorna un enter amb el codi de la tecla espitxada durant aquest període de temps, en cas de no haver-se espitxat cap tecla retorna un 0. Aquest funció dintre del bucle while resulta de gran utilitat per actualitzar els fotogrames a la velocitat adequada de reproducció de la pel·lícula. Per exemple, un vídeo a 24 fps actualitza el fotograma cada 0.04 segons, ja que mostra 24 fotogrames cada segon. Com que aquest valor s’ha de passar a la funció en milisegons es multiplica per 1000. Així doncs 1/24 * 1000 = 1000/24, on 24 son els fps. Això significa que en aquest cas l’execució normal del programa s’aturarà durant 0.04 segons, i un cop passat aquest temps tornarà a començar el bucle while, actualitzarà el fotograma a frame = cvQueryFrame(video), el mostrarà per pantalla i així successivament.
Finalment, en cas de que l’usuari hagi espitxat la tecla “ESC”, finalitzem el programa:
cvDestroyWindow(“aitorkun”): Destrueix la finestra “aitorkun”, és a dir, tanca la finestra i allibera la memòria.
cvReleaseCapture(&video): Allibera la memòria ocupada pel punter “video”, no volem que es quede el vídeo fent de les seves en segon pla!
Quasi bé totes les funcions que hem utilitzat pertanyen a <highgui.h>, son totes aquelles que involucren vídeo i finestres, de fet, la única que pertany a <cv.h> és cvFlip(frame, Null, 1).
Compilació i execució
Per a entorns Unix com GNU/Linux i MacOS és suficient amb el compilador de C GCC (GNU C Compiler). Per poder compilar les aplicacions que contenen capçaleres d’OpenCV és necessari especificar a GCC la ruta on es troben les capçaleres, les llibreries que aquestes requereixen i els enllaçadors. En el cas de Debian i derivats, com Ubuntu, les capçaleres s’instal·len predeterminadament a /usr/include/opencv/ i les llibreries a /usr/lib/
En Microsoft Windows no sé on s’instal·len els fitxers, però suposo que si es fa en l’instal·lador donarà l’opció de triar les rutes de destí. Tant si utilitzes un IDE (Integrated Development Environment) com es Dev-C++ o Eclipse o un compilador individual com MinGW o Cygwin hauràs d’especificar les rutes.
Per a GCC o qualsevol compilador basat en ell com Cygwin la sintaxis bàsica per compilar una aplicació OpenCV és aquesta:
gcc [programa.c] -o [programa] -I[capçaleres] -L[llibreries] -lcv -lhighgui
Essent [capçaleres] i [llibreries] les rutes de la ubicació de les capçaleres i les llibreries d’OpenCV indicades amb l’opció -I i -L respectivament. L’opció -l indica els enllaçadors de les llibreries i [programa.c] i [programa] son el codi font i l’executable resultant respectivament.
En el meu cas (Ubuntu 10.4, GCC) queda així:
gcc reproductor.c -o reproductor -I/usr/include/opencv/ -L/usr/lib/ -lcv -lhighgui
Es recomanable en Microsoft Windows que l’executable resultant acabi amb extensió .exe.
Per agilitar el procés de compilació es recomanable en entorns Unix crear un fitxer de text anomenat Makefile i utilitzar el programa Make de GNU per automatitzar la compilació, d’aquesta manera és més fàcil aplicar canvis al programa, de totes maneres amb la línia anterior es suficient. Dintre dels arxius comprimits hi ha una mostra de fitxer Makefile. Es pot compilar l’aplicació situant-se amb la terminal a la carpeta amb el Makefile i el codi font i teclejant make.
Un cop compilat el programa es pot executar amb un simple ./[nomdelprograma] a la terminal i situat a la carpeta de l’executable. En Microsoft Windows un simple “doble click” sobre el .exe serà suficient, a no ser que vulgueu reproduir un vídeo, llavors haureu d’especificar la ruta de l’arxiu a la línia de comandes de Windows.
El resultat hauria de quedar semblant a això:
Recordeu que si especifiqueu la ruta de un arxiu de vídeo podreu reproduir una pel·lícula! En cas contrari veureu la vostra Webcam, si en teniu.
Fins aquí el tutorial, espero que us hagi quedat tot més o menys clar i que us hagi servit d’ajuda. Fins la propera!
P.D.: OpenCV no està orientat al tractament de so, així que no té suport per descodificar àudio i per tant per reproduir la música de les pel·lícules, potser en un cert temps incorporo una altra llibreria per incloure’l, però si algun dels lectors vol millorar el programa, endavant!
Publicat per AitorKun