[Jderobot-dev] JDErobot 5.0 y OpenCV2.3.1

Julio Guillén julio.guillen en gmail.com
Mie Ene 25 12:46:21 CET 2012


He estado investigando respecto a lo que me comentasteis de IplImage y
CvMat deprecados en OpenCV 2.3.1 y he encontrado un artículo muy
interesante que voy a traduciros en parte. Como yo programaba en C con
OpenCV desconocía esta información que espero resulte útil a los usuarios
de jderobot.

===============================================================================================

*DE C A C++*
Desde la versión 2.0 de OpenCV, en la nueva API de C++, se introdujo el
tipo cv::Mat o simplemente Mat para sustituir los tipos en C IplImage y
CvMat. Aunque ambas estructuras siguen siendo soportadas, se recomienda
cambiar a C++. ¿Por qué?

Mat engloba el concepto de matrix e imagen. De hecho, son la misma cosa al
final. Mat, además incluye varias características interesantes tales como
un "contador de referencia" (reference counter) que puede ser de gran
ayuda. Te libera de la gestión de la memoria.

Además te permite generar un código limpio.

*INTRODUCIENDO MAT*
Antes de poder emplear la interfaz de C++, debes "incluir" el namespace de
OpenCV. Esto se realiza añadiendo la siguiente línea después de los #include

using namespace cv;


Si no incluyeras esta línea, tendrás que emplear cv:: para tener acceso a
las cosas en namespace, como cv::Mat.

El nuevo tipo Mat soporta álgebra matricial de manera parecida a la
empleada en Matlab:

Mat A=Mat(3,4,CV_32FC1);

Mat B=Mat(4,3,CV_32FC1);

...
//code for initialization of A and B
...
Mat C = 2*A*B;


En este ejemplo C es una matriz de 3x3 cuyos elementos se multiplican por
el escalar 2. Esta forma de escribir operaciones matriciales algebraicas es
mucho más simple e intutitiva que empleando funciones tales como
cvGEMM(...). Igualmente, resulta trivial calcular la inversa o traspuesta
de una matriz:

Mat C = C.inv(); //Now C is its own inverse matrix

Mat D = A.t(); //D is the transposed matrix of A


Con esta pequeña introducción, quedan claros los beneficios de emplear la
nueva interfaz C++.

*ESTRUCTURA INTERNA*
Mat es similar a las viejas estructuras CvMat e IplImage. El origen se
encuentra arriba a la izquierda, y filas y columnas comienzan en 0.

*DECLARACION DE LA MATRIZ*
Una matriz puede construirse de varias formas. Es necesario definir el
formato (no como en Matlab o Python). La matriz puede tener uno, dos, tres
o cuatro canales.

La manera más sencilla de declarar una matriz es la siguiente:

Mat m = Mat(rows, cols, type);


donde rows y cols son el número de filas y columnas y type es el formato de
la matriz.

Si lo que quieres crear es una imagen, existe un método más intuitivo:


Mat m = Mat(Size(width,height), type);


Y si lo que deseas es duplicar el tamaño de otra imagen, puedes emplear

Mat n = Mat(m.size(), type);


donde type define el número de bytes asignados para cada elemento en la
matriz. Las constantes que puedes emplear son idénticas para C y C++.

*ACCEDIENDO A LOS ELEMENTOS*
Acceder a cada pixel o elemento en una Matriz de un canal es trivial.
Empleas el método at para acceder al valor en una posición particular (i,j)

Mat a= Mat(4,3, CV_32FC1);
float elem_a= a.at<float>(i,j); //access element aij, with i from 0 to
rows-1 and j from 0 to cols-1


En vez de utilizar la posición (i,j) puedes emplear un puntero:

Point p=Point(x,y);
float elem_a= a.at<float>(p); //Warning: y ranges from 0 to rows-1 and
x from 0 to cols-1


Para acceder a los pixeles en una Matriz multidimensional las cosas se
vuelven un poco más complicadas. Pero aún así resultan más sencillas que
emplear los macros CV_MAT_ELEM o CV_IMAGE_ELEM. Debes utilizar el método
ptr para obtener un puntero a una fila particular. Posteriormente debes
emplear [] para acceder a un pixel en un determinado canal:

type elem = matrix.ptr<type>(i)[N<sub>c</sub>*j+c]


donde type es el tipo (float, int, uchar, etc...), i es la fila que buscas,
N<sub>c el número de canales, j la columna que buscas y c el canal en el
que estás interesado (varía de 0 a 3).

Este método podría utilizarse en las matrices unidimensionales, pero
N<sub>c sería 1 y c sería 0 siempre.
*
REORGANIZANDO*
Aquí vamos a enseñar como jugar con el número de canales y fila de la
Matriz. Imaginemos que tenemos una matriz Nx1 con Nc canales y deseamos
convertirla en una matriz de un canal y NxNc. Una sencilla forma de
conseguirlo sería:

Mat a= Mat(4,1, CV_32FC3); //a is 4x1, 3 channels

Mat b=a.reshape(1); //b is 4x3, 1 channel


¿Dónde sería útil esto? Imaginemos que tenemos una lista de punteros:

vector<Point3f> v; //suppose it is already full


Supongamos que ya se encuentra llena, con los puntos:

[(x0, y0, z0)]
[(x1, y1, z1)]
[(x2, y2, z2)]
[(x3, y3, z3)]
[(..., ..., ...)]


Podemos "importar" esta lista a una matriz de la siguiente manera:

Mat m1=Mat(v, true); //boolean value true is necessary in order to
copy data from v to m1


Si el booleano no los especificamos a true, la matriz solamente apuntará a
la lista y no sería una auténtica copia (duplicación de data en memoria).

De esta forma, m1 tiene varias filas (las mismas que v.size() ),
exactamente 1 columna y 3 filas. Puedes reorganizar esta matriz a una
matriz con v.size() filas, 3 columnas y un canal.

*ALGUNAS EQUIVALENCIAS*
Aquí teneis una equivalencia entre código en C y C++ que será útil para
portar código:

   - *CvSize* -> *Size*
   - *CvVideoCapture* -> *VideoCapture*
   - *IplImage, CvMat* -> *Mat*
   - *cvQueryFrame *->* >> *(operator)
   - *cvShowImage -> imshow*
   - *cvLoadImage -> imread*
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: http://gsyc.escet.urjc.es/pipermail/jde-developers/attachments/20120125/e0e0d8b3/attachment.htm 


More information about the Jde-developers mailing list