c++ - practical - opencv python
Split 3D MatND en vector de 2D Mat opencv (1)
¿Es posible obtener un objeto Mat 2D de un cubo de datos 3D almacenado como MatND en opencv? Básicamente estoy pasando una matriz 3D a MexFile usando "mexopencv". Convierto la matriz en un objeto MatND usando MxArray (prhs [0]). ToMatND (). Ahora quiero dividir este cubo de datos a lo largo de la tercera dimensión en un vector de matrices cv :: Mat. Necesito hacer operaciones en estas matrices 2D y, por lo tanto, iterar sobre la tercera dimensión. ¿Hay una función para dividir el cubo de datos según sea necesario? ¿O tal vez una forma de obtener un puntero a las sub matrices 2D del cubo de datos 3D?
Editar: Este es mi código que usa mexopencv para convertir los argumentos de entrada de Matlab en matrices MatND. Implementé el método de @ chappjc para dividir el código de datos 3D en un vector de matrices 2D. Aparte del hecho de que las dimensiones xey están conmutadas, todo está bien.
#include "mexopencv.hpp"
#include <iostream>
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
// Check arguments
if (nlhs!=1 || nrhs!=1)
mexErrMsgIdAndTxt("myfunc:invalidArgs", "Wrong number of arguments");
// 1) Convert MxArray to cv::Mat
cv::MatND matnd = MxArray(prhs[0]).toMatND();
// Extract planes from matrix
int dims[] = { matnd.size[0],matnd.size[1],matnd.size[2]};
std::vector<cv::Mat> matVec;
for (int p = 0; p < dims[2]; ++p) {
double *ind = (double*)matnd.data + p * dims[0] * dims[1]; // sub-matrix pointer
matVec.push_back(cv::Mat(2, dims, CV_64F, ind).clone()); // clone if mnd goes away
}
std::cout << "/nmatVec[0]:/n" << matVec[0] << std::endl;
std::cout << "/nmatVec[1]:/n" << matVec[1] << std::endl;
// Here I will do some stuff with the 2D submatrices from matVec
// ...
// 2) Here I want to pass the 3D matrix back to Matlab
// I only know how to convert cv::Mat back to mxArray* using mexopencv:
plhs[0] = MxArray(matnd);
}
2nd Edit. En realidad, el hecho de que las dimensiones estén cambiadas en "matVec" es bastante molesto. ¿Alguien tiene una solución mejor?
Este es el resultado de un pequeño ejemplo [5 x 4 x 2]:
>> b
b(:,:,1) =
1 6 11 16
2 7 12 17
3 8 13 18
4 9 14 19
5 10 15 20
b(:,:,2) =
101 106 111 116
102 107 112 117
103 108 113 118
104 109 114 119
105 110 115 120
>> c = cv.myFunc(b)
matVec[0]:
[1, 2, 3, 4, 5;
6, 7, 8, 9, 10;
11, 12, 13, 14, 15;
16, 17, 18, 19, 20]
matVec[1]:
[101, 102, 103, 104, 105;
106, 107, 108, 109, 110;
111, 112, 113, 114, 115;
116, 117, 118, 119, 120]
c(:,:,1) =
1 6 11 16
2 7 12 17
3 8 13 18
4 9 14 19
5 10 15 20
c(:,:,2) =
101 106 111 116
102 107 112 117
103 108 113 118
104 109 114 119
105 110 115 120
Un sabio mago dijo una vez: No trates de dividir el MatND
. Eso es imposible. En cambio ... solo intenta darte cuenta de la verdad. No hay MatND
.
MatND
está obsoleto y ahora está typedef
''d a Mat
. En opencv2 / core / core.hpp:
typedef Mat MatND;
Esto significa que puede tratarlo como una Mat
y cortarlo manualmente. Creo que los métodos at
y ptr
no funcionan como se esperaba para dims> 2, por lo que puede tomar el puntero Mat::data
y calcular la ubicación de la submatriz. Hay un ptr(int i0, int i1, int i2)
, pero no he tenido mucha suerte porque el step[]
para matrices multidimensionales es extraño.
Ejemplo
// create 3D matrix with element index as content
int dims[] = { 5, 5, 3 };
cv::Mat mnd(3, dims, CV_64F);
for (int i = 0; i < mnd.total(); ++i)
*((double*)mnd.data+i) = (double)i;
// extract planes from matrix
std::vector<cv::Mat> matVec;
for (int p = 0; p < dims[2]; ++p) {
double *ind = (double*)mnd.data + p * dims[0] * dims[1]; // sub-matrix pointer
matVec.push_back(cv::Mat(2, dims, CV_64F, ind).clone()); // clone if mnd goes away
}
std::cout << "Size of matVec: " << matVec.size() << std::endl;
std::cout << "Size of first Mat: " << matVec[0].size() << std::endl;
std::cout << "/nmatVec[0]:/n" << matVec[0] << std::endl;
std::cout << "/nmatVec[1]:/n" << matVec[1] << std::endl;
std::cout << "/nmatVec[2]:/n" << matVec[2] << std::endl;
Salida
Size of matVec: 3
Size of first Mat: [5 x 5]
matVec[0]:
[0, 1, 2, 3, 4;
5, 6, 7, 8, 9;
10, 11, 12, 13, 14;
15, 16, 17, 18, 19;
20, 21, 22, 23, 24]
matVec[1]:
[25, 26, 27, 28, 29;
30, 31, 32, 33, 34;
35, 36, 37, 38, 39;
40, 41, 42, 43, 44;
45, 46, 47, 48, 49]
matVec[2]:
[50, 51, 52, 53, 54;
55, 56, 57, 58, 59;
60, 61, 62, 63, 64;
65, 66, 67, 68, 69;
70, 71, 72, 73, 74]