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.<br>
<br>===============================================================================================<br><br><b><u>DE C A C++</u></b><br>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é?<br>
<br>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.<br>
<br>Además te permite generar un código limpio.<br><br><b><u>INTRODUCIENDO MAT</u></b><br>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<br>
<br><div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace"><span style="color:rgb(0,0,255)">using</span> <span style="color:rgb(0,0,255)">namespace</span> cv<span style="color:rgb(0,128,128)">;</span></pre>
</div></div><br>Si no incluyeras esta línea, tendrás que emplear cv:: para tener acceso a las cosas en namespace, como cv::Mat.<br><br>El nuevo tipo Mat soporta álgebra matricial de manera parecida a la empleada en Matlab:<br>
<br><pre class="cpp" style="font-family:monospace">Mat A<span style="color:rgb(0,0,128)">=</span>Mat<span style="color:rgb(0,128,0)">(</span><span style="color:rgb(0,0,221)">3</span>,<span style="color:rgb(0,0,221)">4</span>,CV_32FC1<span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span><br>
Mat B<span style="color:rgb(0,0,128)">=</span>Mat<span style="color:rgb(0,128,0)">(</span><span style="color:rgb(0,0,221)">4</span>,<span style="color:rgb(0,0,221)">3</span>,CV_32FC1<span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span><br>
...<br><span style="color:rgb(102,102,102)">//code for initialization of A and B</span><br>...<br><span style="color:rgb(0,119,136)">Mat</span> C <span style="color:rgb(0,0,128)">=</span> <span style="color:rgb(0,0,221)">2</span><span style="color:rgb(0,0,64)">*</span>A<span style="color:rgb(0,0,64)">*</span>B<span style="color:rgb(0,128,128)">;</span></pre>
<br>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:<br>
<br><pre class="cpp" style="font-family:monospace">Mat C <span style="color:rgb(0,0,128)">=</span> C.<span style="color:rgb(0,119,136)">inv</span><span style="color:rgb(0,128,0)">(</span><span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span> <span style="color:rgb(102,102,102)">//Now C is its own inverse matrix</span><br>
Mat D <span style="color:rgb(0,0,128)">=</span> A.<span style="color:rgb(0,119,136)">t</span><span style="color:rgb(0,128,0)">(</span><span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span> <span style="color:rgb(102,102,102)">//D is the transposed matrix of A</span></pre>
<br>Con esta pequeña introducción, quedan claros los beneficios de emplear la nueva interfaz C++.<br><br><b><u>ESTRUCTURA INTERNA</u></b><br>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.<br>
<br><u><b>DECLARACION DE LA MATRIZ</b></u><br>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.<br><br>La manera más sencilla de declarar una matriz es la siguiente:<br>
<br><pre class="cpp" style="font-family:monospace">Mat m <span style="color:rgb(0,0,128)">=</span> Mat<span style="color:rgb(0,128,0)">(</span>rows, cols, type<span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span></pre>
<br>donde rows y cols son el número de filas y columnas y type es el formato de la matriz.<br><br>Si lo que quieres crear es una imagen, existe un método más intuitivo:<br><br><pre class="cpp" style="font-family:monospace">
Mat m <span style="color:rgb(0,0,128)">=</span> Mat<span style="color:rgb(0,128,0)">(</span>Size<span style="color:rgb(0,128,0)">(</span>width,height<span style="color:rgb(0,128,0)">)</span>, type<span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span></pre>
<br>Y si lo que deseas es duplicar el tamaño de otra imagen, puedes emplear<br><br><pre class="cpp" style="font-family:monospace">Mat n <span style="color:rgb(0,0,128)">=</span> Mat<span style="color:rgb(0,128,0)">(</span>m.<span style="color:rgb(0,119,136)">size</span><span style="color:rgb(0,128,0)">(</span><span style="color:rgb(0,128,0)">)</span>, type<span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span></pre>
<br>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++.<br><br><u><b>ACCEDIENDO A LOS ELEMENTOS</b></u><br>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)<br>
<br><pre class="cpp" style="font-family:monospace">Mat a<span style="color:rgb(0,0,128)">=</span> Mat<span style="color:rgb(0,128,0)">(</span><span style="color:rgb(0,0,221)">4</span>,<span style="color:rgb(0,0,221)">3</span>, CV_32FC1<span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span><br>
<span style="color:rgb(0,0,255)">float</span> elem_a<span style="color:rgb(0,0,128)">=</span> a.<span style="color:rgb(0,119,136)">at</span><span style="color:rgb(0,0,128)"><</span><span style="color:rgb(0,0,255)">float</span><span style="color:rgb(0,0,128)">></span><span style="color:rgb(0,128,0)">(</span>i,j<span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span> <span style="color:rgb(102,102,102)">//access element aij, with i from 0 to rows-1 and j from 0 to cols-1</span></pre>
<br>En vez de utilizar la posición (i,j) puedes emplear un puntero:<br><br><pre class="cpp" style="font-family:monospace">Point p<span style="color:rgb(0,0,128)">=</span>Point<span style="color:rgb(0,128,0)">(</span>x,y<span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span><br>
<span style="color:rgb(0,0,255)">float</span> elem_a<span style="color:rgb(0,0,128)">=</span> a.<span style="color:rgb(0,119,136)">at</span><span style="color:rgb(0,0,128)"><</span><span style="color:rgb(0,0,255)">float</span><span style="color:rgb(0,0,128)">></span><span style="color:rgb(0,128,0)">(</span>p<span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span> <span style="color:rgb(102,102,102)">//Warning: y ranges from 0 to rows-1 and x from 0 to cols-1</span></pre>
<br>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:<br>
<br><pre class="cpp" style="font-family:monospace">type elem <span style="color:rgb(0,0,128)">=</span> matrix.<span style="color:rgb(0,119,136)">ptr</span><span style="color:rgb(0,0,128)"><</span>type<span style="color:rgb(0,0,128)">></span><span style="color:rgb(0,128,0)">(</span>i<span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,0)">[</span>N<span style="color:rgb(0,0,128)"><</span>sub<span style="color:rgb(0,0,128)">></span>c<span style="color:rgb(0,0,128)"><</span><span style="color:rgb(0,0,64)">/</span>sub<span style="color:rgb(0,0,128)">></span><span style="color:rgb(0,0,64)">*</span>j<span style="color:rgb(0,0,64)">+</span>c<span style="color:rgb(0,128,0)">]</span></pre>
<br>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).<br><br>Este método podría utilizarse en las matrices unidimensionales, pero N<sub>c sería 1 y c sería 0 siempre.<br>
<b><u><br>REORGANIZANDO</u></b><br>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:<br>
<br><pre class="cpp" style="font-family:monospace">Mat a<span style="color:rgb(0,0,128)">=</span> Mat<span style="color:rgb(0,128,0)">(</span><span style="color:rgb(0,0,221)">4</span>,<span style="color:rgb(0,0,221)">1</span>, CV_32FC3<span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span> <span style="color:rgb(102,102,102)">//a is 4x1, 3 channels</span><br>
Mat b<span style="color:rgb(0,0,128)">=</span>a.<span style="color:rgb(0,119,136)">reshape</span><span style="color:rgb(0,128,0)">(</span><span style="color:rgb(0,0,221)">1</span><span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span> <span style="color:rgb(102,102,102)">//b is 4x3, 1 channel</span></pre>
<br>¿Dónde sería útil esto? Imaginemos que tenemos una lista de punteros:<br><br><pre class="cpp" style="font-family:monospace">vector<span style="color:rgb(0,0,128)"><</span>Point3f<span style="color:rgb(0,0,128)">></span> v<span style="color:rgb(0,128,128)">;</span> <span style="color:rgb(102,102,102)">//suppose it is already full</span></pre>
<br>Supongamos que ya se encuentra llena, con los puntos:<br><br><pre>[(x0, y0, z0)]<br>[(x1, y1, z1)]<br>[(x2, y2, z2)]<br>[(x3, y3, z3)]<br>[(..., ..., ...)]</pre><br>Podemos "importar" esta lista a una matriz de la siguiente manera:<br>
<br><pre class="cpp" style="font-family:monospace">Mat m1<span style="color:rgb(0,0,128)">=</span>Mat<span style="color:rgb(0,128,0)">(</span>v, <span style="color:rgb(0,0,255)">true</span><span style="color:rgb(0,128,0)">)</span><span style="color:rgb(0,128,128)">;</span> <span style="color:rgb(102,102,102)">//boolean value true is necessary in order to copy data from v to m1</span></pre>
<br>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).<br><br>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.<br>
<br><b><u>ALGUNAS EQUIVALENCIAS</u></b><br>Aquí teneis una equivalencia entre código en C y C++ que será útil para portar código:<br><ul><li><em>CvSize</em> -> <em>Size</em></li><li><em>CvVideoCapture</em> -> <em>VideoCapture</em></li>
<li><em>IplImage, CvMat</em> -> <em>Mat</em></li><li><em>cvQueryFrame </em>-><em> >> </em>(operator)</li><li><em>cvShowImage -> imshow</em></li><li><em>cvLoadImage -> imread</em></li></ul><br><br><br><br>
<br><br><br><br><br><br>