====== OpenCV ======
OpenCV es una biblioteca de Intel que contiene rutinas y clases para el desarrollo de [[ai:computer_vision|Computer Vision]] e [[ai:image_processing|Image Processing]] para C\C++.
===== Introducción =====
==== Estructura de la librería ====
* **cxcore**, donde están las estructuras, funciones y algoritmos básicos.
* **cv**, enfocado a la Computer Vision y a la Image Processing.
* **highgui**, enfocado a la I\O, imágen, vídeo e interfaz gráfica.
==== Cómo utilizarlo? ====
Al instalarlo o descomprimirlo (según la versión) encontramos en el destino al menos dos directorios principalesimportantes: **bin** (donde están las dll) y **lib** (donde están los lib), y luego dentro de cada directorio de módulo (cv, cvaux, cxcore...) existe su directorio **include** correspondiente, donde están las cabeceras para nuestro código. [[highlevel:c:advancing#crear_y_utilizar_una_biblioteca_windows|Aquí]] cómo incluirlas en el proyecto, aunque básicamente necesitarás, sobretodo, vincular el //cxcore.lib// y las que vayas utilizando.
===== GUI =====
==== Ventanas ====
En HighGUI existen un número elevado de funciones que nos serán de utilidad al trabajar con ventanas, sus controles y eventos. \\ \\
Empecemos por **cvNamedWindow**, a la cual se le pasa una cadena de carácteres, identificadora de dicha ventana para futuros usos. El segundo parámetro es opcional, pudiendo pasarle la flag ''CV_WINDOW_AUTOSIZE'' (que si no es indicado es el valor dado). \\ \\
Editar la ventana es fácil utilizando funciones como **cvMoveWindow** o **cvResizeWindow**, para poder acceder a ella desde la API sólo necesitaremos su handle, fácil de coger utilizando la función **cvGetWindowHandle**. Podemos hacer la acción inversa (coger el nombre de la ventana utilizando su handle) ocn la función **cvGetWindowName**. \\ \\
Funciones como **cvDestroyAllWindows** o **cvDestroyWindow** se utilizarán para cerrar la ventana por código.
==== Control de teclado y ratón ====
=== Teclado ===
Para controlar el teclado existe una única función, la **cvWaitKey (delay=0)**, dicha función hace lo que su mismo nombre indica: esperar a que se pulse una tecla, esperará el tiempo que se le pase por parámetro (eternamente si este es 0). \\ \\
Para hacer que el programa continue si el usuario no ha pulsado una tecla se la llama con ''delay != 0'' y se mira su retorno.
=== Ratón ===
Para gestionar el control del ratón hay que definir una función para ello mediante la función **cvSetMouseCallback**, nuestra función tendrá que ser definida como ''void (nombre) (int event, int x, int y, int flags, void* param)'' donde ''x'' e ''y'' son las coordenadas actuales del mouse (en la imágen, no la ventana), ''event'' el evento lanzado (''CV_EVENT_MOUSEMOVE, CV_EVENT_LBUTTONDOWN, CV_EVENT_MBUTTONUP...''), los flags son una combinación de acciones realizadas durante el evento (''CV_EVENT_FLAG_RBUTTON, CV_EVENT_FLAG_ALTKEY...'') y ''param'' datos que el usuario quiere enviar a la función. \\ \\
Para llamar a **cvSetMouseCallback** hay que pasle tres parámetros:
- El nombre de la ventana que ha de gestionar.
- El nombre de la función.
- Lo que el usuario quiera mandar a la función.
void on_mouse (int event, int x, int y, int flags, void* param) { ... }
void main () {
cvSetMouseCallback("LkDemo", on_mouse, 0);
...
==== Controles ====
Podemos colocar y tratar una barra de números en una ventana creada con OpenCV utilizando las funciones ''cvCreateTrackbar'', ''cvGetTrackbarPos'' y ''cvSetTrackbarPos''.
===== Funciones y tipos básicos =====
==== Tipos básicos ====
* **CvSize** estructura que respresenta un tamaño con ''height'' y ''width'', podemos crear una instancia utilizando la función **cvSize** que recibe estos dos argumentos.
* **CvPoint** estructura que representa un punto con ''x'' e ''y'', igual que con CvSize podemos crear una instancia utilizando **cvPoint**.
* **CvRect**, como las anteriores, pero esta representa un área cuadrada, perfecta para indicar regiones de trabajo en una imágen.
==== Funciones de utilidad ====
* **cvGetTickCount** y **cvGetTickFrequency**, para recoger el número de ticks totales de la CPU hasta ahora y su frecuencia.
==== Imágenes ====
La clase **IplImage** representa una imágen cualquiera, para cargar sobre ella un archivo es tan sencillo como llamar a **cvLoadImage** pasándole como único parámetro el nombre de dicho archivo, esta función devolverá el **IplImage*** correspondiente con su formato determinado por el archivo cargado. Para guardar la imágen es igual de fácil, sólo hay que llamar a **cvSaveImage**, función que recibe el nombre de la nueva imágen y un **IplImage***, fácil no? \\ \\
Las propiedades de un **IplImage** incluyen el tamaño (height y width), los bytes correspondientes a la imágen (imageData)... \\ \\
Para mostrar una imágen en una ventana (ya creada) llamaremos a la función **cvShowImage** con dos parámetros, el primero la cadena de carácteres identificadora de la ventana creada con ''cvNamedWindow'' y el segundo un **IplImage***. Si la imágen se muestra en una ventana que se creó indicando que el tamaño es automático (con ''CV_WINDOW_AUTOSIZE'') entonces la ventana se redimensiona al tamaño de la imágen (y queda la ventana como no-redimensionable), si no, la imágen se redimensiona al tamaño de la ventana. \\ \\
Más cosas...
* Podemos cambiar el formato de una imágen utilizando la función **cvConvertImage**.
* **cvCloneImage** clona una imágen (con sus datos relacionados) en otra.
* **cvCreateImage** crea y reserva el espacio para una imágen, requiere un CvSize, una profundidad (definida como ''IPL_DEPTH_XXX'') y el número de canales de color (1, 2, 3 o 4).
Una vez acabemos el trabajo con una imágen deberemos liberar los datos utilizados de memoria, para ello utilizamos la función **cvReleaseImage**.
cvNamedWindow("prueba");
IplImage* img = cvLoadImage("airplane.jpg");
cvShowImage("prueba", img);
cvWaitKey();
=== Dibujar sobre una imágen ===
A todas las funciones de dibujo podemos pasarle como parámetro una **IplImage** (básicamente aceptan un ''CvArr''), que podemos crear mediante **cvCreateImage**, por lo que no nos será complejo realizar dibujos. \\
El color puede ser indicado mediante la macro **CV_RGB** o la función **cvScalar**. \\
Para dibujar **formas**:
* cvLine
* cvRectangle
* cvCircle
* cvEllipse
* ...
Para dibujar **texto**:
* Lo primero que tendremos que hacer es inicializar la fuente con la que vamos a escribir, para ello tenemos la función **cvInitFont** ''(CvFont* font, int font_face, double hscale, double vscale, double shear=0, int thickness=1, int line_type=8)'', la cual inicializa una instancia **CvFont**, con una font_face (que está definida como ''CV_FONT_HERSHEY_XXX''), hscale y vscale corresponden al tamaño, shear a si está en cursiva o no (1.0 serían unos 45º) y line_type corresponde al tipo de línea que utiliza (ver cómo dibujar líneas).
* **cvPutText** ''(CvArr* img, const char* text, CvPoint org, const CvFont* font, CvScalar color )'' escribe en la imágen ''img'' el texto ''text'' en la posición ''org'' utilizando la fuente ''font'' y el color ''color''.
* **cvGetTextSize** es la función adecuada para indicarte cuanto mide un texto en una imágen.
===== Trabajar con la cam =====
Las siguientes funciones las encontraremos en la cabecera //cvcam.h// necesitando vincular la //cvcam.lib//. \\
La función **cvCaptureFromCAM** es la encargada de iniciar una captura de la webcam, se le puede pasar (opcionalmente) un valor numérico para indicar el número de cámara que se utilizará; para saber cuantas CAMs tiene disponible la máquina haremos una llamada a **cvcamGetCamerasCount**. El tipo que representa una captura, ya sea de la cam o de un archivo de video (para hacerla de un archivo de video hay que llamar a **cvCaptureFromFile**) es **CvCapture**. Una vez tenemos una CvCapture la podemos pasar a **cvQueryFrame** y nos devolverá la última **IplImage**. Cuando acabemos con el uso de la cámara no debemos olvidar liberar la CvCapture llamando a **cvReleaseCapture**. \\ \\
Podemos crear una **CvCapture** utilizando también las funciones de la HighGUI (que no nos dan tanto control sobre la cámara) **cvCreateCameraCapture** (para capturar desde la cam, requiere como argumento el índice de la cámara) o **cvCreateFileCapture** (para capturar desde un archivo). También podremos definir las propiedades de la captura con **cvSetCaptureProperty** (o consultarlas con **cvGetCaptureProperty**), esta función requiere de 3 parámetros: un puntero a la **CvCapture**, el id de la propiedad a cambiar (ver más abajo las [[fw:opencv#propiedades_de_una_captura|Propiedades de una captura]]) y el valor asignado.
CvCapture* cpa = cvCreateCameraCapture(0);
cvNamedWindow("winprueba");
do {
IplImage* img = cvQueryFrame(cpa);
cvShowImage("winprueba", img);
cvWaitKey (30);
} while (1);
cvReleaseCapture(&cpa);
==== Mayor control con cvcam ====
Aunque con la HighGUI podemos manejar la cámara la ''cvcam'' nos dá mayor control sobre esta mediante un mayor número de funciones. Para que estas funcionen el sistema ha de tener registrados los filtros de DirectShow ''CalibFilter.ax'' y ''ProxyTrans.ax'' que vienen con OpenCV, para saber cómo registrarlos miralo [[otros:otros#windows|aquí]]. \\ \\
Una vez hemos llamado a ''cvcamGetCamerasCount'' y asignado las propiedades de la cámara deseadas mediante ''cvcamSetProperty'' (es importante activar el enable y al render) entonces llamaremos a **cvcamInit()** para acabar de inicializar la cámara. Para empezar a grabar tenemos la función **cvcamStart** y para acabar **cvcamStop**. Podemos pausar y reanudar el trabajo con la cam utilizando **cvcamPause** y **cvcamResume**. \\ \\
Otras funciones de cvcam:
* **int cvcamSelectCamera(int*)** aparece un cuadro de diálogo donde elegimos qué camara utilizaremos (será colocado en el parámetro).
* **int cvcamGetCamerasCount()** devuelve el número de cámaras disponibles en el sistema e inicializa el cvcam.
Es importante indicar que la primera llamada ha de ser a ''cvcamGetCamerasCount'' para que se inicialice el cvcam.
int ncams = cvcamGetCamerasCount();
cvNamedWindow ("test");
HWND hwnd = (HWND)cvGetWindowHandle("test");
cvcamSetProperty(0, CVCAM_PROP_ENABLE, CVCAMTRUE);
cvcamSetProperty(0, CVCAM_PROP_RENDER, CVCAMTRUE);
cvcamSetProperty(0, CVCAM_PROP_WINDOW, &hwnd);
cvcamInit();
cvcamStart();
for (;;);
cvcamStop( );
cvcamExit( );
==== Propiedades de la cámara ====
* ''cvcamGetProperty(int cameraindex, const char* property, void* value)''
* ''cvcamSetProperty(int cameraindex, const char* property, void* value)''
Son funciones que nos permiten definir\consultar propiedades de la cámara, las //properties// vienen dadas por los siguientes identificadores:
* ''CVCAM_PROP_ENABLE'' - Selecciona\Deselecciona la cámara (hay que pasarle CVCAMTRUE o CVCAMFALSE).
* ''CVCAM_PROP_RENDER'' - Renderiza la cam (hay que pasarle CVCAMTRUE o CVCAMFALSE).
* ''CVCAM_PROP_WINDOW'' - Selecciona la ventana sobre la que se renderizará la captura (hay que pasarle un HWND).
* ''CVCAM_PROP_CALLBACK'' - Asigna una funcción ''void (*callback)(IplImage* image)'' para que trate la captura.
* ''CVCAM_DESCRIPTION'' - Recoge en una ''CameraDescription'' datos de la cam.
* ''CVCAM_VIDEOFORMAT''
* ''CVCAM_CAMERAPROPS''
* ''CVCAM_RNDWIDTH''
* ''CVCAM_RNDHEIGHT''
* ''CVCAM_STEREO_CALLBACK''
* ''CVCAM_PROP_RAW''
* ''CVCAM_PROP_SETFORMAT''
==== Propiedades de una captura ====
* ''CV_CAP_PROP_POS_MSEC'' - Tiempo en milisegundos desde el principio.
* ''CV_CAP_PROP_POS_FRAMES'' - Posición en frames (sólo para capturas desde ficheros).
* ''CV_CAP_PROP_POS_AVI_RATIO'' - Posición en un archivo en un ratio de 0-1.
* ''CV_CAP_PROP_FRAME_WIDTH'' - Ancho de un frame (sólo para capturas desde cámaras).
* ''CV_CAP_PROP_FRAME_HEIGHT'' - Alto de un frame (sólo para capturas desde cámaras).
* ''CV_CAP_PROP_FPS'' - Framerate (sólo para capturas desde cámaras).
* ''CV_CAP_PROP_FOURCC'' - código de 4 carácteres del codec (sólo para capturas desde cámaras).
===== Tratamiento de imágenes =====
==== Conceptos ====
* Un **canal** de una imágen digital corresponde a una imágen en escala de grises que representa la cantidad de un color primario en la imágen que estamos tratando. Por ejemplo, las imágenes RGB tienen 3 canales: rojo, verde y azul; las CMYK 4: cyan, magenta, amarillo y negro.
* La **normalización** es el proceso de cambiar la intensidad de los píxels de una imágen de forma que esté en un rango más igualado (también se le llama //contrast stretching//).
==== Acciones básicas sobre imágenes ====
Para indicar sobre qué área de la imágen vamos a trabajar (Region Of Interest) utilizaremos la función **cvSetImageROI** que recibe la imágen y un **CvRect** que sería dicha región, a partir de entonces la imágen sólo sería esa región hasta que llamemos a **cvResetImageROI**. En cualquier momento podemos llamar a **cvGetImageROI** para saber la //Region of Interest// actual. Las mismas funciones existen para el COI (Channel Of Interest), podemos escoger sobre qué canal de la imágen trabajaremos. \\ \\
Funciones como **cvSet**, **cvSetZero** o **cvCopy** asignan o copias bloques de una imágen. Por ejemplo la primera, **cvSet**, asigna un ''CvScalar'' a una imágen, el **cvSetZero** asigna a 0 los valores de color y el **cvCopy**copia de una imágen a otra.
CvRect rect = cvRect(0, 0, 200, 200 );
cvSetImageROI(img, rect);
cvSetZero(img);
cvResetImageROI(img);
==== Histogramas ====
Un histograma es una gráfica estadística que muestra las frecuencias de los valores de una variable. El histograma de una imágen es un histograma que corresponde a los valores de los píxels de dicha imágen, generalmente el número de píxels se coloca en vertical y su valor de brillo en horizontal, por ejemplo, si una imágen está en escala de grises los rangos se localizarán en la parte horizontal que corresponda al gris. También existe el histograma de color, que representa la distribución de colores, pero no es tan utilizado como el histograma de imágen que nos permite variar el brillo y el contraste de forma sencilla utilizando el método //histogram equalization//. \\ \\
===== Notas =====
* Para la utilización en Linux hay que instalar los paquetes: ''libcv'', ''libcvaux'' y ''libhighgui''.