2014-11-14 2 views
3

OpenCv에서 MatND로 저장된 3D 데이터 큐브에서 2D Mat 오브젝트를 가져올 수 있습니까? 기본적으로 "mexopencv"를 사용하여 MexFile에 3D 행렬을 전달합니다. MxArray (prhs [0]). toMatND()를 사용하여 행렬을 MatND 객체로 변환합니다. 이제이 데이터 큐브를 세 번째 차원을 따라 cv :: Matrices의 벡터로 분리하려고합니다. 따라서이 2D 행렬에 대한 연산을 수행하여 세 번째 차원을 반복해야합니다. 필요에 따라 데이터 큐브를 분할하는 기능이 있습니까? 아니면 3D 데이터 큐브의 2D 하위 행렬 포인터를 가져 오는 방법일까요?3D 매트를 2D 매트 벡터로 분할 opencv

편집 :이 코드는 mexopencv를 사용하여 Matlab 입력 인수를 MatND 배열로 변환하는 코드입니다. 3D 데이터 코드를 2D 행렬의 벡터로 분할하는 @ chappjc의 방법을 구현했습니다. 사실 x와 y 치수가 바뀌어도 모든 것이 좋습니다.

#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); 
} 

두 번째 편집. 실제로 치수가 "matVec"으로 전환된다는 사실은 매우 성가시다. 누구든지 더 나은 해결책이 있습니까?

작은 [5 × 4 × 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 

답변

6

현명한 마법사 한번 상기 : MatND을 분할하려고 시도하지 않는다. 불가능합니다. 대신 ... 오직 진실을 깨닫도록 노력하십시오. MatND은 없습니다.


MatND는 현재 무효이며, 지금 typedef의 'Mat에 거라고. opencv2/코어/core.hpp에서 :

typedef Mat MatND; 

이 방금 단지 Mat처럼 취급하고 수동으로 잘라 수 있다는 것을 의미합니다. atptr 메서드는 dims> 2에 대해 예상대로 작동하지 않으므로 Mat::data 포인터를 잡고 하위 행렬의 위치를 ​​계산할 수 있습니다. ptr(int i0, int i1, int i2) 방법이 있지만 다차원 배열의 경우 step[]이 이상하기 때문에 그다지 운이 없었습니다.

// 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; 

출력

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] 
+0

+1 - 난 내 [매트릭스]에서 웃었다 (http://en.wikipedia.org/wiki/The_Matrix) 기준 :) – rayryeng

+0

@rayryeng 방금 내 머리에 터졌다. :). 다시 : 답변, 또한 MATLAB의':'와 비슷한 'Range' 함수가 있지만 그것을 사용한 적이 없습니다. 또한 일반적으로'cv : Rect'를 통해 ROI를 사용할 수는 있지만 2 차원이라고 생각합니다. 어쨌든, 나는 다차원의'Mat's을 자주 사용하지 않지만'MatND''t typedef에 대해서 알고 있습니다. – chappjc

+0

답변 해 주셔서 감사합니다. 2D 하위 행렬의 포인터를 얻는 방법은 다음과 같습니다 :). mexopencv 내부에서 일어나는 일은 여전히 ​​이상 할지라도 : cv :: MatND와 prhs [0]). toMatND()를 사용하는 것은 더 이상 사용되지 않습니다. Matlab에서 mexopencv로 큰 3D 행렬을 전달할 때 충돌이 발생하기 때문에 toMatND prhs [0]). toMat() (cv :: Mat는 세 번째 차원을 "채널"로 저장하고 최대 채널 번호는 4입니다. – mcExchange